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