• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "hiperf_module.h"
16 
17 #include <array>
18 #include <poll.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 #include <vector>
24 
25 #include "common.h"
26 #include "hiperf_plugin_config.pb.h"
27 #include "hisysevent.h"
28 #include "logging.h"
29 #include "securec.h"
30 #include "trace_file_writer.h"
31 
32 namespace {
33 constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
34 constexpr uint32_t SLEEP_TIME = 250000;
35 const std::string SU_ROOT = "su root";
36 const std::string HIPERF_CMD = " hiperf";
37 const std::string HIPERF_RECORD_CMD = " record";
38 const std::string HIPERF_RECORD_PREPARE = " --control prepare";
39 const std::string HIPERF_RECORD_START = " --control start";
40 const std::string HIPERF_RECORD_STOP = " --control stop";
41 const std::string HIPERF_RECORD_OK = "sampling success";
42 const int WAIT_HIPERF_TIME = 10;
43 const std::string HIPERF_BIN_PATH = "/system/bin/hiperf";
44 
45 std::mutex g_taskMutex;
46 bool g_isRoot = false;
47 std::string g_logLevel = "";
48 HiperfPluginConfig g_config;
49 std::shared_ptr<TraceFileWriter> g_splitTraceWriter {nullptr};
50 
ParseConfigToCmd(const HiperfPluginConfig & config,std::vector<std::string> & cmds)51 bool ParseConfigToCmd(const HiperfPluginConfig& config, std::vector<std::string>& cmds)
52 {
53     g_isRoot = config.is_root();
54     auto logLevel = config.log_level();
55     if (logLevel == HiperfPluginConfig_LogLevel_MUCH) {
56         g_logLevel = " --hilog --much";
57     } else if (logLevel == HiperfPluginConfig_LogLevel_VERBOSE) {
58         g_logLevel = " --hilog --verbose";
59     } else if (logLevel == HiperfPluginConfig_LogLevel_DEBUG) {
60         g_logLevel = " --hilog --debug";
61     } else {
62         g_logLevel = " --nodebug";
63     }
64 
65     // command of prepare
66     std::string traceCmd;
67     auto &prepareCmd = cmds.emplace_back();
68     prepareCmd = g_isRoot ? SU_ROOT : "";
69     prepareCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_PREPARE;
70     if (!config.outfile_name().empty()) {
71         prepareCmd += " -o " + config.outfile_name();
72         size_t fileSize = sizeof(g_pluginModule.outFileName);
73         int ret = strncpy_s(g_pluginModule.outFileName, fileSize, config.outfile_name().c_str(), fileSize - 1);
74         CHECK_TRUE(ret == EOK, false, "strncpy_s error! outfile is %s", config.outfile_name().c_str());
75     }
76     if (!config.record_args().empty()) {
77         prepareCmd += " " + config.record_args();
78     }
79 
80     // command of start
81     auto &startCmd = cmds.emplace_back();
82     startCmd = g_isRoot ? SU_ROOT : "";
83     startCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_START;
84     return true;
85 }
86 
RunCommand(const std::string & cmd)87 bool RunCommand(const std::string& cmd)
88 {
89     PROFILER_LOG_INFO(LOG_CORE, "run command: %s", cmd.c_str());
90     bool res = false;
91     std::vector<std::string> cmdArg;
92     COMMON::SplitString(cmd, " ", cmdArg);
93     cmdArg.emplace(cmdArg.begin(), HIPERF_BIN_PATH);
94 
95     volatile pid_t childPid = -1;
96     int pipeFds[2] = {-1, -1};
97     FILE* fp = COMMON::CustomPopen(cmdArg, "r", pipeFds, childPid);
98     CHECK_NOTNULL(fp, false, "HiperfPlugin::RunCommand CustomPopen FAILED!r");
99     constexpr uint32_t readBufferSize = 4096;
100     std::array<char, readBufferSize> buffer;
101     std::string result;
102     usleep(WAIT_HIPERF_TIME);
103     while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
104         result += buffer.data();
105         res = result.find(HIPERF_RECORD_OK) != std::string::npos;
106         if (res) {
107             break;
108         }
109     }
110     COMMON::CustomPclose(fp, pipeFds, childPid);
111     PROFILER_LOG_INFO(LOG_CORE, "run command result: %s", result.c_str());
112     CHECK_TRUE(res, false, "HiperfPlugin::RunCommand: execute command FAILED!");
113     return true;
114 }
115 
GetCmdArgs(const HiperfPluginConfig & protoConfig)116 std::string GetCmdArgs(const HiperfPluginConfig& protoConfig)
117 {
118     std::stringstream args;
119     args << "is_root: " << (protoConfig.is_root() ? "true" : "false") << ", ";
120     args << "record_args: " << protoConfig.record_args() << ", ";
121     args << "split_outfile_name: " << protoConfig.split_outfile_name() << ", ";
122     args << "log_level: " << std::to_string(protoConfig.log_level());
123     return args.str();
124 }
125 } // namespace
126 
HiperfPluginSessionStart(const uint8_t * configData,const uint32_t configSize)127 int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize)
128 {
129     if (configData == nullptr) {
130         return -1;
131     }
132     std::lock_guard<std::mutex> guard(g_taskMutex);
133     (void)remove("/data/local/tmp/perf.data");
134     bool res = g_config.ParseFromArray(configData, configSize);
135     CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config from array FAILED! configSize: %u", configSize);
136 
137     if (!g_config.split_outfile_name().empty()) {
138         g_splitTraceWriter = std::make_shared<TraceFileWriter>(g_config.split_outfile_name());
139         g_splitTraceWriter->WriteStandalonePluginData(
140             std::string(g_pluginModule.name) + "_config",
141             std::string(reinterpret_cast<const char *>(configData),
142                         configSize));
143         g_splitTraceWriter->SetTimeSource();
144     }
145 
146     std::vector<std::string> cmds;
147     res = ParseConfigToCmd(g_config, cmds);
148     CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config FAILED!");
149 
150     for (const auto &cmd : cmds) {
151         res = RunCommand(cmd);
152         CHECK_TRUE(res, -1, "HiperfPluginSessionStart, RunCommand(%s) FAILED!", cmd.c_str());
153     }
154 
155     int ret = COMMON::PluginWriteToHisysevent("hiperf_plugin", "sh", GetCmdArgs(g_config),
156                                               COMMON::ErrorType::RET_SUCC, "success");
157     PROFILER_LOG_INFO(LOG_CORE, "hisysevent report hiperf_plugin result:%d", ret);
158     return 0;
159 }
160 
HiperfPluginSessionStop(void)161 int HiperfPluginSessionStop(void)
162 {
163     std::lock_guard<std::mutex> guard(g_taskMutex);
164     if (!g_config.split_outfile_name().empty()) {
165         CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, SetDurationTime failed", __func__);
166         g_splitTraceWriter->SetDurationTime();
167     }
168 
169     std::string cmd;
170     if (g_isRoot) {
171         cmd = SU_ROOT;
172     }
173     cmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD;
174     cmd += HIPERF_RECORD_STOP;
175     RunCommand(cmd);
176     usleep(SLEEP_TIME); // 250000: wait for perf.data
177 
178     if (!g_config.split_outfile_name().empty()) { // write split file.
179         CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__);
180         g_splitTraceWriter->WriteStandalonePluginFile(std::string(g_pluginModule.outFileName),
181             std::string(g_pluginModule.name), std::string(g_pluginModule.version), DataType::HIPERF_DATA);
182         g_splitTraceWriter->Finish();
183         g_splitTraceWriter.reset();
184         g_splitTraceWriter = nullptr;
185     }
186     return 0;
187 }
188 
HiperfRegisterWriterStruct(const WriterStruct * writer)189 int HiperfRegisterWriterStruct(const WriterStruct* writer)
190 {
191     PROFILER_LOG_INFO(LOG_CORE, "%s:writer", __func__);
192     return 0;
193 }
194 
195 static PluginModuleCallbacks g_callbacks = {
196     .onPluginSessionStart = HiperfPluginSessionStart,
197     .onPluginReportResult = 0,
198     .onPluginSessionStop = HiperfPluginSessionStop,
199     .onRegisterWriterStruct = HiperfRegisterWriterStruct,
200 };
201 
202 EXPORT_API PluginModuleStruct g_pluginModule = {
203     .callbacks = &g_callbacks,
204     .name = "hiperf-plugin",
205     .version = "1.02",
206     .resultBufferSizeHint = MAX_BUFFER_SIZE,
207     .isStandaloneFileData = true,
208     .outFileName = "/data/local/tmp/perf.data",
209 };