106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci#include "hiperf_module.h" 1606f6ba60Sopenharmony_ci 1706f6ba60Sopenharmony_ci#include <array> 1806f6ba60Sopenharmony_ci#include <poll.h> 1906f6ba60Sopenharmony_ci#include <sys/stat.h> 2006f6ba60Sopenharmony_ci#include <sys/types.h> 2106f6ba60Sopenharmony_ci#include <sys/wait.h> 2206f6ba60Sopenharmony_ci#include <unistd.h> 2306f6ba60Sopenharmony_ci#include <vector> 2406f6ba60Sopenharmony_ci 2506f6ba60Sopenharmony_ci#include "hiperf_plugin_config.pb.h" 2606f6ba60Sopenharmony_ci#include "logging.h" 2706f6ba60Sopenharmony_ci#include "securec.h" 2806f6ba60Sopenharmony_ci#include "common.h" 2906f6ba60Sopenharmony_ci#include "trace_file_writer.h" 3006f6ba60Sopenharmony_ci 3106f6ba60Sopenharmony_cinamespace { 3206f6ba60Sopenharmony_ciconstexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024; 3306f6ba60Sopenharmony_ciconstexpr uint32_t SLEEP_TIME = 250000; 3406f6ba60Sopenharmony_ciconst std::string SU_ROOT = "su root"; 3506f6ba60Sopenharmony_ciconst std::string HIPERF_CMD = " hiperf"; 3606f6ba60Sopenharmony_ciconst std::string HIPERF_RECORD_CMD = " record"; 3706f6ba60Sopenharmony_ciconst std::string HIPERF_RECORD_PREPARE = " --control prepare"; 3806f6ba60Sopenharmony_ciconst std::string HIPERF_RECORD_START = " --control start"; 3906f6ba60Sopenharmony_ciconst std::string HIPERF_RECORD_STOP = " --control stop"; 4006f6ba60Sopenharmony_ciconst std::string HIPERF_RECORD_OK = "sampling success"; 4106f6ba60Sopenharmony_ciconst int WAIT_HIPERF_TIME = 10; 4206f6ba60Sopenharmony_ciconst std::string HIPERF_BIN_PATH = "/system/bin/hiperf"; 4306f6ba60Sopenharmony_ci 4406f6ba60Sopenharmony_cistd::mutex g_taskMutex; 4506f6ba60Sopenharmony_cibool g_isRoot = false; 4606f6ba60Sopenharmony_cistd::string g_logLevel = ""; 4706f6ba60Sopenharmony_ciHiperfPluginConfig g_config; 4806f6ba60Sopenharmony_cistd::shared_ptr<TraceFileWriter> g_splitTraceWriter {nullptr}; 4906f6ba60Sopenharmony_ci 5006f6ba60Sopenharmony_cibool ParseConfigToCmd(const HiperfPluginConfig& config, std::vector<std::string>& cmds) 5106f6ba60Sopenharmony_ci{ 5206f6ba60Sopenharmony_ci g_isRoot = config.is_root(); 5306f6ba60Sopenharmony_ci auto logLevel = config.log_level(); 5406f6ba60Sopenharmony_ci if (logLevel == HiperfPluginConfig_LogLevel_MUCH) { 5506f6ba60Sopenharmony_ci g_logLevel = " --hilog --much"; 5606f6ba60Sopenharmony_ci } else if (logLevel == HiperfPluginConfig_LogLevel_VERBOSE) { 5706f6ba60Sopenharmony_ci g_logLevel = " --hilog --verbose"; 5806f6ba60Sopenharmony_ci } else if (logLevel == HiperfPluginConfig_LogLevel_DEBUG) { 5906f6ba60Sopenharmony_ci g_logLevel = " --hilog --debug"; 6006f6ba60Sopenharmony_ci } else { 6106f6ba60Sopenharmony_ci g_logLevel = " --nodebug"; 6206f6ba60Sopenharmony_ci } 6306f6ba60Sopenharmony_ci 6406f6ba60Sopenharmony_ci // command of prepare 6506f6ba60Sopenharmony_ci std::string traceCmd; 6606f6ba60Sopenharmony_ci auto &prepareCmd = cmds.emplace_back(); 6706f6ba60Sopenharmony_ci prepareCmd = g_isRoot ? SU_ROOT : ""; 6806f6ba60Sopenharmony_ci prepareCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_PREPARE; 6906f6ba60Sopenharmony_ci if (!config.outfile_name().empty()) { 7006f6ba60Sopenharmony_ci prepareCmd += " -o " + config.outfile_name(); 7106f6ba60Sopenharmony_ci size_t fileSize = sizeof(g_pluginModule.outFileName); 7206f6ba60Sopenharmony_ci int ret = strncpy_s(g_pluginModule.outFileName, fileSize, config.outfile_name().c_str(), fileSize - 1); 7306f6ba60Sopenharmony_ci CHECK_TRUE(ret == EOK, false, "strncpy_s error! outfile is %s", config.outfile_name().c_str()); 7406f6ba60Sopenharmony_ci } 7506f6ba60Sopenharmony_ci if (!config.record_args().empty()) { 7606f6ba60Sopenharmony_ci prepareCmd += " " + config.record_args(); 7706f6ba60Sopenharmony_ci } 7806f6ba60Sopenharmony_ci 7906f6ba60Sopenharmony_ci // command of start 8006f6ba60Sopenharmony_ci auto &startCmd = cmds.emplace_back(); 8106f6ba60Sopenharmony_ci startCmd = g_isRoot ? SU_ROOT : ""; 8206f6ba60Sopenharmony_ci startCmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD + HIPERF_RECORD_START; 8306f6ba60Sopenharmony_ci return true; 8406f6ba60Sopenharmony_ci} 8506f6ba60Sopenharmony_ci 8606f6ba60Sopenharmony_cibool RunCommand(const std::string& cmd) 8706f6ba60Sopenharmony_ci{ 8806f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "run command: %s", cmd.c_str()); 8906f6ba60Sopenharmony_ci bool res = false; 9006f6ba60Sopenharmony_ci std::vector<std::string> cmdArg; 9106f6ba60Sopenharmony_ci COMMON::SplitString(cmd, " ", cmdArg); 9206f6ba60Sopenharmony_ci cmdArg.emplace(cmdArg.begin(), HIPERF_BIN_PATH); 9306f6ba60Sopenharmony_ci 9406f6ba60Sopenharmony_ci volatile pid_t childPid = -1; 9506f6ba60Sopenharmony_ci int pipeFds[2] = {-1, -1}; 9606f6ba60Sopenharmony_ci FILE* fp = COMMON::CustomPopen(cmdArg, "r", pipeFds, childPid); 9706f6ba60Sopenharmony_ci CHECK_NOTNULL(fp, false, "HiperfPlugin::RunCommand CustomPopen FAILED!r"); 9806f6ba60Sopenharmony_ci constexpr uint32_t readBufferSize = 4096; 9906f6ba60Sopenharmony_ci std::array<char, readBufferSize> buffer; 10006f6ba60Sopenharmony_ci std::string result; 10106f6ba60Sopenharmony_ci usleep(WAIT_HIPERF_TIME); 10206f6ba60Sopenharmony_ci while (fgets(buffer.data(), buffer.size(), fp) != nullptr) { 10306f6ba60Sopenharmony_ci result += buffer.data(); 10406f6ba60Sopenharmony_ci res = result.find(HIPERF_RECORD_OK) != std::string::npos; 10506f6ba60Sopenharmony_ci if (res) { 10606f6ba60Sopenharmony_ci break; 10706f6ba60Sopenharmony_ci } 10806f6ba60Sopenharmony_ci } 10906f6ba60Sopenharmony_ci COMMON::CustomPclose(fp, pipeFds, childPid); 11006f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "run command result: %s", result.c_str()); 11106f6ba60Sopenharmony_ci CHECK_TRUE(res, false, "HiperfPlugin::RunCommand: execute command FAILED!"); 11206f6ba60Sopenharmony_ci return true; 11306f6ba60Sopenharmony_ci} 11406f6ba60Sopenharmony_ci} // namespace 11506f6ba60Sopenharmony_ci 11606f6ba60Sopenharmony_ciint HiperfPluginSessionStart(const uint8_t* configData, const uint32_t configSize) 11706f6ba60Sopenharmony_ci{ 11806f6ba60Sopenharmony_ci if (configData == nullptr) { 11906f6ba60Sopenharmony_ci return -1; 12006f6ba60Sopenharmony_ci } 12106f6ba60Sopenharmony_ci std::lock_guard<std::mutex> guard(g_taskMutex); 12206f6ba60Sopenharmony_ci (void)remove("/data/local/tmp/perf.data"); 12306f6ba60Sopenharmony_ci bool res = g_config.ParseFromArray(configData, configSize); 12406f6ba60Sopenharmony_ci CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config from array FAILED! configSize: %u", configSize); 12506f6ba60Sopenharmony_ci 12606f6ba60Sopenharmony_ci if (!g_config.split_outfile_name().empty()) { 12706f6ba60Sopenharmony_ci g_splitTraceWriter = std::make_shared<TraceFileWriter>(g_config.split_outfile_name()); 12806f6ba60Sopenharmony_ci g_splitTraceWriter->WriteStandalonePluginData( 12906f6ba60Sopenharmony_ci std::string(g_pluginModule.name) + "_config", 13006f6ba60Sopenharmony_ci std::string(reinterpret_cast<const char *>(configData), 13106f6ba60Sopenharmony_ci configSize)); 13206f6ba60Sopenharmony_ci g_splitTraceWriter->SetTimeSource(); 13306f6ba60Sopenharmony_ci } 13406f6ba60Sopenharmony_ci 13506f6ba60Sopenharmony_ci std::vector<std::string> cmds; 13606f6ba60Sopenharmony_ci res = ParseConfigToCmd(g_config, cmds); 13706f6ba60Sopenharmony_ci CHECK_TRUE(res, -1, "HiperfPluginSessionStart, parse config FAILED!"); 13806f6ba60Sopenharmony_ci 13906f6ba60Sopenharmony_ci for (const auto &cmd : cmds) { 14006f6ba60Sopenharmony_ci res = RunCommand(cmd); 14106f6ba60Sopenharmony_ci CHECK_TRUE(res, -1, "HiperfPluginSessionStart, RunCommand(%s) FAILED!", cmd.c_str()); 14206f6ba60Sopenharmony_ci } 14306f6ba60Sopenharmony_ci 14406f6ba60Sopenharmony_ci return 0; 14506f6ba60Sopenharmony_ci} 14606f6ba60Sopenharmony_ci 14706f6ba60Sopenharmony_ciint HiperfPluginSessionStop(void) 14806f6ba60Sopenharmony_ci{ 14906f6ba60Sopenharmony_ci std::lock_guard<std::mutex> guard(g_taskMutex); 15006f6ba60Sopenharmony_ci if (!g_config.split_outfile_name().empty()) { 15106f6ba60Sopenharmony_ci CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, SetDurationTime failed", __func__); 15206f6ba60Sopenharmony_ci g_splitTraceWriter->SetDurationTime(); 15306f6ba60Sopenharmony_ci } 15406f6ba60Sopenharmony_ci 15506f6ba60Sopenharmony_ci std::string cmd; 15606f6ba60Sopenharmony_ci if (g_isRoot) { 15706f6ba60Sopenharmony_ci cmd = SU_ROOT; 15806f6ba60Sopenharmony_ci } 15906f6ba60Sopenharmony_ci cmd += HIPERF_CMD + g_logLevel + HIPERF_RECORD_CMD; 16006f6ba60Sopenharmony_ci cmd += HIPERF_RECORD_STOP; 16106f6ba60Sopenharmony_ci RunCommand(cmd); 16206f6ba60Sopenharmony_ci usleep(SLEEP_TIME); // 250000: wait for perf.data 16306f6ba60Sopenharmony_ci 16406f6ba60Sopenharmony_ci if (!g_config.split_outfile_name().empty()) { // write split file. 16506f6ba60Sopenharmony_ci CHECK_NOTNULL(g_splitTraceWriter, -1, "%s: writer is nullptr, WriteStandaloneFile failed", __func__); 16606f6ba60Sopenharmony_ci g_splitTraceWriter->WriteStandalonePluginFile(std::string(g_pluginModule.outFileName), 16706f6ba60Sopenharmony_ci std::string(g_pluginModule.name), std::string(g_pluginModule.version), DataType::HIPERF_DATA); 16806f6ba60Sopenharmony_ci g_splitTraceWriter->Finish(); 16906f6ba60Sopenharmony_ci g_splitTraceWriter.reset(); 17006f6ba60Sopenharmony_ci g_splitTraceWriter = nullptr; 17106f6ba60Sopenharmony_ci } 17206f6ba60Sopenharmony_ci return 0; 17306f6ba60Sopenharmony_ci} 17406f6ba60Sopenharmony_ci 17506f6ba60Sopenharmony_ciint HiperfRegisterWriterStruct(const WriterStruct* writer) 17606f6ba60Sopenharmony_ci{ 17706f6ba60Sopenharmony_ci PROFILER_LOG_INFO(LOG_CORE, "%s:writer", __func__); 17806f6ba60Sopenharmony_ci return 0; 17906f6ba60Sopenharmony_ci} 18006f6ba60Sopenharmony_ci 18106f6ba60Sopenharmony_cistatic PluginModuleCallbacks g_callbacks = { 18206f6ba60Sopenharmony_ci .onPluginSessionStart = HiperfPluginSessionStart, 18306f6ba60Sopenharmony_ci .onPluginReportResult = 0, 18406f6ba60Sopenharmony_ci .onPluginSessionStop = HiperfPluginSessionStop, 18506f6ba60Sopenharmony_ci .onRegisterWriterStruct = HiperfRegisterWriterStruct, 18606f6ba60Sopenharmony_ci}; 18706f6ba60Sopenharmony_ci 18806f6ba60Sopenharmony_ciEXPORT_API PluginModuleStruct g_pluginModule = { 18906f6ba60Sopenharmony_ci .callbacks = &g_callbacks, 19006f6ba60Sopenharmony_ci .name = "hiperf-plugin", 19106f6ba60Sopenharmony_ci .version = "1.02", 19206f6ba60Sopenharmony_ci .resultBufferSizeHint = MAX_BUFFER_SIZE, 19306f6ba60Sopenharmony_ci .isStandaloneFileData = true, 19406f6ba60Sopenharmony_ci .outFileName = "/data/local/tmp/perf.data", 19506f6ba60Sopenharmony_ci};