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