• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "hiperf_plugin_config.pb.h"
26 #include "logging.h"
27 #include "securec.h"
28 #include "common.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         CHECK_TRUE(ret == EOK, false, "strncpy_s error! outfile is %s", config.outfile_name().c_str());
70     }
71     if (!config.record_args().empty()) {
72         prepareCmd += " " + config.record_args();
73     }
74 
75     // command of start
76     auto &startCmd = cmds.emplace_back();
77     startCmd = g_isRoot ? SU_ROOT : "";
78     startCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_START;
79     return true;
80 }
81 
RunCommand(const std::string & cmd)82 bool RunCommand(const std::string& cmd)
83 {
84     HILOG_INFO(LOG_CORE, "run command: %s", cmd.c_str());
85     bool res = false;
86     std::vector<std::string> cmdArg;
87     COMMON::SplitString(cmd, " ", cmdArg);
88     cmdArg.emplace(cmdArg.begin(), HIPERF_BIN_PATH);
89 
90     volatile pid_t childPid = -1;
91     int pipeFds[2] = {-1, -1};
92     FILE* fp = COMMON::CustomPopen(cmdArg, "r", pipeFds, childPid);
93     CHECK_NOTNULL(fp, false, "HiperfPlugin::RunCommand CustomPopen FAILED!r");
94     constexpr uint32_t readBufferSize = 4096;
95     std::array<char, readBufferSize> buffer;
96     std::string result;
97     usleep(WAIT_HIPERF_TIME);
98     while (fgets(buffer.data(), buffer.size(), fp) != nullptr) {
99         result += buffer.data();
100         res = result.find(HIPERF_RECORD_OK) != std::string::npos;
101         if (res) {
102             break;
103         }
104     }
105     COMMON::CustomPclose(fp, pipeFds, childPid);
106     HILOG_INFO(LOG_CORE, "run command result: %s", result.c_str());
107     CHECK_TRUE(res, false, "HiperfPlugin::RunCommand: execute command FAILED!");
108     return true;
109 }
110 } // namespace
111 
HiperfPluginSessionStart(const uint8_t * configData,const uint32_t configSize)112 int HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize)
113 {
114     std::lock_guard<std::mutex> guard(g_taskMutex);
115     HiperfPluginConfig config;
116     bool res = config.ParseFromArray(configData, configSize);
117     CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config from array FAILED! configSize: %u", configSize);
118 
119     std::vector<std::string> cmds;
120     res = ParseConfigToCmd(config, cmds);
121     CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config FAILED!");
122 
123     for (const auto &cmd : cmds) {
124         res = RunCommand(cmd);
125         CHECK_TRUE(res, -1, "HiperfPluginSessionStart, RunCommand(%s) FAILED!", cmd.c_str());
126     }
127 
128     return 0;
129 }
130 
HiperfPluginSessionStop(void)131 int HiperfPluginSessionStop(void)
132 {
133     std::lock_guard<std::mutex> guard(g_taskMutex);
134     std::string cmd;
135     if (g_isRoot) {
136         cmd = SU_ROOT;
137     }
138     cmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD;
139     cmd += HIPERF_RECORD_STOP;
140     RunCommand(cmd);
141     usleep(250000); // 250000: wait for perf.data
142     return 0;
143 }
144 
HiperfRegisterWriterStruct(const WriterStruct * writer)145 int HiperfRegisterWriterStruct(const WriterStruct* writer)
146 {
147     HILOG_INFO(LOG_CORE, "%s:writer", __func__);
148     return 0;
149 }
150 
151 static PluginModuleCallbacks g_callbacks = {
152     .onPluginSessionStart = HiperfPluginSessionStart,
153     .onPluginReportResult = 0,
154     .onPluginSessionStop = HiperfPluginSessionStop,
155     .onRegisterWriterStruct = HiperfRegisterWriterStruct,
156 };
157 
158 EXPORT_API PluginModuleStruct g_pluginModule = {
159     .callbacks = &g_callbacks,
160     .name = "hiperf-plugin",
161     .version = "1.02",
162     .resultBufferSizeHint = MAX_BUFFER_SIZE,
163     .isStandaloneFileData = true,
164     .outFileName = "/data/local/tmp/perf.data",
165 };