1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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 "logging.h"
28 #include "securec.h"
29
30 namespace {
31 constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
32 const std::string SU_ROOT = "su root";
33 const std::string HIPERF_CMD = " hiperf";
34 const std::string HIPERF_RECORD_CMD = " record";
35 const std::string HIPERF_RECORD_PREPARE = " --control prepare";
36 const std::string HIPERF_RECORD_START = " --control start";
37 const std::string HIPERF_RECORD_STOP = " --control stop";
38 const std::string HIPERF_RECORD_OK = "sampling success";
39 const int WAIT_HIPERF_TIME = 10;
40 const std::string HIPERF_BIN_PATH = "/system/bin/hiperf";
41
42 std::mutex g_taskMutex;
43 bool g_isRoot = false;
44 std::string g_logLevel = "";
45
ParseConfigToCmd(const HiperfPluginConfig & config,std::vector<std::string> & cmds)46 bool ParseConfigToCmd(const HiperfPluginConfig& config, std::vector<std::string>& cmds)
47 {
48 g_isRoot = config.is_root();
49 auto logLevel = config.log_level();
50 if (logLevel == HiperfPluginConfig_LogLevel_MUCH) {
51 g_logLevel = " --hilog --much";
52 } else if (logLevel == HiperfPluginConfig_LogLevel_VERBOSE) {
53 g_logLevel = " --hilog --verbose";
54 } else if (logLevel == HiperfPluginConfig_LogLevel_DEBUG) {
55 g_logLevel = " --hilog --debug";
56 } else {
57 g_logLevel = " --nodebug";
58 }
59
60 // command of prepare
61 std::string traceCmd;
62 auto &prepareCmd = cmds.emplace_back();
63 prepareCmd = g_isRoot ? SU_ROOT : "";
64 prepareCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_PREPARE;
65 if (!config.outfile_name().empty()) {
66 prepareCmd += " -o " + config.outfile_name();
67 size_t fileSize = sizeof(g_pluginModule.outFileName);
68 int ret = strncpy_s(g_pluginModule.outFileName, fileSize, config.outfile_name().c_str(), fileSize - 1);
69 if (ret != EOK) {
70 HILOG_ERROR(LOG_CORE, "strncpy_s error! outfile is %s", config.outfile_name().c_str());
71 return false;
72 }
73 }
74 if (!config.record_args().empty()) {
75 prepareCmd += " " + config.record_args();
76 }
77
78 // command of start
79 auto &startCmd = cmds.emplace_back();
80 startCmd = g_isRoot ? SU_ROOT : "";
81 startCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_START;
82 return true;
83 }
84
RunCommand(const std::string & cmd)85 bool RunCommand(const std::string& cmd)
86 {
87 HILOG_INFO(LOG_CORE, "run command: %s", cmd.c_str());
88 int childPid = -1;
89 bool res = false;
90 std::vector<std::string> cmdArg;
91 COMMON::SplitString(cmd, " ", cmdArg);
92 FILE* fp = COMMON::CustomPopen(childPid, HIPERF_BIN_PATH, cmdArg, "r");
93 if (fp == nullptr) {
94 HILOG_ERROR(LOG_CORE, "HiperfPlugin::RunCommand CustomPopen FAILED!r");
95 return false;
96 }
97 constexpr uint32_t readBufferSize = 4096;
98 std::array<char, readBufferSize> buffer;
99 std::string result;
100 usleep(WAIT_HIPERF_TIME);
101 while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
102 result += buffer.data();
103 res = result.find(HIPERF_RECORD_OK) != std::string::npos;
104 if (res) {
105 break;
106 }
107 }
108 COMMON::CustomPclose(fp, childPid);
109 HILOG_INFO(LOG_CORE, "run command result: %s", result.c_str());
110 CHECK_TRUE(res, false, "HiperfPlugin::RunCommand: execute command FAILED!");
111 return true;
112 }
113 } // namespace
114
HiperfPluginSessionStart(const uint8_t * configData,const uint32_t configSize)115 int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize)
116 {
117 std::lock_guard<std::mutex> guard(g_taskMutex);
118 HiperfPluginConfig config;
119 bool res = config.ParseFromArray(configData, configSize);
120 CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config from array FAILED! configSize: %u", configSize);
121
122 std::vector<std::string> cmds;
123 res = ParseConfigToCmd(config, cmds);
124 CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config FAILED!");
125
126 for (const auto &cmd : cmds) {
127 res = RunCommand(cmd);
128 CHECK_TRUE(res, -1, "HiperfPluginSessionStart, RunCommand(%s) FAILED!", cmd.c_str());
129 }
130
131 return 0;
132 }
133
HiperfPluginSessionStop(void)134 int HiperfPluginSessionStop(void)
135 {
136 std::lock_guard<std::mutex> guard(g_taskMutex);
137 std::string cmd;
138 if (g_isRoot) {
139 cmd = SU_ROOT;
140 }
141 cmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD;
142 cmd += HIPERF_RECORD_STOP;
143 RunCommand(cmd);
144 usleep(250000); // 250000: wait for perf.data
145 return 0;
146 }
147
HiperfRegisterWriterStruct(const WriterStruct * writer)148 int HiperfRegisterWriterStruct(const WriterStruct* writer)
149 {
150 HILOG_INFO(LOG_CORE, "%s:writer %p", __func__, writer);
151 return 0;
152 }
153
154 static PluginModuleCallbacks g_callbacks = {
155 .onPluginSessionStart = HiperfPluginSessionStart,
156 .onPluginReportResult = 0,
157 .onPluginSessionStop = HiperfPluginSessionStop,
158 .onRegisterWriterStruct = HiperfRegisterWriterStruct,
159 };
160
161 EXPORT_API PluginModuleStruct g_pluginModule = {
162 .callbacks = &g_callbacks,
163 .name = "hiperf-plugin",
164 .version = "1.01",
165 .resultBufferSizeHint = MAX_BUFFER_SIZE,
166 .isStandaloneFileData = true,
167 .outFileName = "/data/local/tmp/perf.data",
168 };