feat: 支持大trace切割

Signed-off-by: jichuan <jichuan1@huawei.com>
This commit is contained in:
jichuan 2023-12-08 09:37:35 +08:00
parent feb7ad8118
commit 90e84f6a39
31 changed files with 553 additions and 82 deletions

View File

@ -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()

View File

@ -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

View File

@ -148,10 +148,6 @@ std::unique_ptr<CreateSessionRequest> 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();

View File

@ -18,6 +18,7 @@
#include <fcntl.h>
#include <hwext/gtest-ext.h>
#include <hwext/gtest-tag.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
@ -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"
"<<CONFIG\n"
"request_id: 1\n"
"session_config {\n"
" buffers {\n"
" pages: 16384\n"
" }\n"
" split_file: true\n"
"}\n"
"plugin_configs {\n"
" plugin_name: \"ftrace-plugin\"\n"
" sample_interval: 1000\n"
" config_data {\n"
" ftrace_events: \"sched/sched_switch\"\n"
" ftrace_events: \"sched/sched_wakeup\"\n"
" ftrace_events: \"sched/sched_wakeup_new\"\n"
" ftrace_events: \"sched/sched_waking\"\n"
" ftrace_events: \"sched/sched_process_exit\"\n"
" ftrace_events: \"sched/sched_process_free\"\n"
" buffer_size_kb: 51200\n"
" flush_interval_ms: 1000\n"
" flush_threshold_kb: 4096\n"
" parse_ksyms: true\n"
" clock: \"mono\"\n"
" trace_period_ms: 200\n"
" debug_on: false\n"
" }\n"
"}\n"
"CONFIG\n";
return cmdStr;
}
std::string CreateSplitArktsCommand(const std::string &outFile, const std::string &arktsSplitFile, int time) const
{
std::string cmdStr =
"hiprofiler_cmd -s -k \\\n"
"-c - \\\n";
cmdStr += "-o " + outFile + " \\\n";
cmdStr += "-t " + std::to_string(time) + " \\\n"
"<<CONFIG\n"
"request_id: 1\n"
"session_config {\n"
" buffers {\n"
" pages: 16384\n"
" }\n"
" split_file: true\n"
"}\n"
"plugin_configs {\n"
" plugin_name: \"arkts-plugin\"\n"
" config_data {\n"
" pid: 1\n"
" capture_numeric_value: true\n"
" track_allocations: false\n"
" enable_cpu_profiler: true\n"
" cpu_profiler_interval: 1000\n"
" split_outfile_name: \"" + arktsSplitFile + "\"\n"
" }\n"
"}\n"
"CONFIG\n";
return cmdStr;
}
std::string CreateSplitHiperfCommand(const std::string &outFile, const std::string &perfFile,
const std::string &perfSplitFile, int time) const
{
std::string cmdStr =
"hiprofiler_cmd -s -k \\\n"
"-c - \\\n";
cmdStr += "-o " + outFile + " \\\n";
cmdStr += "-t " + std::to_string(time) + " \\\n"
"<<CONFIG\n"
"request_id: 1\n"
"session_config {\n"
" buffers {\n"
" pages: 16384\n"
" }\n"
" split_file: true\n"
"}\n"
"plugin_configs {\n"
" plugin_name: \"hiperf-plugin\"\n"
" config_data {\n"
" is_root: false\n"
" outfile_name: \"" + perfFile + "\"\n"
" record_args: \"-f 1000 -a --cpu-limit 100 -e hw-cpu-cycles,sched:sched_waking --call-stack dwarf --clockid monotonic --offcpu -m 256\"\n"
" split_outfile_name: \"" + perfSplitFile + "\"\n"
" }\n"
"}\n"
"CONFIG\n";
return cmdStr;
}
std::string CreateSplitHiebpfCommand(const std::string &outFile, const std::string &ebpfFile,
const std::string &ebpfSplitFile, int time) const
{
std::string cmdStr =
"hiprofiler_cmd -s -k \\\n"
"-c - \\\n";
cmdStr += "-o " + outFile + " \\\n";
cmdStr += "-t " + std::to_string(time) + " \\\n"
"<<CONFIG\n"
"request_id: 1\n"
"session_config {\n"
" buffers {\n"
" pages: 16384\n"
" }\n"
" split_file: true\n"
"}\n"
"plugin_configs {\n"
" plugin_name: \"hiebpf-plugin\"\n"
" config_data {\n"
" cmd_line: \"hiebpf --events fs,ptrace,bio --duration 200 --max_stack_depth 10\"\n"
" outfile_name: \"" + ebpfFile + "\"\n"
" split_outfile_name: \"" + ebpfSplitFile + "\"\n"
" }\n"
"}\n"
"CONFIG\n";
return cmdStr;
}
unsigned long GetFileSize(const char* filename)
{
struct stat buf;
if (stat(filename, &buf) < 0) {
return 0;
}
return static_cast<unsigned long>(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());
}

View File

@ -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) {}

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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" ]

View File

@ -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<TraceFileWriter> splitTraceWriter_ {nullptr};
};
#endif // ARKTS_PLUGIN_H

View File

@ -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<TraceFileWriter>(protoConfig_.split_outfile_name());
splitTraceWriter_->WriteStandalonePluginData(
std::string(g_pluginModule.name) + "_config",
std::string(reinterpret_cast<const char *>(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());
if (protoConfig_.split_outfile_name().empty()) {
resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
resultWriter_->flush(resultWriter_);
if (endFlag.empty()) {
return;
} 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)

View File

@ -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",
]

View File

@ -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}"

View File

@ -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<TraceFileWriter> 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<TraceFileWriter>(g_config.split_outfile_name());
g_splitTraceWriter->WriteStandalonePluginData(
std::string(g_pluginModule.name) + "_config",
std::string(reinterpret_cast<const char *>(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<std::mutex> 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;
}

View File

@ -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}"

View File

@ -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<TraceFileWriter> g_splitTraceWriter {nullptr};
bool ParseConfigToCmd(const HiperfPluginConfig& config, std::vector<std::string>& cmds)
{
@ -112,12 +115,20 @@ bool RunCommand(const std::string& cmd)
int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize)
{
std::lock_guard<std::mutex> 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<TraceFileWriter>(g_config.split_outfile_name());
g_splitTraceWriter->WriteStandalonePluginData(
std::string(g_pluginModule.name) + "_config",
std::string(reinterpret_cast<const char *>(configData),
configSize));
g_splitTraceWriter->SetTimeSource();
}
std::vector<std::string> 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<std::mutex> 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;
}

View File

@ -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" ]
}

View File

@ -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);

View File

@ -94,12 +94,3 @@ bool StackWriter::Flush()
bytesPending_ = 0;
return true;
}
bool StackWriter::Clear()
{
if (shareMemoryBlock_ == nullptr) {
return false;
}
shareMemoryBlock_->ClearShareMemoryBlock();
return true;
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -21,7 +21,11 @@
#include <cstdio>
#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<char>::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<char> 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<uint64_t>(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<char*>(&header), sizeof(header));
constexpr uint64_t readBufSize = 4 * 1024 * 1024;
std::vector<char> 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;

View File

@ -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();

View File

@ -45,7 +45,6 @@ public:
std::string GetName();
uint32_t GetSize();
EXPORT_API int GetfileDescriptor();
EXPORT_API void ClearShareMemoryBlock();
bool Valid() const;

View File

@ -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)
{

View File

@ -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;

View File

@ -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}"
}

View File

@ -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;
}

View File

@ -18,4 +18,5 @@ option optimize_for = LITE_RUNTIME;
message HiebpfConfig {
string cmd_line = 1;
string outfile_name = 2;
string split_outfile_name = 3;
}

View File

@ -25,4 +25,5 @@ message HiperfPluginConfig {
DEBUG = 3;
};
LogLevel log_level = 4; // set log level, default is NO_LOG
string split_outfile_name = 5;
}