diff --git a/build/make_standard_proto.py b/build/make_proto.py similarity index 59% rename from build/make_standard_proto.py rename to build/make_proto.py index be18ba8d5..9b8984849 100644 --- a/build/make_standard_proto.py +++ b/build/make_proto.py @@ -17,7 +17,7 @@ import sys import shutil -def replace_lite_option(target_path, protofilepath): +def remove_lite_option(target_path, protofilepath): target_file_path = os.path.basename(protofilepath) target_file_path = target_path + '/' + target_file_path.replace(".proto", "_standard.proto") shutil.copyfile(protofilepath, target_file_path) @@ -33,13 +33,33 @@ def replace_lite_option(target_path, protofilepath): content.close() +def add_lite_option(target_path, protofilepath): + target_file_path = os.path.basename(protofilepath) + target_file_path = target_path + '/' + target_file_path.replace(".proto", "_lite.proto") + shutil.copyfile(protofilepath, target_file_path) + # replease lite flag, import file name, add package name + with open(target_file_path, 'r+') as content: + newcontent = content.read() + if newcontent.find('option optimize_for = LITE_RUNTIME') == -1: + newcontent = newcontent.replace('syntax = "proto3";', + 'syntax = "proto3";\n\noption optimize_for = LITE_RUNTIME;') + newcontent = newcontent.replace('syntax = "proto3";', 'syntax = "proto3";\n\npackage LITE;') + newcontent = newcontent.replace('.proto";', '_lite.proto";') + content.seek(0, 0) + content.write(newcontent) + content.truncate() + content.close() + + def main(): target_dir = sys.argv[1] i = 2 while i < len(sys.argv): proto_file_path = sys.argv[i] - replace_lite_option(target_dir, proto_file_path) + remove_lite_option(target_dir, proto_file_path) + add_lite_option(target_dir, proto_file_path) i += 1 + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/build/protoc.sh b/build/protoc.sh index 09375b242..b66f35f53 100755 --- a/build/protoc.sh +++ b/build/protoc.sh @@ -24,7 +24,8 @@ PROTOC=$PROJECT_TOP/$2/thirdparty/protobuf/protoc OPT_PLUGIN_PATH=$PROJECT_TOP/$2/developtools/hiprofiler/protoencoder_plugin OPT_PLUGIN=--plugin=protoc-gen-opt=$PROJECT_TOP/$2/developtools/hiprofiler/protoencoder_plugin OPT_OUT=--opt_out -PYTHON_SHELL=$THIS_DIR/make_standard_proto.py # shell path + +PYTHON_SHELL=$THIS_DIR/make_proto.py # shell path TMP=$2 PROTO_OUT_DIR="$PROJECT_TOP/${TMP%/*}/$3" # path of the new proto file @@ -59,6 +60,14 @@ do done PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD" # add new argument list to old argument list +PARAMS_LITE_REPLACE=${PARAMS_SOURCES//.proto/_lite.proto} # make the new proto file name. like "_lite.proto" +PARAMS_LITE=" --proto_path $PROTO_OUT_DIR " # add proto_path,$PROTO_OUT_DIR is the pb file path +for VAR in ${PARAMS_LITE_REPLACE[@]} +do + PARAMS_LITE="$PARAMS_LITE$PROTO_OUT_DIR/${VAR##*/} " # add .proto file name to args +done +PARAMS_ALL="$PARAMS_SRC $PARAMS_STANDARD $PARAMS_LITE" # add new argument list to old argument list + # avoid conflict, param4=--plugin* means ipc plugin, generate encode file if opt plugin exist if [[ "$4" != --plugin* ]]; then if [ -f "$OPT_PLUGIN_PATH" ]; then diff --git a/device/cmds/src/main.cpp b/device/cmds/src/main.cpp index 03dbb7d50..243d838ac 100644 --- a/device/cmds/src/main.cpp +++ b/device/cmds/src/main.cpp @@ -148,10 +148,6 @@ std::unique_ptr MakeCreateRequest(const std::string& confi printf("set %s plugin config failed\n", pluginConfig->name().c_str()); return nullptr; } - if (sessionConfig->split_file() && pluginConfig->name() != "ftrace-plugin") { - printf("only ftrace-plugin support split_file, please check session_config.\n"); - return nullptr; - } } content.clear(); diff --git a/device/cmds/test/unittest/hiprofiler_cmd_test.cpp b/device/cmds/test/unittest/hiprofiler_cmd_test.cpp index 3f086c2d7..75b709ac3 100644 --- a/device/cmds/test/unittest/hiprofiler_cmd_test.cpp +++ b/device/cmds/test/unittest/hiprofiler_cmd_test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -327,6 +328,141 @@ public: return cmdStr; } + std::string CreateSplitHtraceCommand(const std::string &outFile, int time) const + { + std::string cmdStr = + "hiprofiler_cmd -s -k \\\n" + "-c - \\\n"; + cmdStr += "-o " + outFile + " \\\n"; + cmdStr += "-t " + std::to_string(time) + " \\\n" + "<(buf.st_size); + } + void KillProcess(const std::string processName) { int pid = -1; @@ -616,3 +752,119 @@ HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0190, Function | MediumTest | Lev StopProcessStub(hiprofilerdPid_); } } + +/** + * @tc.name: hiprofiler_cmd + * @tc.desc: Test hiprofiler_cmd with split Htrace file. + * @tc.type: FUNC + */ +HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0190, Function | MediumTest | Level1) +{ + std::string outFileName = "split_htrace"; + std::string outFile = DEFAULT_PATH + outFileName + ".htrace"; + std::string content = ""; + int time = 10; + std::string cmd = CreateSplitHtraceCommand(outFile, time); + EXPECT_TRUE(RunCommand(cmd, content)); + + EXPECT_NE(access(outFile.c_str(), F_OK), 0); + + cmd = "ls " + DEFAULT_PATH + outFileName + "*_1.htrace"; + EXPECT_TRUE(RunCommand(cmd, content)); + EXPECT_STRNE(content.c_str(), ""); + + cmd = "rm " + DEFAULT_PATH + outFileName + "*.htrace"; + system(cmd.c_str()); +} + +/** + * @tc.name: hiprofiler_cmd + * @tc.desc: Test hiprofiler_cmd with split arkts file. + * @tc.type: FUNC + */ +HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0200, Function | MediumTest | Level1) +{ + std::string outFileName = "split_arkts"; + std::string outFile = DEFAULT_PATH + outFileName + ".htrace"; + std::string arktsSplitFile = "/data/local/tmp/split_arkts_data.htrace"; + std::string content = ""; + int time = 10; + std::string cmd = CreateSplitArktsCommand(outFile, arktsSplitFile, time); + EXPECT_TRUE(RunCommand(cmd, content)); + + EXPECT_NE(access(outFile.c_str(), F_OK), 0); + + cmd = "ls " + DEFAULT_PATH + outFileName + "*_1.htrace"; + EXPECT_TRUE(RunCommand(cmd, content)); + EXPECT_STRNE(content.c_str(), ""); + + EXPECT_EQ(access(arktsSplitFile.c_str(), F_OK), 0); + cmd = "rm " + DEFAULT_PATH + outFileName + "*.htrace"; + system(cmd.c_str()); +} +/** + * @tc.name: hiprofiler_cmd + * @tc.desc: Test hiprofiler_cmd with split hiperf file. + * @tc.type: FUNC + */ +HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0210, Function | MediumTest | Level1) +{ + std::string outFileName = "split_hiperf"; + std::string outFile = DEFAULT_PATH + outFileName + ".htrace"; + std::string perfFile = "/data/local/tmp/perf.data"; + std::string perfSplitFile = "/data/local/tmp/split_perf_data.htrace"; + std::string content = ""; + int time = 10; + std::string cmd = CreateSplitHiperfCommand(outFile, perfFile, perfSplitFile, time); + EXPECT_TRUE(RunCommand(cmd, content)); + + EXPECT_NE(access(outFile.c_str(), F_OK), 0); + + cmd = "ls " + DEFAULT_PATH + outFileName + "*_1.htrace"; + EXPECT_TRUE(RunCommand(cmd, content)); + EXPECT_STRNE(content.c_str(), ""); + + EXPECT_EQ(access(perfSplitFile.c_str(), F_OK), 0); + if (access(perfFile.c_str(), F_OK) == 0) { + const int headerSize = 1024 + 1024; // htrace header + hiperf header + auto perfFileSize = GetFileSize(perfFile.c_str()); + auto perfSplitFileSize = GetFileSize(perfSplitFile.c_str()); + EXPECT_GT(perfSplitFileSize, perfFileSize + headerSize); + } + + cmd = "rm " + DEFAULT_PATH + outFileName + "*.htrace " + perfFile + " " + perfSplitFile; + system(cmd.c_str()); +} +/** + * @tc.name: hiprofiler_cmd + * @tc.desc: Test hiprofiler_cmd with split hiebpf file. + * @tc.type: FUNC + */ +HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0220, Function | MediumTest | Level1) +{ + std::string outFileName = "split_hiebpf"; + std::string outFile = DEFAULT_PATH + outFileName + ".htrace"; + std::string ebpfFile = "/data/local/tmp/ebpf.data"; + std::string ebpfSplitFile = "/data/local/tmp/split_ebpf_data.htrace"; + std::string content = ""; + int time = 10; + std::string cmd = CreateSplitHiebpfCommand(outFile, ebpfFile, ebpfSplitFile, time); + EXPECT_TRUE(RunCommand(cmd, content)); + + EXPECT_NE(access(outFile.c_str(), F_OK), 0); + + cmd = "ls " + DEFAULT_PATH + outFileName + "*_1.htrace"; + EXPECT_TRUE(RunCommand(cmd, content)); + EXPECT_STRNE(content.c_str(), ""); + + EXPECT_EQ(access(ebpfSplitFile.c_str(), F_OK), 0); + if (access(ebpfFile.c_str(), F_OK) == 0) { + const int headerSize = 1024 + 1024; // htrace header + hiebpf header + auto ebpfFileSize = GetFileSize(ebpfFile.c_str()); + auto ebpfSplitFileSize = GetFileSize(ebpfSplitFile.c_str()); + EXPECT_GT(ebpfSplitFileSize, ebpfFileSize + headerSize); + } + + cmd = "rm " + DEFAULT_PATH + outFileName + "*.htrace " + ebpfFile + " " + ebpfSplitFile; + system(cmd.c_str()); +} diff --git a/device/plugins/api/include/writer.h b/device/plugins/api/include/writer.h index 559ce42e0..20b7ee5ad 100644 --- a/device/plugins/api/include/writer.h +++ b/device/plugins/api/include/writer.h @@ -25,10 +25,6 @@ public: virtual long Write(const void* data, size_t size) = 0; virtual bool Flush() = 0; virtual void SetClockId(clockid_t clockId) {} - virtual bool Clear() - { - return true; - } virtual void UseMemory(int32_t size) {} diff --git a/device/plugins/api/src/buffer_writer.cpp b/device/plugins/api/src/buffer_writer.cpp index f6e174e5b..9ffdb8a78 100644 --- a/device/plugins/api/src/buffer_writer.cpp +++ b/device/plugins/api/src/buffer_writer.cpp @@ -129,15 +129,6 @@ bool BufferWriter::Flush() return true; } -bool BufferWriter::Clear() -{ - if (shareMemoryBlock_ == nullptr) { - return false; - } - shareMemoryBlock_->ClearShareMemoryBlock(); - return true; -} - void BufferWriter::UseMemory(int32_t size) { if (shareMemoryBlock_ == nullptr) { diff --git a/device/plugins/api/src/buffer_writer.h b/device/plugins/api/src/buffer_writer.h index cc27f8176..4c7d09a93 100644 --- a/device/plugins/api/src/buffer_writer.h +++ b/device/plugins/api/src/buffer_writer.h @@ -36,7 +36,6 @@ public: ~BufferWriter(); long Write(const void* data, size_t size) override; bool Flush() override; - bool Clear() override; void UseMemory(int32_t size) override; RandomWriteCtx* StartReport() override; void FinishReport(int32_t size) override; diff --git a/device/plugins/api/src/plugin_module.cpp b/device/plugins/api/src/plugin_module.cpp index 5871b5ada..5a7ed4001 100644 --- a/device/plugins/api/src/plugin_module.cpp +++ b/device/plugins/api/src/plugin_module.cpp @@ -250,13 +250,6 @@ bool PluginModule::ReportBasicData() CHECK_NOTNULL(handle_, false, "%s:plugin not load", __func__); if (structPtr_ != nullptr && structPtr_->callbacks != nullptr) { if (structPtr_->callbacks->onReportBasicDataCallback != nullptr) { - auto write = GetWriter(); - CHECK_NOTNULL(write, false, "%s:get write falied!", __func__); - if (isProtobufSerialize_) { - // proto_encoder mode cannot clean up shared memory because data is written directly to shared memory. - // protobuf mode requires clear shared memory in order to prioritize reporting basic data. - write->Clear(); - } return (structPtr_->callbacks->onReportBasicDataCallback() == 0); } } diff --git a/device/plugins/api/test/unittest/buffer_write_test.cpp b/device/plugins/api/test/unittest/buffer_write_test.cpp index 309f9cd5e..e51f70863 100644 --- a/device/plugins/api/test/unittest/buffer_write_test.cpp +++ b/device/plugins/api/test/unittest/buffer_write_test.cpp @@ -213,6 +213,5 @@ HWTEST_F(BufferWriteTest, WriteMessageTest, TestSize.Level1) EXPECT_TRUE(write->WriteMessage(pluginData, "111")); EXPECT_TRUE(CheckMessage(data, size)); - EXPECT_TRUE(write->Clear()); } } // namespace diff --git a/device/plugins/arkts_plugin/BUILD.gn b/device/plugins/arkts_plugin/BUILD.gn index 3e14fdced..3f4af2b97 100644 --- a/device/plugins/arkts_plugin/BUILD.gn +++ b/device/plugins/arkts_plugin/BUILD.gn @@ -16,6 +16,8 @@ import("../../base/config.gni") ohos_source_set("arkts_source") { sources = [ + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_helper.cpp", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_writer.cpp", "src/arkts_module.cpp", "src/arkts_plugin.cpp", ] @@ -24,17 +26,20 @@ ohos_source_set("arkts_source") { "../../base/include/", "${OHOS_PROFILER_DIR}/interfaces/kits", "${OHOS_PROFILER_DIR}/device/base/include", + "${OHOS_PROFILER_DIR}/device/plugins/api/include", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src", "//third_party/bounds_checking_function/include", ] deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", "${OHOS_PROFILER_DIR}/proto_encoder:proto_encoder_source", + "${OHOS_PROFILER_DIR}/protos/services:common_types_lite_proto", "${OHOS_PROFILER_DIR}/protos/types/plugins/arkts_plugin:arkts_plugin_data_cpp", "../../base:hiprofiler_base", "//third_party/bounds_checking_function:libsec_static", + "//third_party/openssl:libcrypto_shared", ] - defines = [] + defines = [ "LITE_PROTO" ] if (current_toolchain != host_toolchain) { defines += [ "HAVE_HILOG" ] external_deps = [ "hilog:libhilog" ] diff --git a/device/plugins/arkts_plugin/include/arkts_plugin.h b/device/plugins/arkts_plugin/include/arkts_plugin.h index 96b7530b1..7c21f5efa 100644 --- a/device/plugins/arkts_plugin/include/arkts_plugin.h +++ b/device/plugins/arkts_plugin/include/arkts_plugin.h @@ -19,6 +19,7 @@ #include "arkts_plugin_config.pb.h" #include "plugin_module_api.h" #include "schedule_task_manager.h" +#include "trace_file_writer.h" struct WebSocketFrame { uint8_t fin; @@ -72,6 +73,7 @@ private: uint8_t commandResult_{0}; ScheduleTaskManager scheduleTaskManager_; int32_t snapshotScheduleTaskFd_; + std::shared_ptr splitTraceWriter_ {nullptr}; }; #endif // ARKTS_PLUGIN_H \ No newline at end of file diff --git a/device/plugins/arkts_plugin/src/arkts_plugin.cpp b/device/plugins/arkts_plugin/src/arkts_plugin.cpp index c0fb49ce7..dabf858c5 100644 --- a/device/plugins/arkts_plugin/src/arkts_plugin.cpp +++ b/device/plugins/arkts_plugin/src/arkts_plugin.cpp @@ -79,6 +79,16 @@ int32_t ArkTSPlugin::Start(const uint8_t* configData, uint32_t configSize) HILOG_ERROR(LOG_CORE, "%s:parseFromArray failed!", __func__); return -1; } + + if (!protoConfig_.split_outfile_name().empty()) { + splitTraceWriter_ = std::make_shared(protoConfig_.split_outfile_name()); + splitTraceWriter_->WriteStandalonePluginData( + std::string(g_pluginModule.name) + "_config", + std::string(reinterpret_cast(configData), + configSize)); + splitTraceWriter_->SetTimeSource(); + } + pid_ = protoConfig_.pid(); if (pid_ <= 0) { HILOG_ERROR(LOG_CORE, "%s: pid is less than or equal to 0", __func__); @@ -199,6 +209,14 @@ int32_t ArkTSPlugin::Stop() } } Close(); + + if (!protoConfig_.split_outfile_name().empty()) { // write split file. + CHECK_NOTNULL(splitTraceWriter_, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__); + splitTraceWriter_->SetDurationTime(); + splitTraceWriter_->Finish(); + splitTraceWriter_.reset(); + splitTraceWriter_ = nullptr; + } return 0; } @@ -226,6 +244,9 @@ void ArkTSPlugin::FlushData(const std::string& command) endFlag = RESPONSE_FLAG_HEAD + match[1].str() + RESPONSE_FLAG_TAIL; } } + if (!protoConfig_.split_outfile_name().empty()) { + CHECK_NOTNULL(splitTraceWriter_, NO_RETVAL, "%s: writer is nullptr, WriteStandaloneFile failed", __func__); + } while (true) { std::string recv = Decode(); @@ -237,15 +258,25 @@ void ArkTSPlugin::FlushData(const std::string& command) data.set_result(recv.c_str(), recv.size()); buffer_.resize(data.ByteSizeLong()); data.SerializeToArray(buffer_.data(), buffer_.size()); - resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size()); - resultWriter_->flush(resultWriter_); - if (endFlag.empty()) { - return; + + if (protoConfig_.split_outfile_name().empty()) { + resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size()); + resultWriter_->flush(resultWriter_); + } else { // write split file. + splitTraceWriter_->WriteStandalonePluginData( + std::string(g_pluginModule.name), + std::string(buffer_.data(), buffer_.size()), + std::string(g_pluginModule.version)); } - if (recv == endFlag) { - return; + + if (endFlag.empty() || recv == endFlag) { + break; } } + + if (!protoConfig_.split_outfile_name().empty()) { + splitTraceWriter_->Flush(); + } } bool ArkTSPlugin::ClientConnectUnixWebSocket(const std::string& sockName, uint32_t timeoutLimit) diff --git a/device/plugins/arkts_plugin/test/BUILD.gn b/device/plugins/arkts_plugin/test/BUILD.gn index de19cbfa7..88e389fc9 100644 --- a/device/plugins/arkts_plugin/test/BUILD.gn +++ b/device/plugins/arkts_plugin/test/BUILD.gn @@ -27,13 +27,17 @@ ohos_unittest("arktsplugin_ut") { sources = [ "unittest/arkts_plugin_unittest.cpp" ] deps = [ "${OHOS_PROFILER_DIR}/device/plugins/arkts_plugin:arkts_source", + "${OHOS_PROFILER_DIR}/protos/services:common_types_lite_proto", "${OHOS_PROFILER_DIR}/protos/types/plugins/arkts_plugin:arkts_plugin_data_cpp", "//third_party/bounds_checking_function:libsec_static", + "//third_party/openssl:libcrypto_shared", ] include_dirs = [ "../include", "${OHOS_PROFILER_DIR}/interfaces/kits", "${OHOS_PROFILER_DIR}/device/base/include", + "${OHOS_PROFILER_DIR}/device/plugins/api/include", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src", "//third_party/googletest/googletest/include/gtest", "//third_party/bounds_checking_function/include", ] diff --git a/device/plugins/hiebpf_plugin/BUILD.gn b/device/plugins/hiebpf_plugin/BUILD.gn index 9ba5e2ba5..01c864769 100644 --- a/device/plugins/hiebpf_plugin/BUILD.gn +++ b/device/plugins/hiebpf_plugin/BUILD.gn @@ -15,22 +15,32 @@ import("//build/ohos.gni") import("../../base/config.gni") ohos_source_set("hiebpfplugin_source") { - sources = [ "src/hiebpf_module.cpp" ] + sources = [ + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_helper.cpp", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_writer.cpp", + "src/hiebpf_module.cpp", + ] include_dirs = [ "include", "${OHOS_PROFILER_DIR}/interfaces/kits", "${OHOS_PROFILER_DIR}/device/base/include", + "${OHOS_PROFILER_DIR}/device/plugins/api/include", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src", "//third_party/bounds_checking_function/include", ] deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + "${OHOS_PROFILER_DIR}/protos/services:common_types_lite_proto", "${OHOS_PROFILER_DIR}/protos/types/plugins/hiebpf_data:hiebpf_data_cpp", "../../base:hiprofiler_base", "//third_party/bounds_checking_function:libsec_static", + "//third_party/openssl:libcrypto_shared", ] if (current_toolchain != host_toolchain) { - defines = [ "HAVE_HILOG" ] + defines = [ + "HAVE_HILOG", + "LITE_PROTO", + ] external_deps = [ "hilog:libhilog" ] } subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" diff --git a/device/plugins/hiebpf_plugin/src/hiebpf_module.cpp b/device/plugins/hiebpf_plugin/src/hiebpf_module.cpp index a057db9a7..22f45da59 100644 --- a/device/plugins/hiebpf_plugin/src/hiebpf_module.cpp +++ b/device/plugins/hiebpf_plugin/src/hiebpf_module.cpp @@ -23,6 +23,7 @@ #include "hiebpf_plugin_config.pb.h" #include "logging.h" #include "plugin_module_api.h" +#include "trace_file_writer.h" namespace { constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024; @@ -30,6 +31,8 @@ std::mutex g_taskMutex; constexpr int32_t RET_OK = 0; constexpr int32_t RET_ERR = -1; bool g_releaseResources = false; +HiebpfConfig g_config; +std::shared_ptr g_splitTraceWriter {nullptr}; void RunCmd(std::string& cmd) { @@ -57,16 +60,25 @@ static int32_t HiebpfSessionStart(const uint8_t* configData, uint32_t configSize HILOG_ERROR(LOG_CORE, "Parameter error"); return RET_ERR; } - HiebpfConfig config; - CHECK_TRUE(config.ParseFromArray(configData, configSize) > 0, RET_ERR, "Parameter parsing failed"); + + CHECK_TRUE(g_config.ParseFromArray(configData, configSize) > 0, RET_ERR, "Parameter parsing failed"); + + if (!g_config.split_outfile_name().empty()) { + g_splitTraceWriter = std::make_shared(g_config.split_outfile_name()); + g_splitTraceWriter->WriteStandalonePluginData( + std::string(g_pluginModule.name) + "_config", + std::string(reinterpret_cast(configData), + configSize)); + g_splitTraceWriter->SetTimeSource(); + } size_t defaultSize = sizeof(g_pluginModule.outFileName); - CHECK_TRUE(sizeof(config.outfile_name().c_str()) <= defaultSize - 1, RET_ERR, + CHECK_TRUE(sizeof(g_config.outfile_name().c_str()) <= defaultSize - 1, RET_ERR, "The out file path more than %zu bytes", defaultSize); - int32_t ret = strncpy_s(g_pluginModule.outFileName, defaultSize, config.outfile_name().c_str(), defaultSize - 1); - CHECK_TRUE(ret == EOK, RET_ERR, "strncpy_s error! outfile is %s", config.outfile_name().c_str()); - std::string cmd = config.cmd_line(); - cmd += " --start true --output_file " + config.outfile_name(); + int32_t ret = strncpy_s(g_pluginModule.outFileName, defaultSize, g_config.outfile_name().c_str(), defaultSize - 1); + CHECK_TRUE(ret == EOK, RET_ERR, "strncpy_s error! outfile is %s", g_config.outfile_name().c_str()); + std::string cmd = g_config.cmd_line(); + cmd += " --start true --output_file " + g_config.outfile_name(); RunCmd(cmd); HILOG_DEBUG(LOG_CORE, "leave"); return RET_OK; @@ -77,8 +89,23 @@ static int32_t HiebpfSessionStop() std::lock_guard guard(g_taskMutex); CHECK_TRUE(!g_releaseResources, 0, "%s: hiebpf released resources, return", __func__); HILOG_DEBUG(LOG_CORE, "enter"); + + if (!g_config.split_outfile_name().empty()) { + CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, SetDurationTime failed", __func__); + g_splitTraceWriter->SetDurationTime(); + } + std::string stop = "hiebpf --stop true"; RunCmd(stop); + + if (!g_config.split_outfile_name().empty()) { // write split file. + CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__); + g_splitTraceWriter->WriteStandalonePluginFile(std::string(g_pluginModule.outFileName), + std::string(g_pluginModule.name), std::string(g_pluginModule.version), DataType::STANDALONE_DATA); + g_splitTraceWriter->Finish(); + g_splitTraceWriter.reset(); + g_splitTraceWriter = nullptr; + } HILOG_DEBUG(LOG_CORE, "leave"); return RET_OK; } diff --git a/device/plugins/hiperf_plugin/BUILD.gn b/device/plugins/hiperf_plugin/BUILD.gn index 20da9ed1e..07d615fbe 100755 --- a/device/plugins/hiperf_plugin/BUILD.gn +++ b/device/plugins/hiperf_plugin/BUILD.gn @@ -26,19 +26,28 @@ config("hiperfplugin_config") { ohos_source_set("hiperfplugin_source") { output_name = "hiperfplugin" - sources = [ "src/hiperf_module.cpp" ] + sources = [ + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_helper.cpp", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_writer.cpp", + "src/hiperf_module.cpp", + ] public_configs = [ ":hiperfplugin_config", "${OHOS_PROFILER_DIR}/device/base:hiprofiler_test_config", ] public_deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + "${OHOS_PROFILER_DIR}/protos/services:common_types_lite_proto", "${OHOS_PROFILER_DIR}/protos/types/plugins/hiperf_data:hiperf_data_cpp", "../../base:hiprofiler_base", "//third_party/bounds_checking_function:libsec_static", + "//third_party/openssl:libcrypto_shared", ] if (current_toolchain != host_toolchain) { - defines = [ "HAVE_HILOG" ] + defines = [ + "HAVE_HILOG", + "LITE_PROTO", + ] external_deps = [ "hilog:libhilog" ] } subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" diff --git a/device/plugins/hiperf_plugin/src/hiperf_module.cpp b/device/plugins/hiperf_plugin/src/hiperf_module.cpp index 8da96c776..89d61721f 100644 --- a/device/plugins/hiperf_plugin/src/hiperf_module.cpp +++ b/device/plugins/hiperf_plugin/src/hiperf_module.cpp @@ -26,6 +26,7 @@ #include "logging.h" #include "securec.h" #include "common.h" +#include "trace_file_writer.h" namespace { constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024; @@ -42,6 +43,8 @@ const std::string HIPERF_BIN_PATH = "/system/bin/hiperf"; std::mutex g_taskMutex; bool g_isRoot = false; std::string g_logLevel = ""; +HiperfPluginConfig g_config; +std::shared_ptr g_splitTraceWriter {nullptr}; bool ParseConfigToCmd(const HiperfPluginConfig& config, std::vector& cmds) { @@ -112,12 +115,20 @@ bool RunCommand(const std::string& cmd) int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize) { std::lock_guard guard(g_taskMutex); - HiperfPluginConfig config; - bool res = config.ParseFromArray(configData, configSize); + bool res = g_config.ParseFromArray(configData, configSize); CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config from array FAILED! configSize: %u", configSize); + if (!g_config.split_outfile_name().empty()) { + g_splitTraceWriter = std::make_shared(g_config.split_outfile_name()); + g_splitTraceWriter->WriteStandalonePluginData( + std::string(g_pluginModule.name) + "_config", + std::string(reinterpret_cast(configData), + configSize)); + g_splitTraceWriter->SetTimeSource(); + } + std::vector cmds; - res = ParseConfigToCmd(config, cmds); + res = ParseConfigToCmd(g_config, cmds); CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config FAILED!"); for (const auto &cmd : cmds) { @@ -131,6 +142,11 @@ int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSiz int HiperfPluginSessionStop(void) { std::lock_guard guard(g_taskMutex); + if (!g_config.split_outfile_name().empty()) { + CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, SetDurationTime failed", __func__); + g_splitTraceWriter->SetDurationTime(); + } + std::string cmd; if (g_isRoot) { cmd = SU_ROOT; @@ -139,6 +155,15 @@ int HiperfPluginSessionStop(void) cmd += HIPERF_RECORD_STOP; RunCommand(cmd); usleep(250000); // 250000: wait for perf.data + + if (!g_config.split_outfile_name().empty()) { // write split file. + CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__); + g_splitTraceWriter->WriteStandalonePluginFile(std::string(g_pluginModule.outFileName), + std::string(g_pluginModule.name), std::string(g_pluginModule.version), DataType::HIPERF_DATA); + g_splitTraceWriter->Finish(); + g_splitTraceWriter.reset(); + g_splitTraceWriter = nullptr; + } return 0; } diff --git a/device/plugins/hiperf_plugin/test/fuzztest/hiperfstartplugin_fuzzer/BUILD.gn b/device/plugins/hiperf_plugin/test/fuzztest/hiperfstartplugin_fuzzer/BUILD.gn index cbb163d30..763e3968f 100755 --- a/device/plugins/hiperf_plugin/test/fuzztest/hiperfstartplugin_fuzzer/BUILD.gn +++ b/device/plugins/hiperf_plugin/test/fuzztest/hiperfstartplugin_fuzzer/BUILD.gn @@ -28,11 +28,15 @@ ohos_fuzztest("HiperfStartPluginFuzzTest") { ] sources = [ "${OHOS_PROFILER_DIR}/device/plugins/hiperf_plugin/src/hiperf_module.cpp", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_helper.cpp", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src/trace_file_writer.cpp", "hiperfstartplugin_fuzzer.cpp", ] deps = [ "${OHOS_PROFILER_DIR}/device/base:hiprofiler_base", + "${OHOS_PROFILER_DIR}/protos/services:common_types_lite_proto", "${OHOS_PROFILER_DIR}/protos/types/plugins/hiperf_data:hiperf_data_cpp", + "//third_party/openssl:libcrypto_shared", ] include_dirs = [ @@ -40,8 +44,10 @@ ohos_fuzztest("HiperfStartPluginFuzzTest") { "${OHOS_PROFILER_DIR}/device/plugins/api/include", "${OHOS_PROFILER_DIR}/interfaces/kits", "${OHOS_PROFILER_DIR}/device/base/include", + "${OHOS_PROFILER_DIR}/device/services/profiler_service/src", "//commonlibrary/c_utils/base/include", ] + defines = [ "LITE_PROTO" ] external_deps = [ "c_utils:utils" ] } diff --git a/device/plugins/native_hook/include/stack_writer.h b/device/plugins/native_hook/include/stack_writer.h index eb8c29efc..f69b4c962 100644 --- a/device/plugins/native_hook/include/stack_writer.h +++ b/device/plugins/native_hook/include/stack_writer.h @@ -37,7 +37,6 @@ public: long WriteTimeout(const void* data, size_t size); long WriteWithPayloadTimeout(const void* data, size_t size, const void* payload, size_t payloadSize); bool Flush() override; - bool Clear() override; private: void DoStats(long bytes); diff --git a/device/plugins/native_hook/src/stack_writer.cpp b/device/plugins/native_hook/src/stack_writer.cpp index 96f515df3..f68422129 100644 --- a/device/plugins/native_hook/src/stack_writer.cpp +++ b/device/plugins/native_hook/src/stack_writer.cpp @@ -94,12 +94,3 @@ bool StackWriter::Flush() bytesPending_ = 0; return true; } - -bool StackWriter::Clear() -{ - if (shareMemoryBlock_ == nullptr) { - return false; - } - shareMemoryBlock_->ClearShareMemoryBlock(); - return true; -} diff --git a/device/plugins/native_hook/test/unittest/stack_writer_test.cpp b/device/plugins/native_hook/test/unittest/stack_writer_test.cpp index af75efefb..23b6e3d46 100644 --- a/device/plugins/native_hook/test/unittest/stack_writer_test.cpp +++ b/device/plugins/native_hook/test/unittest/stack_writer_test.cpp @@ -214,6 +214,5 @@ HWTEST_F(StackWriterTest, WriterSyncTest, TestSize.Level1) EXPECT_FALSE(write->Write(nullptr, 0)); EXPECT_FALSE(write->WriteTimeout(nullptr, 0)); EXPECT_TRUE(write->WriteTimeout((const void*)buffer1, sizeof(buffer1))); - EXPECT_TRUE(write->Clear()); } } // namespace diff --git a/device/services/profiler_service/src/profiler_service.cpp b/device/services/profiler_service/src/profiler_service.cpp index 95682ce34..c7d4f1d3f 100644 --- a/device/services/profiler_service/src/profiler_service.cpp +++ b/device/services/profiler_service/src/profiler_service.cpp @@ -614,11 +614,10 @@ Status ProfilerService::DestroySession(ServerContext* context, auto pluginName = ctx->pluginNames[i]; std::tie(pluginId, pluginCtx) = pluginService_->GetPluginContext(pluginName); if (pluginCtx->isStandaloneFileData == true) { - std::string file = ctx->sessionConfig.result_file(); - if (ctx->sessionConfig.split_file()) { - file = ctx->traceFileWriter.get()->Path(); + if (!ctx->sessionConfig.split_file()) { + MergeStandaloneFile(ctx->sessionConfig.result_file(), pluginName, pluginCtx->outFileName, + pluginCtx->pluginVersion); } - MergeStandaloneFile(file, pluginName, pluginCtx->outFileName, pluginCtx->pluginVersion); } } } diff --git a/device/services/profiler_service/src/trace_file_writer.cpp b/device/services/profiler_service/src/trace_file_writer.cpp index 61c9ff003..6be66ecb0 100644 --- a/device/services/profiler_service/src/trace_file_writer.cpp +++ b/device/services/profiler_service/src/trace_file_writer.cpp @@ -21,7 +21,11 @@ #include #include "common.h" +#ifdef LITE_PROTO +#include "common_types_lite.pb.h" +#else #include "common_types.pb.h" +#endif #include "logging.h" using CharPtr = std::unique_ptr::pointer; @@ -84,7 +88,36 @@ bool TraceFileWriter::SetPluginConfig(const void* data, size_t size) return true; } -void TraceFileWriter::WriteStandalonePluginData(std::string pluginName, std::string data, std::string pluginVersion) +#ifdef LITE_PROTO +void TraceFileWriter::WriteStandalonePluginData( + const std::string &pluginName, const std::string &data, + const std::string &pluginVersion) +{ + LITE::ProfilerPluginData pluginData; + pluginData.set_name(pluginName); + pluginData.set_data(data); + if (!pluginVersion.empty()) { + pluginData.set_version(pluginVersion); + pluginData.set_status(0); + + struct timespec ts = { 0, 0 }; + clock_gettime(CLOCK_REALTIME, &ts); + pluginData.set_tv_sec(ts.tv_sec); + pluginData.set_tv_nsec(ts.tv_nsec); + pluginData.set_clock_id(LITE::ProfilerPluginData::CLOCKID_REALTIME); + } + + std::vector msgData(pluginData.ByteSizeLong()); + if (pluginData.SerializeToArray(msgData.data(), msgData.size()) <= 0) { + HILOG_WARN(LOG_CORE, "%s StandalonePluginData SerializeToArray failed!", pluginName.c_str()); + } + + Write(msgData.data(), msgData.size()); +} +#else +void TraceFileWriter::WriteStandalonePluginData( + const std::string &pluginName, const std::string &data, + const std::string &pluginVersion) { ProfilerPluginData pluginData; pluginData.set_name(pluginName); @@ -107,7 +140,7 @@ void TraceFileWriter::WriteStandalonePluginData(std::string pluginName, std::str Write(msgData.data(), msgData.size()); } - +#endif void TraceFileWriter::SetTimeStamp() { header_.data_.boottime = headerDataTime_.boottime; @@ -232,6 +265,62 @@ long TraceFileWriter::Write(const void* data, size_t size) return nbytes; } +long TraceFileWriter::WriteStandalonePluginFile(const std::string &file, + const std::string &name, + const std::string &version, + DataType type) +{ + CHECK_TRUE(stream_.is_open(), 0, "binary file %s not open or open failed!", path_.c_str()); + + std::ifstream fsFile {}; // read data from file + fsFile.open(file, std::ios_base::in | std::ios_base::binary); + if (!fsFile.good()) { + HILOG_ERROR(LOG_CORE, "open file(%s) failed: %d", file.c_str(), fsFile.rdstate()); + return 0; + } + + TraceFileHeader header {}; + fsFile.seekg(0, std::ios_base::end); + uint64_t fileSize = static_cast(fsFile.tellg()); + header.data_.length += fileSize; + size_t size = name.size(); + if (size > 0) { + if (size > PLUGIN_MODULE_NAME_MAX) { + HILOG_ERROR(LOG_CORE, "standalonePluginName(%s) size(%zu) is greater than %d!", + name.c_str(), size, PLUGIN_MODULE_NAME_MAX); + } else if (strncpy_s(header.data_.standalonePluginName, PLUGIN_MODULE_NAME_MAX, name.c_str(), size) != EOK) { + HILOG_ERROR(LOG_CORE, "strncpy_s standalonePluginName(%s) error!", name.c_str()); + } + } + size = version.size(); + if (size > 0) { + if (size > PLUGIN_MODULE_VERSION_MAX) { + HILOG_ERROR(LOG_CORE, "pluginVersion(%s) size(%zu) is greater than %d!", + version.c_str(), size, PLUGIN_MODULE_VERSION_MAX); + } else if (strncpy_s(header.data_.pluginVersion, PLUGIN_MODULE_VERSION_MAX, version.c_str(), size) != EOK) { + HILOG_ERROR(LOG_CORE, "strncpy_s pluginVersion(%s) error!", version.c_str()); + } + } + header.data_.dataType = type; + stream_.write(reinterpret_cast(&header), sizeof(header)); + + constexpr uint64_t readBufSize = 4 * 1024 * 1024; + std::vector readBuf(readBufSize); + uint64_t readSize = 0; + fsFile.seekg(0); + while ((readSize = std::min(readBufSize, fileSize)) > 0) { + fsFile.read(readBuf.data(), readSize); + stream_.write(readBuf.data(), readSize); + + fileSize -= readSize; + writeBytes_ += readSize; + ++writeCount_; + } + + fsFile.close(); + return fileSize; +} + bool TraceFileWriter::IsSplitFile(uint32_t size) { dataSize_ += sizeof(uint32_t) + size; diff --git a/device/services/profiler_service/src/trace_file_writer.h b/device/services/profiler_service/src/trace_file_writer.h index 14e9883d5..50d701175 100644 --- a/device/services/profiler_service/src/trace_file_writer.h +++ b/device/services/profiler_service/src/trace_file_writer.h @@ -43,7 +43,9 @@ public: bool SetPluginConfig(const void* data, size_t size); - void WriteStandalonePluginData(std::string pluginName, std::string data, std::string pluginVersion = ""); + void WriteStandalonePluginData(const std::string& pluginName, + const std::string& data, + const std::string& pluginVersion = ""); bool WriteHeader(); @@ -51,6 +53,10 @@ public: long Write(const void* data, size_t size) override; + long WriteStandalonePluginFile(const std::string& file, + const std::string& name, + const std::string& version, DataType type); + bool Flush() override; bool Finish(); diff --git a/device/services/shared_memory/include/share_memory_block.h b/device/services/shared_memory/include/share_memory_block.h index 00748d070..102f16c70 100644 --- a/device/services/shared_memory/include/share_memory_block.h +++ b/device/services/shared_memory/include/share_memory_block.h @@ -45,7 +45,6 @@ public: std::string GetName(); uint32_t GetSize(); EXPORT_API int GetfileDescriptor(); - EXPORT_API void ClearShareMemoryBlock(); bool Valid() const; diff --git a/device/services/shared_memory/src/share_memory_block.cpp b/device/services/shared_memory/src/share_memory_block.cpp index 12c02556e..116dab416 100644 --- a/device/services/shared_memory/src/share_memory_block.cpp +++ b/device/services/shared_memory/src/share_memory_block.cpp @@ -443,15 +443,6 @@ bool ShareMemoryBlock::PutWithPayloadSync(const int8_t* header, uint32_t headerS pthread_mutex_unlock(&header_->info.mutex_); return true; } -void ShareMemoryBlock::ClearShareMemoryBlock() -{ - // clear header infos - PthreadLocker locker(header_->info.mutex_); - header_->info.readOffset_ = 0; - header_->info.writeOffset_ = 0; - header_->info.bytesCount_ = 0; - header_->info.chunkCount_ = 0; -} void ShareMemoryBlock::UseMemory(int32_t size) { diff --git a/device/services/shared_memory/test/unittest/shared_memory_block_test.cpp b/device/services/shared_memory/test/unittest/shared_memory_block_test.cpp index 4bbc1620a..68b1854cd 100644 --- a/device/services/shared_memory/test/unittest/shared_memory_block_test.cpp +++ b/device/services/shared_memory/test/unittest/shared_memory_block_test.cpp @@ -367,7 +367,6 @@ HWTEST_F(SharedMemoryBlockTest, GetMemory, TestSize.Level1) { ShareMemoryBlock shareMemoryBlock("testname", PAGE_SIZE); ASSERT_TRUE(shareMemoryBlock.Valid()); - shareMemoryBlock.ClearShareMemoryBlock(); // There are only 12 bytes left in shared memory. const int expectedSize = 12; diff --git a/protos/services/BUILD.gn b/protos/services/BUILD.gn index b679bb586..f24b41ca8 100644 --- a/protos/services/BUILD.gn +++ b/protos/services/BUILD.gn @@ -32,6 +32,8 @@ all_type_proto = [ "./plugin_service_types.proto", ] +common_type_proto = [ "./common_types.proto" ] + all_type_codegen = [] foreach(proto, all_type_proto) { name = get_path_info(proto, "name") @@ -41,10 +43,20 @@ foreach(proto, all_type_proto) { ] } +lite_codegen = [] +foreach(proto, common_type_proto) { + name = get_path_info(proto, "name") + lite_codegen += [ + "$proto_out_dir/${name}_lite.pb.h", + "$proto_out_dir/${name}_lite.pb.cc", + ] +} + action("all_type_gen") { script = "${OHOS_PROFILER_DIR}/build/protoc.sh" sources = all_type_proto outputs = all_type_codegen + outputs += lite_codegen args = [ "$libc_dir_proto", "$root_output_dir_proto", @@ -242,3 +254,13 @@ ohos_source_set("proto_services_cpp") { subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" part_name = "${OHOS_PROFILER_PART_NAME}" } + +ohos_source_set("common_types_lite_proto") { + deps = [ ":all_type_gen" ] + public_deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite" ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":public_configs" ] + sources = lite_codegen + subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" + part_name = "${OHOS_PROFILER_PART_NAME}" +} diff --git a/protos/types/plugins/arkts_plugin/arkts_plugin_config.proto b/protos/types/plugins/arkts_plugin/arkts_plugin_config.proto index c1ceb7e90..b66e5ff2f 100644 --- a/protos/types/plugins/arkts_plugin/arkts_plugin_config.proto +++ b/protos/types/plugins/arkts_plugin/arkts_plugin_config.proto @@ -32,4 +32,5 @@ message ArkTSConfig { // When the CPU profiler mode is active, it signifies the data capturing interval, measured in microseconds, // with a default value of 1000 microseconds. uint32 cpu_profiler_interval = 7; + string split_outfile_name = 8; } \ No newline at end of file diff --git a/protos/types/plugins/hiebpf_data/hiebpf_plugin_config.proto b/protos/types/plugins/hiebpf_data/hiebpf_plugin_config.proto index ec64583db..7f9b31cbe 100755 --- a/protos/types/plugins/hiebpf_data/hiebpf_plugin_config.proto +++ b/protos/types/plugins/hiebpf_data/hiebpf_plugin_config.proto @@ -18,4 +18,5 @@ option optimize_for = LITE_RUNTIME; message HiebpfConfig { string cmd_line = 1; string outfile_name = 2; + string split_outfile_name = 3; } \ No newline at end of file diff --git a/protos/types/plugins/hiperf_data/hiperf_plugin_config.proto b/protos/types/plugins/hiperf_data/hiperf_plugin_config.proto index 0b8106725..2ae8dc7ec 100755 --- a/protos/types/plugins/hiperf_data/hiperf_plugin_config.proto +++ b/protos/types/plugins/hiperf_data/hiperf_plugin_config.proto @@ -25,4 +25,5 @@ message HiperfPluginConfig { DEBUG = 3; }; LogLevel log_level = 4; // set log level, default is NO_LOG + string split_outfile_name = 5; } \ No newline at end of file