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 "bytrace_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 "bytrace_plugin_config.pb.h"
26 #include "logging.h"
27 #include "securec.h"
28
29 namespace {
30 constexpr uint32_t MAX_BUFFER_SIZE = 4 * 1024 * 1024;
31 constexpr uint32_t READ_BUFFER_SIZE = 4096;
32 const std::string DEFAULT_FILE = "/local/data/tmp/bytrace.txt";
33
34 std::mutex g_taskMutex;
35
36 struct BytraceInfo {
37 bool isRoot;
38 uint32_t buffSize;
39 uint32_t time;
40 std::string clockType;
41 std::string outFile;
42 std::vector<std::string> categoryVec;
43 };
44 std::unique_ptr<BytraceInfo> g_bytraceInfo = nullptr;
45
ParseConfig(const BytracePluginConfig & config)46 void ParseConfig(const BytracePluginConfig& config)
47 {
48 if (config.buffe_size() != 0) {
49 g_bytraceInfo->buffSize = config.buffe_size();
50 }
51 g_bytraceInfo->time = config.time();
52 g_bytraceInfo->isRoot = config.is_root();
53 if (!config.clock().empty()) {
54 g_bytraceInfo->clockType = config.clock();
55 }
56 if (!config.outfile_name().empty()) {
57 g_bytraceInfo->outFile = config.outfile_name();
58 }
59 if (!config.categories().empty()) {
60 for (std::string category : config.categories()) {
61 g_bytraceInfo->categoryVec.push_back(category);
62 }
63 }
64 }
65
RunCommand(const std::string & cmd)66 bool RunCommand(const std::string& cmd)
67 {
68 PROFILER_LOG_INFO(LOG_CORE, "%s:start running commond: %s", __func__, cmd.c_str());
69 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.data(), "r"), pclose);
70 CHECK_TRUE(pipe, false, "BytraceCall::RunCommand: create popen FAILED!");
71
72 std::array<char, READ_BUFFER_SIZE> buffer;
73 std::string result;
74 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
75 result += buffer.data();
76 }
77 PROFILER_LOG_INFO(LOG_CORE, "%s:runCommand result: %s", __func__, result.data());
78 return true;
79 }
80
BeginTrace()81 bool BeginTrace()
82 {
83 // two case: real-time and offline type.
84 std::string beginCmd;
85 if (g_bytraceInfo->isRoot) {
86 beginCmd = "su root ";
87 }
88 beginCmd += "bytrace ";
89 if (g_bytraceInfo->buffSize != 0) {
90 beginCmd += " -b " + std::to_string(g_bytraceInfo->buffSize);
91 }
92 if (!g_bytraceInfo->clockType.empty()) {
93 beginCmd += " --trace_clock " + g_bytraceInfo->clockType;
94 }
95 // real-time: time is set 0.
96 if (g_bytraceInfo->time == 0) {
97 // if time is not set 1s(must >= 1), bytrace tool will use 5s by default.
98 beginCmd += " -t 1 ";
99 beginCmd += " --trace_begin ";
100 } else {
101 beginCmd += " -t " + std::to_string(g_bytraceInfo->time);
102 beginCmd += " -o ";
103 beginCmd += g_bytraceInfo->outFile;
104 beginCmd += " ";
105 }
106 for (const std::string& category : g_bytraceInfo->categoryVec) {
107 beginCmd += category;
108 beginCmd += " ";
109 }
110 return RunCommand(beginCmd);
111 }
112
StopTrace()113 bool StopTrace()
114 {
115 std::string finishCmd;
116 if (g_bytraceInfo->isRoot) {
117 finishCmd = "su root ";
118 }
119 finishCmd += "bytrace --trace_finish --trace_dump";
120 if (g_bytraceInfo->outFile.empty()) {
121 g_bytraceInfo->outFile = DEFAULT_FILE;
122 }
123 finishCmd += " -o ";
124 finishCmd += g_bytraceInfo->outFile;
125 return RunCommand(finishCmd);
126 }
127 } // namespace
128
BytracePluginSessionStart(const uint8_t * configData,const uint32_t configSize)129 int BytracePluginSessionStart(const uint8_t* configData, const uint32_t configSize)
130 {
131 std::lock_guard<std::mutex> guard(g_taskMutex);
132 BytracePluginConfig config;
133 int res = config.ParseFromArray(configData, configSize);
134 CHECK_TRUE(res, 0, "BytracePluginSessionStart, parse config FAILED! configSize: %u", configSize);
135 g_bytraceInfo = std::make_unique<BytraceInfo>();
136 ParseConfig(config);
137 res = BeginTrace();
138 CHECK_TRUE(res, 0, "BytracePluginSessionStart, bytrace begin FAILED!");
139 return 0;
140 }
141
BytracePluginSessionStop()142 int BytracePluginSessionStop()
143 {
144 std::lock_guard<std::mutex> guard(g_taskMutex);
145 // real-time type need finish trace.
146 if (g_bytraceInfo->time == 0) {
147 int res = StopTrace();
148 CHECK_TRUE(res, 0, "BytracePluginSessionStop, bytrace finish FAILED!");
149 }
150 g_bytraceInfo = nullptr;
151 return 0;
152 }
153
BytraceRegisterWriterStruct(const WriterStruct * writer)154 int BytraceRegisterWriterStruct(const WriterStruct* writer)
155 {
156 PROFILER_LOG_INFO(LOG_CORE, "%s:writer %p", __func__, writer);
157 return 0;
158 }
159
160 static PluginModuleCallbacks g_callbacks = {
161 .onPluginSessionStart = BytracePluginSessionStart,
162 .onPluginReportResult = nullptr,
163 .onPluginSessionStop = BytracePluginSessionStop,
164 .onRegisterWriterStruct = BytraceRegisterWriterStruct,
165 };
166
167 EXPORT_API PluginModuleStruct g_pluginModule = {
168 .callbacks = &g_callbacks,
169 .name = "bytrace_plugin",
170 .version = "1.02",
171 .resultBufferSizeHint = MAX_BUFFER_SIZE,
172 };