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