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