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 <chrono>
16 #include <cinttypes>
17 #include <fcntl.h>
18 #include <fstream>
19 #include <iostream>
20 #include <memory>
21 #include <stdio.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include "codec_cov.h"
27 #include "file.h"
28 #include "filter/slice_filter.h"
29 #include "http_server.h"
30 #include "log.h"
31 #include "parser/bytrace_parser/bytrace_event_parser.h"
32 #include "parser/bytrace_parser/bytrace_parser.h"
33 #include "parting_string.h"
34 #include "rpc_server.h"
35 #include "string_help.h"
36
37 #include "thread_state_flag.h"
38 #include "trace_streamer/trace_streamer_selector.h"
39 #include "trace_streamer_filters.h"
40 #include "version.h"
41 using namespace SysTuning::TraceStreamer;
42 using namespace SysTuning;
43 namespace SysTuning {
44 namespace TraceStreamer {
45 using namespace SysTuning::TraceStreamer;
46 using namespace SysTuning::base;
47 constexpr size_t G_CHUNK_SIZE = 1024 * 1024;
48 constexpr int G_MIN_PARAM_NUM = 2;
49 constexpr size_t G_FILE_PERMISSION = 664;
50 // set version info in meta.cpp please
ExportStatusToLog(const std::string & dbPath,TraceParserStatus status)51 void ExportStatusToLog(const std::string& dbPath, TraceParserStatus status)
52 {
53 std::string path = dbPath + ".ohos.ts";
54 std::ofstream out(path, std::ios_base::trunc);
55 out << (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
56 .count()
57 << ":" << status << std::endl;
58 using std::chrono::system_clock;
59
60 system_clock::time_point today = system_clock::now();
61
62 std::time_t tt = system_clock::to_time_t(today);
63 out << "last running time is: " << ctime(&tt);
64 out << "last running status is: " << status;
65 out.close();
66 }
ShowHelpInfo(const char * argv)67 void ShowHelpInfo(const char* argv)
68 {
69 TS_LOGI(
70 "trace analyze tool, it can transfer a bytrace/htrace file into a "
71 "SQLite database and save result to a local file trace_streamer.log.\n"
72 "Usage: %s FILE -e sqlite_out.pb\n"
73 " or %s FILE -c\n"
74 "Options:\n"
75 " -e transfer a bytrace file into a SQLiteBased DB. with -nm to except meta table\n"
76 " -c command line mode.\n"
77 " -h start HTTP server.\n"
78 " -s separate arkts-plugin data, and save it in current dir with default filename.\n"
79 " -p Specify the port of HTTP server, default is 9001.\n"
80 " -i show information.\n"
81 " -v show version.",
82 argv, argv);
83 }
PrintInformation()84 void PrintInformation()
85 {
86 TraceStreamerConfig cfg;
87 cfg.PrintInfo();
88 }
PrintVersion()89 void PrintVersion()
90 {
91 fprintf(stderr, "version %s\n", g_traceStreamerVersion.c_str());
92 }
93
LoadQueryFile(const std::string & sqlOperator,std::vector<std::string> & sqlStrings)94 void LoadQueryFile(const std::string& sqlOperator, std::vector<std::string>& sqlStrings)
95 {
96 auto fd = fopen(sqlOperator.c_str(), "r");
97 if (!fd) {
98 TS_LOGE("open file failed!");
99 return;
100 }
101 char buffer[G_CHUNK_SIZE];
102 while (!feof(fd)) {
103 std::string sqlString;
104 while (fgets(buffer, sizeof(buffer), fd)) {
105 std::string line = buffer;
106 if (line == "\n" || line == "\r\n") {
107 break;
108 }
109 sqlString.append(buffer);
110
111 if (EndWith(line, ";") || EndWith(line, ";\r\n")) {
112 break;
113 }
114 }
115
116 if (sqlString.empty()) {
117 continue;
118 }
119 sqlStrings.push_back(sqlString);
120 }
121 fclose(fd);
122 fd = nullptr;
123 }
124
ReadSqlFileAndPrintResult(TraceStreamerSelector & ts,const std::string & sqlOperator)125 void ReadSqlFileAndPrintResult(TraceStreamerSelector& ts, const std::string& sqlOperator)
126 {
127 std::vector<std::string> sqlStrings;
128 LoadQueryFile(sqlOperator, sqlStrings);
129 for (const auto& str : sqlStrings) {
130 ts.SearchDatabase(str, true);
131 }
132 }
133
ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector & ta,int fd)134 bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd)
135 {
136 auto startTime =
137 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
138 .count();
139 g_loadSize = 0;
140 while (true) {
141 std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(G_CHUNK_SIZE);
142 auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE);
143 if (rsize == 0) {
144 break;
145 }
146
147 if (rsize < 0) {
148 TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
149 return false;
150 }
151 g_loadSize += rsize;
152 if (!ta.ParseTraceDataSegment(std::move(buf), static_cast<size_t>(rsize))) {
153 return false;
154 };
155 printf("\rLoadingFile:\t%.2f MB\r", static_cast<double>(g_loadSize) / 1E6);
156 }
157 ta.WaitForParserEnd();
158 auto endTime =
159 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
160 .count();
161 (void)fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
162 (void)fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3));
163 return true;
164 }
OpenAndParserFile(TraceStreamerSelector & ts,const std::string & traceFilePath)165 int OpenAndParserFile(TraceStreamerSelector& ts, const std::string& traceFilePath)
166 {
167 int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION));
168 if (fd < 0) {
169 TS_LOGE("%s does not exist", traceFilePath.c_str());
170 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
171 return 1;
172 }
173 if (!ReadAndParser(ts, fd)) {
174 close(fd);
175 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
176 return 1;
177 }
178 MetaData* metaData = ts.GetMetaData();
179
180 std::string fileNameTmp = traceFilePath;
181 #ifdef _WIN32
182 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
183 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
184 }
185 #endif
186 metaData->SetSourceFileName(fileNameTmp);
187 metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace");
188
189 close(fd);
190 return 0;
191 }
ExportDatabase(TraceStreamerSelector & ts,const std::string & sqliteFilePath)192 int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath)
193 {
194 auto startTime =
195 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
196 .count();
197 if (!sqliteFilePath.empty()) {
198 MetaData* metaData = ts.GetMetaData();
199 std::string fileNameTmp = sqliteFilePath;
200 #ifdef _WIN32
201 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
202 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
203 }
204 #endif
205 metaData->SetOutputFileName(fileNameTmp);
206 metaData->SetParserToolVersion(g_traceStreamerVersion);
207 metaData->SetParserToolPublishDateTime(g_traceStreamerPublishVersion);
208 metaData->SetTraceDataSize(g_loadSize);
209 fprintf(stdout, "ExportDatabase begin...\n");
210 if (ts.ExportDatabase(sqliteFilePath)) {
211 fprintf(stdout, "ExportDatabase failed\n");
212 ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL);
213 return 1;
214 }
215 fprintf(stdout, "ExportDatabase end\n");
216 }
217 auto endTime =
218 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
219 .count();
220 endTime += 1; // for any exception of endTime == startTime
221 fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
222 fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3);
223 return 0;
224 }
225
226 struct TraceExportOption {
227 std::string traceFilePath;
228 std::string sqliteFilePath;
229 std::string sqlOperatorFilePath;
230 bool interactiveState = false;
231 bool exportMetaTable = true;
232 bool separateFile = false;
233 };
234 struct HttpOption {
235 bool enable = false;
236 int port = 9001;
237 };
CheckFinal(char ** argv,TraceExportOption & traceExportOption,HttpOption & httpOption)238 int CheckFinal(char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption)
239 {
240 if ((traceExportOption.traceFilePath.empty() ||
241 (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) &&
242 !httpOption.enable && !traceExportOption.separateFile && traceExportOption.sqlOperatorFilePath.empty()) {
243 ShowHelpInfo(argv[0]);
244 return 1;
245 }
246 return 0;
247 }
CheckArgs(int argc,char ** argv,TraceExportOption & traceExportOption,HttpOption & httpOption)248 int CheckArgs(int argc, char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption)
249 {
250 for (int i = 1; i < argc; i++) {
251 if (!strcmp(argv[i], "-e")) {
252 i++;
253 if (i == argc) {
254 ShowHelpInfo(argv[0]);
255 return 1;
256 }
257 traceExportOption.sqliteFilePath = std::string(argv[i]);
258 continue;
259 } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) {
260 traceExportOption.interactiveState = true;
261 continue;
262 } else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--query-file")) {
263 i++;
264 if (i == argc) {
265 ShowHelpInfo(argv[0]);
266 return 1;
267 }
268 traceExportOption.sqlOperatorFilePath = std::string(argv[i]);
269 continue;
270 } else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) {
271 PrintInformation();
272 } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--s")) {
273 traceExportOption.separateFile = true;
274 continue;
275 } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) {
276 traceExportOption.exportMetaTable = false;
277 continue;
278 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--v") || !strcmp(argv[i], "-version") ||
279 !strcmp(argv[i], "--version")) {
280 PrintVersion();
281 return 1;
282 } else if (!strcmp(argv[i], "-h")) {
283 httpOption.enable = true;
284 continue;
285 } else if (!strcmp(argv[i], "-p")) {
286 if (++i == argc) {
287 ShowHelpInfo(argv[0]);
288 return 1;
289 }
290 httpOption.port = std::stoi(argv[i]);
291 continue;
292 }
293 traceExportOption.traceFilePath = std::string(argv[i]);
294 }
295 return CheckFinal(argv, traceExportOption, httpOption);
296 }
297 } // namespace TraceStreamer
298 } // namespace SysTuning
main(int argc,char ** argv)299 int main(int argc, char** argv)
300 {
301 if (argc < G_MIN_PARAM_NUM) {
302 ShowHelpInfo(argv[0]);
303 return 1;
304 }
305 TraceExportOption tsOption;
306 HttpOption httpOption;
307 int ret = CheckArgs(argc, argv, tsOption, httpOption);
308 if (ret) {
309 if (!tsOption.sqliteFilePath.empty()) {
310 ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
311 }
312 return 0;
313 }
314 if (httpOption.enable) {
315 RpcServer rpcServer;
316 HttpServer httpServer;
317 httpServer.RegisterRpcFunction(&rpcServer);
318 httpServer.Run(httpOption.port);
319 return 0;
320 }
321 TraceStreamerSelector ts;
322 ts.EnableMetaTable(tsOption.exportMetaTable);
323 ts.EnableFileSave(tsOption.separateFile);
324 if (OpenAndParserFile(ts, tsOption.traceFilePath)) {
325 if (!tsOption.sqliteFilePath.empty()) {
326 ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
327 }
328 return 1;
329 }
330 if (tsOption.interactiveState) {
331 MetaData* metaData = ts.GetMetaData();
332 metaData->SetOutputFileName("command line mode");
333 metaData->SetParserToolVersion(g_traceStreamerVersion.c_str());
334 metaData->SetParserToolPublishDateTime(g_traceStreamerPublishVersion.c_str());
335 metaData->SetTraceDataSize(g_loadSize);
336 while (1) {
337 auto values = ts.SearchData();
338 std::string symbolsPath = "default";
339 if (!values.empty()) {
340 ts.ReloadSymbolFiles(symbolsPath, values);
341 } else {
342 return 0;
343 }
344 }
345 }
346 if (!tsOption.sqliteFilePath.empty()) {
347 if (ExportDatabase(ts, tsOption.sqliteFilePath)) {
348 ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
349 return 1;
350 }
351 if (!tsOption.sqliteFilePath.empty()) {
352 ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
353 }
354 }
355 if (!tsOption.sqlOperatorFilePath.empty()) {
356 ReadSqlFileAndPrintResult(ts, tsOption.sqlOperatorFilePath);
357 }
358 return 0;
359 }
360