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