1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. 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 <dirent.h>
16 #include <fcntl.h>
17 #include <fstream>
18 #include <iostream>
19 #include <memory>
20 #include <regex>
21 #include <sys/stat.h>
22 #include <unistd.h>
23
24 #include "codec_cov.h"
25 #include "file.h"
26 #include "cpu_filter.h"
27 #include "frame_filter.h"
28 #include "slice_filter.h"
29 #include "string_help.h"
30
31 #include "trace_streamer_selector.h"
32 #include "version.h"
33 using namespace SysTuning::TraceStreamer;
34 using namespace SysTuning;
35 namespace SysTuning {
36 namespace TraceStreamer {
37 using namespace SysTuning::TraceStreamer;
38 using namespace SysTuning::base;
39 constexpr int G_MIN_PARAM_NUM = 2;
40 constexpr size_t G_FILE_PERMISSION = 664;
41 constexpr uint8_t RAW_TRACE_PARSE_MAX = 2;
42 constexpr uint8_t PARSER_THREAD_MAX = 16;
43 constexpr uint8_t PARSER_THREAD_MIN = 1;
44 std::regex traceInvalidStr("\\\\");
45 // set version info in meta.cpp please
ExportStatusToLog(const std::string &dbPath, TraceParserStatus status)46 void ExportStatusToLog(const std::string &dbPath, TraceParserStatus status)
47 {
48 std::string path = dbPath + ".ohos.ts";
49 std::ofstream out(path, std::ios_base::trunc);
50 out << (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
51 .count()
52 << ":" << status << std::endl;
53 using std::chrono::system_clock;
54
55 system_clock::time_point today = system_clock::now();
56
57 std::time_t tt = system_clock::to_time_t(today);
58 out << "last running time is: " << ctime(&tt);
59 out << "last running status is: " << status;
60 out.close();
61 }
ShowHelpInfo(const char *argv)62 void ShowHelpInfo(const char *argv)
63 {
64 std::string dumpReadableTextPluginName;
65 #ifdef ENABLE_NATIVE_HOOK
66 dumpReadableTextPluginName.append("hook.");
67 #endif
68 #ifdef ENABLE_HIPERF
69 dumpReadableTextPluginName.append("perf.");
70 #endif
71 #ifdef ENABLE_EBPF
72 dumpReadableTextPluginName.append("ebpf.");
73 #endif
74 printf(
75 "trace analyze tool, it can transfer a bytrace/htrace file into a "
76 "SQLite database and save result to a local file trace_streamer.log.\n"
77 "Usage: %s FILE -e sqlite_out.db\n"
78 " or %s FILE -c\n"
79 "Options:\n"
80 " -e transfer a trace file into a SQLiteBased DB. with -nm to except meta table\n"
81 " -c command line mode.\n"
82 " -D Specify the directory path with multiple long trace files\n"
83 " -d dump '%s' readable text.Default dump file path is src path name + `_ReadableText.txt`\n"
84 " -l <level>, --level=<level>\n"
85 " Show specific level/levels logs with format: level1,level2,level3\n"
86 " Long level string coule be: DEBUG/INFO/WARN/ERROR/FATAL/OFF.\n"
87 " Short level string coule be: D/I/W/E/F/O.\n"
88 " Default level is OFF.\n"
89 " --list Show the support and disable ability.\n"
90 " -lnc long trace no clear the db cache.\n"
91 " -o set dump file path.\n"
92 " -s separate arkts-plugin data, and save it in current dir with default filename.\n"
93 " -q select sql from file.\n"
94 " -m Perform operations that query metrics through linux,supports querying multiple metrics items.For "
95 "example:-m x,y,z.\n"
96 " -tn <num> set parser thread num, min is 1, max is 16.\n"
97 " -nt close muti thread.\n"
98 " -i show information.\n"
99 " -v show version.\n",
100 argv, argv, dumpReadableTextPluginName.empty() ? "null" : dumpReadableTextPluginName.data());
101 }
PrintInformation()102 void PrintInformation()
103 {
104 TraceStreamerConfig cfg;
105 cfg.PrintInfo();
106 }
PrintVersion()107 void PrintVersion()
108 {
109 (void)fprintf(stderr, "version %s\n", TRACE_STREAMER_VERSION.c_str());
110 }
SetFtracePluginsAbilityInfo(std::string &disableInfo, std::string &enableInfo)111 void SetFtracePluginsAbilityInfo(std::string &disableInfo, std::string &enableInfo)
112 {
113 #ifndef ENABLE_BYTRACE
114 disableInfo.append("\n\tbytrace");
115 #else
116 enableInfo.append("\n\tbytrace");
117 #endif
118 #ifndef ENABLE_RAWTRACE
119 disableInfo.append("\n\trawtrace");
120 #else
121 enableInfo.append("\n\trawtrace");
122 #endif
123 #ifndef ENABLE_HTRACE
124 disableInfo.append("\n\thtrace");
125 #else
126 enableInfo.append("\n\thtrace");
127 #endif
128 #ifndef ENABLE_FFRT
129 disableInfo.append("\n\tffrt");
130 #else
131 enableInfo.append("\n\tffrt");
132 #endif
133 }
PrintDefaultAbilityInfo(std::string &disableInfo, std::string &enableInfo)134 void PrintDefaultAbilityInfo(std::string &disableInfo, std::string &enableInfo)
135 {
136 SetFtracePluginsAbilityInfo(disableInfo, enableInfo);
137 #ifndef ENABLE_MEMORY
138 disableInfo.append("\n\tmemory");
139 #else
140 enableInfo.append("\n\tmemory");
141 #endif
142 #ifndef ENABLE_HTDUMP
143 disableInfo.append("\n\thidump");
144 #else
145 enableInfo.append("\n\thidump");
146 #endif
147 #ifndef ENABLE_CPUDATA
148 disableInfo.append("\n\tcpudata");
149 #else
150 enableInfo.append("\n\tcpudata");
151 #endif
152 #ifndef ENABLE_NETWORK
153 disableInfo.append("\n\tnetwork");
154 #else
155 enableInfo.append("\n\tnetwork");
156 #endif
157 #ifndef ENABLE_DISKIO
158 disableInfo.append("\n\tdiskio");
159 #else
160 enableInfo.append("\n\tdiskio");
161 #endif
162 #ifndef ENABLE_PROCESS
163 disableInfo.append("\n\tprocess");
164 #else
165 enableInfo.append("\n\tprocess");
166 #endif
167 printf(
168 "the default support ability list:\n\thiperf,ebpf,native_hook,hilog,hisysevent,arkts\n\t"
169 "bytrace,rawtrace,htrace,ffrt,memory,hidump,cpudata,network,diskio,process\n");
170 }
PrintExtendAbilityInfo(std::string &disableInfo, std::string &enableInfo)171 void PrintExtendAbilityInfo(std::string &disableInfo, std::string &enableInfo)
172 {
173 #ifndef ENABLE_STREAM_EXTEND
174 disableInfo.append("\n\tstream_extend");
175 #else
176 enableInfo.append("\n\tstream_extend");
177 #endif
178 printf("the extend support ability list:\n\tstream_extend\n");
179 }
PrintAbilityInfo()180 void PrintAbilityInfo()
181 {
182 std::string disableInfo;
183 std::string enableInfo;
184 #ifndef ENABLE_HIPERF
185 disableInfo.append("\n\thiperf");
186 #else
187 enableInfo.append("\n\thiperf");
188 #endif
189 #ifndef ENABLE_EBPF
190 disableInfo.append("\n\tebpf");
191 #else
192 enableInfo.append("\n\tebpf");
193 #endif
194 #ifndef ENABLE_NATIVE_HOOK
195 disableInfo.append("\n\tnative_hook");
196 #else
197 enableInfo.append("\n\tnative_hook");
198 #endif
199 #ifndef ENABLE_HILOG
200 disableInfo.append("\n\thilog");
201 #else
202 enableInfo.append("\n\thilog");
203 #endif
204 #ifndef ENABLE_HISYSEVENT
205 disableInfo.append("\n\thisysevent");
206 #else
207 enableInfo.append("\n\thisysevent");
208 #endif
209 #ifndef ENABLE_ARKTS
210 disableInfo.append("\n\tarkts");
211 #else
212 enableInfo.append("\n\tarkts");
213 #endif
214 PrintDefaultAbilityInfo(disableInfo, enableInfo);
215 PrintExtendAbilityInfo(disableInfo, enableInfo);
216 printf("the enable ability list:%s\n", enableInfo.empty() ? "\n\tnull" : enableInfo.c_str());
217 printf("the disable ability list:%s\n", disableInfo.empty() ? "\n\tnull" : disableInfo.c_str());
218 }
ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector &ta, int fd)219 bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector &ta, int fd)
220 {
221 auto startTime =
222 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
223 .count();
224 auto isFinish = false;
225 g_loadSize = 0;
226 auto curParseCnt = 1;
227 while (true) {
228 // for rawtrace next parse.the first parse is for last comm data;
229 if (isFinish && ta.GetFileType() == TRACE_FILETYPE_RAW_TRACE && curParseCnt < RAW_TRACE_PARSE_MAX) {
230 ++curParseCnt;
231 isFinish = false;
232 g_loadSize = 0;
233 TS_CHECK_TRUE(lseek(fd, 0, SEEK_SET) != -1, false, "lseek error:%s", strerror(errno));
234 }
235 std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(G_CHUNK_SIZE);
236 auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE);
237 if (rsize == 0) {
238 break;
239 }
240
241 if (rsize < 0) {
242 TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
243 return false;
244 }
245 g_loadSize += rsize;
246 if (g_loadSize == g_fileSize) {
247 isFinish = true;
248 }
249 if (!ta.ParseTraceDataSegment(std::move(buf), static_cast<size_t>(rsize), false, isFinish)) {
250 return false;
251 };
252 printf("\rLoadingFile:\t%.2f MB\r", static_cast<double>(g_loadSize) / 1E6);
253 }
254 ta.WaitForParserEnd();
255 auto endTime =
256 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
257 .count();
258 (void)fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
259 (void)fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3));
260 return true;
261 }
SetFileSize(const std::string &traceFilePath)262 bool SetFileSize(const std::string &traceFilePath)
263 {
264 if (traceFilePath.empty()) {
265 g_fileSize = 0;
266 return false;
267 }
268 struct stat statBuff;
269 stat(traceFilePath.c_str(), &statBuff);
270 g_fileSize = statBuff.st_size;
271 return true;
272 }
OpenAndParserFile(TraceStreamerSelector &ts, const std::string &traceFilePath)273 int OpenAndParserFile(TraceStreamerSelector &ts, const std::string &traceFilePath)
274 {
275 std::string filePath = traceFilePath;
276 if (!UnZipFile(traceFilePath, filePath)) {
277 return 1;
278 }
279 if (!SetFileSize(filePath)) {
280 return 0;
281 }
282 int fd(OpenFile(filePath, O_RDONLY, G_FILE_PERMISSION));
283 if (fd < 0) {
284 TS_LOGE("%s does not exist", filePath.c_str());
285 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
286 return 1;
287 }
288 if (!ReadAndParser(ts, fd)) {
289 close(fd);
290 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
291 return 1;
292 }
293 MetaData *metaData = ts.GetMetaData();
294
295 std::string fileNameTmp = traceFilePath;
296 #ifdef _WIN32
297 if (!base::GetCoding(reinterpret_cast<const uint8_t *>(fileNameTmp.c_str()), fileNameTmp.length())) {
298 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
299 }
300 #endif
301 metaData->SetSourceFileName(fileNameTmp);
302 metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace");
303
304 close(fd);
305 return 0;
306 }
ExportDatabase(TraceStreamerSelector &ts, const std::string &sqliteFilePath)307 int ExportDatabase(TraceStreamerSelector &ts, const std::string &sqliteFilePath)
308 {
309 auto startTime =
310 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
311 .count();
312 if (!sqliteFilePath.empty()) {
313 MetaData *metaData = ts.GetMetaData();
314 std::string fileNameTmp = sqliteFilePath;
315 #ifdef _WIN32
316 if (!base::GetCoding(reinterpret_cast<const uint8_t *>(fileNameTmp.c_str()), fileNameTmp.length())) {
317 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
318 }
319 #endif
320 metaData->SetOutputFileName(fileNameTmp);
321 metaData->SetParserToolVersion(TRACE_STREAMER_VERSION);
322 metaData->SetParserToolPublishDateTime(TRACE_STREAMER_PUBLISH_VERSION);
323 metaData->SetTraceDataSize(g_loadSize);
324 if (ts.ExportDatabase(sqliteFilePath)) {
325 fprintf(stdout, "ExportDatabase failed\n");
326 ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL);
327 return 1;
328 }
329 }
330 auto endTime =
331 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
332 .count();
333 endTime += 1; // for any exception of endTime == startTime
334 (void)fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
335 (void)fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3);
336 return 0;
337 }
LongTraceExportDatabase(TraceStreamerSelector &ts, const std::string &sqliteFilePath)338 bool LongTraceExportDatabase(TraceStreamerSelector &ts, const std::string &sqliteFilePath)
339 {
340 if (!sqliteFilePath.empty()) {
341 std::string fileNameTmp = sqliteFilePath;
342 #ifdef _WIN32
343 if (!base::GetCoding(reinterpret_cast<const uint8_t *>(fileNameTmp.c_str()), fileNameTmp.length())) {
344 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
345 }
346 #endif
347 if (ts.BatchExportDatabase(sqliteFilePath)) {
348 fprintf(stdout, "ExportDatabase failed\n");
349 ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL);
350 return false;
351 }
352 }
353 return true;
354 }
355 enum DumpFileType { UNKONW_TYPE = 0, PERF_TYPE, NATIVE_HOOK_TYPE, EBPF_TYPE };
356 struct TraceExportOption {
357 std::string longTraceDir;
358 std::string traceFilePath;
359 std::string sqliteFilePath;
360 DumpFileType dumpFileType = DumpFileType::UNKONW_TYPE;
361 std::string outputFilePath;
362 std::string metricsIndex;
363 std::string sqlOperatorFilePath;
364 bool interactiveState = false;
365 bool exportMetaTable = true;
366 bool separateFile = false;
367 bool closeMutiThread = false;
368 uint8_t parserThreadNum = INVALID_UINT8;
369 bool needClearLongTraceCache = true;
370 std::string soFilesDir;
371 };
CheckFinal(char **argv, TraceExportOption &traceExportOption)372 bool CheckFinal(char **argv, TraceExportOption &traceExportOption)
373 {
374 if (((traceExportOption.traceFilePath.empty() && traceExportOption.longTraceDir.empty()) ||
375 (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) &&
376 !traceExportOption.separateFile && traceExportOption.metricsIndex.empty() &&
377 traceExportOption.sqlOperatorFilePath.empty() && traceExportOption.outputFilePath.empty() &&
378 traceExportOption.dumpFileType == DumpFileType::UNKONW_TYPE) {
379 ShowHelpInfo(argv[0]);
380 return false;
381 }
382 return true;
383 }
CheckArgc(int argc, char **argv, int curArgNum)384 bool CheckArgc(int argc, char **argv, int curArgNum)
385 {
386 if (curArgNum == argc) {
387 ShowHelpInfo(argv[0]);
388 return false;
389 }
390 return true;
391 }
CheckAndSetSoFilesPath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)392 bool CheckAndSetSoFilesPath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
393 {
394 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
395 traceExportOption.soFilesDir = std::string(argv[index]);
396 return true;
397 }
CheckAndSetLogLevel(int argc, char **argv, int &index)398 bool CheckAndSetLogLevel(int argc, char **argv, int &index)
399 {
400 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
401 if (SetLogLevel(std::string(argv[index]))) {
402 return true;
403 }
404 ShowHelpInfo(argv[0]);
405 return false;
406 }
CheckAndSetMetrics(TraceExportOption &traceExportOption, int argc, char **argv, int &index)407 bool CheckAndSetMetrics(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
408 {
409 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
410 traceExportOption.metricsIndex = std::string(argv[index]);
411 return true;
412 }
CheckAndSetThreadNum(TraceExportOption &traceExportOption, int argc, char **argv, int &index)413 bool CheckAndSetThreadNum(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
414 {
415 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
416 traceExportOption.parserThreadNum = std::stoi(argv[index]);
417 return true;
418 }
419
CheckAndSetSqlitePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)420 bool CheckAndSetSqlitePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
421 {
422 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
423 traceExportOption.sqliteFilePath = std::string(argv[index]);
424 return true;
425 }
CheckAndSetOutputFilePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)426 bool CheckAndSetOutputFilePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
427 {
428 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
429 traceExportOption.outputFilePath = std::string(argv[index]);
430 return true;
431 }
CheckAndSetSqlQueryFilePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)432 bool CheckAndSetSqlQueryFilePath(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
433 {
434 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
435 traceExportOption.sqlOperatorFilePath = std::string(argv[index]);
436 return true;
437 }
CheckAndSetDumpFileType(TraceExportOption &traceExportOption, int argc, char **argv, int &index)438 bool CheckAndSetDumpFileType(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
439 {
440 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
441 auto dumpFileType = std::string(argv[index]);
442 if (dumpFileType == "perf") {
443 #ifdef ENABLE_HIPERF
444 traceExportOption.dumpFileType = DumpFileType::PERF_TYPE;
445 #endif
446 } else if (dumpFileType == "hook") {
447 #ifdef ENABLE_NATIVE_HOOK
448 traceExportOption.dumpFileType = DumpFileType::NATIVE_HOOK_TYPE;
449 #endif
450 } else if (dumpFileType == "ebpf") {
451 #ifdef ENABLE_EBPF
452 traceExportOption.dumpFileType = DumpFileType::EBPF_TYPE;
453 #endif
454 }
455 if (traceExportOption.dumpFileType == DumpFileType::UNKONW_TYPE) {
456 ShowHelpInfo(argv[0]);
457 return false;
458 }
459 if (!traceExportOption.outputFilePath.empty()) {
460 auto strVec = SplitStringToVec(traceExportOption.traceFilePath, ".");
461 traceExportOption.outputFilePath = strVec.front() + "_ReadableText.txt";
462 }
463 return true;
464 }
CheckAndSetLongTraceDir(TraceExportOption &traceExportOption, int argc, char **argv, int &index)465 bool CheckAndSetLongTraceDir(TraceExportOption &traceExportOption, int argc, char **argv, int &index)
466 {
467 TS_CHECK_TRUE_RET(CheckArgc(argc, argv, ++index), false);
468 traceExportOption.longTraceDir = std::string(argv[index]);
469 return true;
470 }
ParseOtherArgs(int argc, char **argv, TraceExportOption &traceExportOption, int &i)471 bool ParseOtherArgs(int argc, char **argv, TraceExportOption &traceExportOption, int &i)
472 {
473 if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) {
474 PrintInformation();
475 i++;
476 } else if (!strcmp(argv[i], "-lnc")) {
477 traceExportOption.needClearLongTraceCache = false;
478 i++;
479 return true;
480 } else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--level")) {
481 TS_CHECK_TRUE_RET(CheckAndSetLogLevel(argc, argv, i), false);
482 i++;
483 return true;
484 } else if (!strcmp(argv[i], "--list")) {
485 PrintAbilityInfo();
486 i++;
487 return false;
488 } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--s")) {
489 traceExportOption.separateFile = true;
490 return true;
491 } else if (!strcmp(argv[i], "-tn") || !strcmp(argv[i], "--threadnum")) {
492 TS_CHECK_TRUE_RET(CheckAndSetThreadNum(traceExportOption, argc, argv, i), false);
493 i++;
494 return true;
495 } else if (!strcmp(argv[i], "-nt") || !strcmp(argv[i], "--nothreads")) {
496 traceExportOption.closeMutiThread = true;
497 i++;
498 return true;
499 } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) {
500 traceExportOption.exportMetaTable = false;
501 i++;
502 return true;
503 } else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--run-metrics")) {
504 TS_CHECK_TRUE_RET(CheckAndSetMetrics(traceExportOption, argc, argv, i), false);
505 i++;
506 return true;
507 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
508 PrintVersion();
509 i++;
510 return false;
511 }
512 traceExportOption.traceFilePath = std::string(argv[i]);
513 i++;
514 return true;
515 }
ParseArgs(int argc, char **argv, TraceExportOption &traceExportOption)516 bool ParseArgs(int argc, char **argv, TraceExportOption &traceExportOption)
517 {
518 int i = 1;
519 while (i < argc) {
520 if (!strcmp(argv[i], "-e")) {
521 TS_CHECK_TRUE_RET(CheckAndSetSqlitePath(traceExportOption, argc, argv, i), false);
522 i++;
523 continue;
524 } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) {
525 traceExportOption.interactiveState = true;
526 i++;
527 continue;
528 } else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--directory")) {
529 TS_CHECK_TRUE_RET(CheckAndSetLongTraceDir(traceExportOption, argc, argv, i), false);
530 i++;
531 continue;
532 } else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--dump")) {
533 TS_CHECK_TRUE_RET(CheckAndSetDumpFileType(traceExportOption, argc, argv, i), false);
534 i++;
535 continue;
536 } else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--query-file")) {
537 TS_CHECK_TRUE_RET(CheckAndSetSqlQueryFilePath(traceExportOption, argc, argv, i), false);
538 i++;
539 continue;
540 } else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--out")) {
541 TS_CHECK_TRUE_RET(CheckAndSetOutputFilePath(traceExportOption, argc, argv, i), false);
542 i++;
543 continue;
544 } else if (!strcmp(argv[i], "--So_dir")) {
545 TS_CHECK_TRUE_RET(CheckAndSetSoFilesPath(traceExportOption, argc, argv, i), false);
546 i++;
547 continue;
548 } else if (!ParseOtherArgs(argc, argv, traceExportOption, i)) {
549 return false;
550 }
551 }
552 return CheckFinal(argv, traceExportOption);
553 }
554
GetLongTraceFilePaths(const TraceExportOption &traceExportOption, std::map<int, std::string> &seqToFilePathMap)555 bool GetLongTraceFilePaths(const TraceExportOption &traceExportOption, std::map<int, std::string> &seqToFilePathMap)
556 {
557 std::regex traceInvalidStr("\\\\");
558 auto strEscape = std::regex_replace(traceExportOption.longTraceDir, traceInvalidStr, "\\\\\\\\");
559 DIR *dir = opendir(strEscape.c_str());
560 if (dir == nullptr) {
561 TS_LOGE("long trace dir is not exist or not dir");
562 return false;
563 }
564 dirent *entry;
565 while ((entry = readdir(dir)) != nullptr) {
566 std::regex pattern("^hiprofiler_data_(\\d{8})_(\\d{6})_(\\d+)\\.htrace$");
567 std::smatch matches;
568 std::string name = entry->d_name;
569 if (std::regex_match(name, matches, pattern)) {
570 std::string seqStr = matches[3].str();
571 int seq = std::stoi(seqStr);
572 std::string path = std::string(strEscape) + "/" + name;
573 seqToFilePathMap.insert({seq, path});
574 }
575 }
576 closedir(dir);
577 if (!seqToFilePathMap.size()) {
578 TS_LOGE("%s has no matched file!", strEscape.c_str());
579 return false;
580 }
581 auto seq = seqToFilePathMap.begin()->first;
582 for (auto itor = seqToFilePathMap.begin(); itor != seqToFilePathMap.end(); itor++) {
583 if (itor->first != seq++) {
584 seqToFilePathMap.erase(itor, seqToFilePathMap.end());
585 break;
586 }
587 }
588 return true;
589 }
590
ReadAndParserLongTrace(SysTuning::TraceStreamer::TraceStreamerSelector &ta, int fd, const std::string &traceFilePath)591 bool ReadAndParserLongTrace(SysTuning::TraceStreamer::TraceStreamerSelector &ta,
592 int fd,
593 const std::string &traceFilePath)
594 {
595 printf("Start Parse %s ...\n", traceFilePath.c_str());
596 g_loadSize = 0;
597 while (true) {
598 std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(G_CHUNK_SIZE);
599 auto rSize = Read(fd, buf.get(), G_CHUNK_SIZE);
600 if (rSize == 0) {
601 break;
602 }
603 if (rSize < 0) {
604 TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
605 return false;
606 }
607 g_loadSize += rSize;
608 if (!ta.BatchParseTraceDataSegment(std::move(buf), static_cast<size_t>(rSize))) {
609 return false;
610 }
611 printf("\rLoadingFile:\t%.2f MB\r", static_cast<double>(g_loadSize) / 1E6);
612 }
613 return true;
614 }
OpenAndParserLongTraceFile(TraceStreamerSelector &ts, const std::string &traceFilePath)615 bool OpenAndParserLongTraceFile(TraceStreamerSelector &ts, const std::string &traceFilePath)
616 {
617 if (!SetFileSize(traceFilePath)) {
618 return false;
619 }
620 int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION));
621 if (fd < 0) {
622 TS_LOGE("%s does not exist", traceFilePath.c_str());
623 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
624 return false;
625 }
626 if (!ReadAndParserLongTrace(ts, fd, traceFilePath)) {
627 close(fd);
628 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
629 return false;
630 }
631 close(fd);
632 return true;
633 }
ParseLongTrace(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)634 bool ParseLongTrace(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)
635 {
636 std::map<int, std::string> seqToFilePathMap;
637 TS_CHECK_TRUE(!traceExportOption.sqliteFilePath.empty(), false, "sqliteFilePath is empty");
638 TS_CHECK_TRUE(GetLongTraceFilePaths(traceExportOption, seqToFilePathMap), false, "GetLongTraceFilePaths err!");
639 ts.CreatEmptyBatchDB(traceExportOption.sqliteFilePath);
640 ts.GetTraceDataCache()->supportThread_ = false;
641 for (auto itor = seqToFilePathMap.begin(); itor != seqToFilePathMap.end(); itor++) {
642 if (!OpenAndParserLongTraceFile(ts, itor->second)) {
643 break;
644 }
645 if (itor == std::prev(seqToFilePathMap.end())) {
646 ts.WaitForParserEnd();
647 if (!traceExportOption.needClearLongTraceCache) {
648 TS_CHECK_TRUE(ExportDatabase(ts, traceExportOption.sqliteFilePath) == 0, false, "ExportDatabase Err!");
649 }
650 }
651 if (!traceExportOption.needClearLongTraceCache) {
652 continue;
653 }
654 ts.GetStreamFilter()->sliceFilter_->UpdateReadySize(); // for irq_
655 ts.GetStreamFilter()->frameFilter_->UpdateReadySize(); // for frameSliceRow_
656 ts.GetStreamFilter()->cpuFilter_->UpdateReadySize(); // for sched_slice
657 ts.GetTraceDataCache()->UpdateAllReadySize();
658 TS_CHECK_TRUE(LongTraceExportDatabase(ts, traceExportOption.sqliteFilePath), false,
659 "LongTraceExportDatabase Err!");
660 ts.GetTraceDataCache()->ClearAllExportedCacheData();
661 if (itor == std::prev(seqToFilePathMap.end())) {
662 ts.RevertTableName(traceExportOption.sqliteFilePath);
663 }
664 }
665 if (!traceExportOption.sqliteFilePath.empty()) {
666 ExportStatusToLog(traceExportOption.sqliteFilePath, GetAnalysisResult());
667 }
668 return true;
669 }
ExportReadableText(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)670 void ExportReadableText(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)
671 {
672 if (traceExportOption.dumpFileType == DumpFileType::PERF_TYPE) {
673 ts.ExportPerfReadableText(traceExportOption.outputFilePath);
674 } else if (traceExportOption.dumpFileType == DumpFileType::NATIVE_HOOK_TYPE) {
675 ts.ExportHookReadableText(traceExportOption.outputFilePath);
676 } else if (traceExportOption.dumpFileType == DumpFileType::EBPF_TYPE) {
677 ts.ExportEbpfReadableText(traceExportOption.outputFilePath);
678 }
679 }
CheckAndParseArgs(int argc, char **argv, TraceExportOption &traceExportOption)680 bool CheckAndParseArgs(int argc, char **argv, TraceExportOption &traceExportOption)
681 {
682 if (argc < G_MIN_PARAM_NUM) {
683 ShowHelpInfo(argv[0]);
684 return false;
685 }
686 int ret = ParseArgs(argc, argv, traceExportOption);
687 if (ret) {
688 if (!traceExportOption.sqliteFilePath.empty()) {
689 ExportStatusToLog(traceExportOption.sqliteFilePath, GetAnalysisResult());
690 }
691 return true;
692 }
693 return false;
694 }
EnterInteractiveState(TraceStreamerSelector &ts)695 bool EnterInteractiveState(TraceStreamerSelector &ts)
696 {
697 MetaData *metaData = ts.GetMetaData();
698 metaData->SetOutputFileName("command line mode");
699 metaData->SetParserToolVersion(TRACE_STREAMER_VERSION.c_str());
700 metaData->SetParserToolPublishDateTime(TRACE_STREAMER_PUBLISH_VERSION.c_str());
701 metaData->SetTraceDataSize(g_loadSize);
702 while (true) {
703 auto values = ts.SearchData();
704 if (!values.empty()) {
705 std::string symbolsPath = "default";
706 ts.ReloadSymbolFiles(symbolsPath, values);
707 } else {
708 return false;
709 }
710 }
711 }
Init(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)712 void Init(TraceStreamerSelector &ts, const TraceExportOption &traceExportOption)
713 {
714 ts.EnableMetaTable(traceExportOption.exportMetaTable);
715 ts.EnableFileSave(traceExportOption.separateFile);
716 if (traceExportOption.closeMutiThread) {
717 ts.GetTraceDataCache()->supportThread_ = false;
718 }
719 if (traceExportOption.parserThreadNum != INVALID_UINT8 && traceExportOption.parserThreadNum >= PARSER_THREAD_MIN &&
720 traceExportOption.parserThreadNum <= PARSER_THREAD_MAX) {
721 ts.GetTraceDataCache()->parserThreadNum_ = traceExportOption.parserThreadNum;
722 }
723 }
724
725 } // namespace TraceStreamer
726 } // namespace SysTuning
727
main(int argc, char **argv)728 int main(int argc, char **argv)
729 {
730 TraceExportOption traceExportOption;
731 TS_CHECK_TRUE_RET(CheckAndParseArgs(argc, argv, traceExportOption), 1);
732 TraceStreamerSelector ts;
733 Init(ts, traceExportOption);
734 #ifndef IS_WASM
735 if (!traceExportOption.longTraceDir.empty()) {
736 ParseLongTrace(ts, traceExportOption);
737 return 0;
738 }
739 #endif
740 auto strEscape = std::regex_replace(traceExportOption.traceFilePath, traceInvalidStr, "\\\\\\\\");
741 if (OpenAndParserFile(ts, strEscape)) {
742 if (!traceExportOption.sqliteFilePath.empty()) {
743 ExportStatusToLog(traceExportOption.sqliteFilePath, GetAnalysisResult());
744 }
745 return 1;
746 }
747 #if defined(is_linux) || defined(_WIN32)
748 if (!traceExportOption.soFilesDir.empty()) {
749 auto values = GetFilesNameFromDir(traceExportOption.soFilesDir);
750 ts.ReloadSymbolFiles(traceExportOption.soFilesDir, values);
751 }
752 #endif
753 if (traceExportOption.interactiveState) {
754 TS_CHECK_TRUE_RET(EnterInteractiveState(ts), 1);
755 }
756 if (traceExportOption.dumpFileType != DumpFileType::UNKONW_TYPE) {
757 ExportReadableText(ts, traceExportOption);
758 }
759 if (!traceExportOption.sqliteFilePath.empty()) {
760 if (ExportDatabase(ts, traceExportOption.sqliteFilePath)) {
761 ExportStatusToLog(traceExportOption.sqliteFilePath, GetAnalysisResult());
762 return 1;
763 }
764 ExportStatusToLog(traceExportOption.sqliteFilePath, GetAnalysisResult());
765 }
766 if (!traceExportOption.metricsIndex.empty()) {
767 MetaData *metaData = ts.GetMetaData();
768 metaData->SetOutputFileName("command line mode");
769 metaData->SetParserToolVersion(TRACE_STREAMER_VERSION.c_str());
770 metaData->SetParserToolPublishDateTime(TRACE_STREAMER_PUBLISH_VERSION.c_str());
771 metaData->SetTraceDataSize(g_loadSize);
772 ts.ParserAndPrintMetrics(traceExportOption.metricsIndex);
773 }
774 if (!traceExportOption.sqlOperatorFilePath.empty()) {
775 ts.ReadSqlFileAndPrintResult(traceExportOption.sqlOperatorFilePath);
776 }
777 return 0;
778 }
779