• 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 
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 "meta.h"
32 #include "parser/bytrace_parser/bytrace_event_parser.h"
33 #include "parser/bytrace_parser/bytrace_parser.h"
34 #include "parting_string.h"
35 #include "rpc_server.h"
36 
37 #include "thread_state.h"
38 #include "trace_streamer/trace_streamer_selector.h"
39 #include "trace_streamer_filters.h"
40 using namespace SysTuning::TraceStreamer;
41 using namespace SysTuning;
42 namespace SysTuning {
43 namespace TraceStreamer {
44 using namespace SysTuning::TraceStreamer;
45 using namespace SysTuning::base;
46 constexpr size_t G_CHUNK_SIZE = 1024 * 1024;
47 constexpr int G_MIN_PARAM_NUM = 2;
48 constexpr size_t G_FILE_PERMISSION = 664;
49 // set version info in meta.cpp please
ExportStatusToLog(const std::string & dbPath,TraceParserStatus status)50 void ExportStatusToLog(const std::string& dbPath, TraceParserStatus status)
51 {
52     std::string path = dbPath + ".ohos.ts";
53     std::ofstream out(path, std::ios_base::trunc);
54     out << (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
55         .count()
56         << ":" << status << std::endl;
57     using std::chrono::system_clock;
58 
59     system_clock::time_point today = system_clock::now();
60 
61     std::time_t tt = system_clock::to_time_t(today);
62     out << "last running  time  is: " << ctime(&tt);
63     out << "last running status is: " << status;
64     out.close();
65 }
ShowHelpInfo(const char * argv)66 void ShowHelpInfo(const char* argv)
67 {
68     TS_LOGI(
69         "trace analyze tool, it can transfer a bytrace/htrace file into a "
70         "SQLite database and save result to a local file trace_streamer.log.\n"
71         "Usage: %s FILE -e sqlite_out.pb\n"
72         " or    %s FILE -c\n"
73         "Options:\n"
74         " -e    transfer a bytrace file into a SQLiteBased DB. with -nm to except meta table\n"
75         " -c    command line mode.\n"
76         " -h    start HTTP server.\n"
77         " -p    Specify the port of HTTP server, default is 9001.\n"
78         " -i    show information.\n"
79         " -v    show version.",
80         argv, argv);
81 }
PrintInformation()82 void PrintInformation()
83 {
84     TraceStreamerConfig cfg;
85     cfg.PrintInfo();
86 }
PrintVersion()87 void PrintVersion()
88 {
89     fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION.c_str());
90 }
91 
ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector & ta,int fd)92 bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd)
93 {
94     auto startTime =
95         (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
96             .count();
97     g_loadSize = 0;
98     while (true) {
99         std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(G_CHUNK_SIZE);
100         auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE);
101         if (rsize == 0) {
102             break;
103         }
104 
105         if (rsize < 0) {
106             TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
107             return false;
108         }
109         g_loadSize += rsize;
110         if (!ta.ParseTraceDataSegment(std::move(buf), static_cast<size_t>(rsize))) {
111             return false;
112         };
113         printf("\rLoadingFile:\t%.2f MB\r", static_cast<double>(g_loadSize) / 1E6);
114     }
115     ta.WaitForParserEnd();
116     auto endTime =
117         (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
118             .count();
119     fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
120     fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3));
121     return true;
122 }
OpenAndParserFile(TraceStreamerSelector & ts,const std::string & traceFilePath)123 int OpenAndParserFile(TraceStreamerSelector& ts, const std::string& traceFilePath)
124 {
125     int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION));
126     if (fd < 0) {
127         TS_LOGE("%s does not exist", traceFilePath.c_str());
128         SetAnalysisResult(TRACE_PARSER_ABNORMAL);
129         return 1;
130     }
131     if (!ReadAndParser(ts, fd)) {
132         close(fd);
133         SetAnalysisResult(TRACE_PARSER_ABNORMAL);
134         return 1;
135     }
136     MetaData* metaData = ts.GetMetaData();
137 
138     std::string fileNameTmp = traceFilePath;
139 #ifdef _WIN32
140     if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
141         fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
142     }
143 #endif
144     metaData->SetSourceFileName(fileNameTmp);
145     metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace");
146 
147     close(fd);
148     return 0;
149 }
ExportDatabase(TraceStreamerSelector & ts,const std::string & sqliteFilePath)150 int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath)
151 {
152     auto startTime =
153         (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
154             .count();
155     if (!sqliteFilePath.empty()) {
156         MetaData* metaData = ts.GetMetaData();
157         std::string fileNameTmp = sqliteFilePath;
158 #ifdef _WIN32
159         if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
160             fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
161         }
162 #endif
163         metaData->SetOutputFileName(fileNameTmp);
164         metaData->SetParserToolVersion(TRACE_STREAM_VERSION);
165         metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION);
166         metaData->SetTraceDataSize(g_loadSize);
167         fprintf(stdout, "ExportDatabase begin...\n");
168         if (ts.ExportDatabase(sqliteFilePath)) {
169             fprintf(stdout, "ExportDatabase failed\n");
170             ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL);
171             return 1;
172         }
173         fprintf(stdout, "ExportDatabase end\n");
174     }
175     auto endTime =
176         (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
177             .count();
178     endTime += 1; // for any exception of endTime == startTime
179     fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
180     fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3);
181     return 0;
182 }
183 
184 struct TraceExportOption {
185     std::string traceFilePath;
186     std::string sqliteFilePath;
187     bool interactiveState = false;
188     bool exportMetaTable = true;
189 };
190 struct HttpOption {
191     bool enable = false;
192     int port = 9001;
193 };
194 
CheckArgs(int argc,char ** argv,TraceExportOption & traceExportOption,HttpOption & httpOption)195 int CheckArgs(int argc, char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption)
196 {
197     for (int i = 1; i < argc; i++) {
198         if (!strcmp(argv[i], "-e")) {
199             i++;
200             if (i == argc) {
201                 ShowHelpInfo(argv[0]);
202                 return 1;
203             }
204             traceExportOption.sqliteFilePath = std::string(argv[i]);
205             continue;
206         } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) {
207             traceExportOption.interactiveState = true;
208             continue;
209         } else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) {
210             PrintInformation();
211         } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) {
212             traceExportOption.exportMetaTable = false;
213             continue;
214         } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--v") || !strcmp(argv[i], "-version") ||
215                    !strcmp(argv[i], "--version")) {
216             PrintVersion();
217             return 1;
218         } else if (!strcmp(argv[i], "-h")) {
219             httpOption.enable = true;
220             continue;
221         } else if (!strcmp(argv[i], "-p")) {
222             if (++i == argc) {
223                 ShowHelpInfo(argv[0]);
224                 return 1;
225             }
226             httpOption.port = std::stoi(argv[i]);
227             continue;
228         }
229         traceExportOption.traceFilePath = std::string(argv[i]);
230     }
231     if ((traceExportOption.traceFilePath.empty() ||
232          (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) &&
233         !httpOption.enable) {
234         ShowHelpInfo(argv[0]);
235         return 1;
236     }
237     return 0;
238 }
239 } // namespace TraceStreamer
240 } // namespace SysTuning
main(int argc,char ** argv)241 int main(int argc, char** argv)
242 {
243     if (argc < G_MIN_PARAM_NUM) {
244         ShowHelpInfo(argv[0]);
245         return 1;
246     }
247     TraceExportOption tsOption;
248     HttpOption httpOption;
249     int ret = CheckArgs(argc, argv, tsOption, httpOption);
250     if (ret) {
251         if (!tsOption.sqliteFilePath.empty()) {
252             ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
253         }
254         return 0;
255     }
256 
257     if (httpOption.enable) {
258         RpcServer rpcServer;
259         HttpServer httpServer;
260         httpServer.RegisterRpcFunction(&rpcServer);
261         httpServer.Run(httpOption.port);
262         return 0;
263     }
264     TraceStreamerSelector ts;
265     ts.EnableMetaTable(tsOption.exportMetaTable);
266     if (OpenAndParserFile(ts, tsOption.traceFilePath)) {
267         if (!tsOption.sqliteFilePath.empty()) {
268             ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
269         }
270         return 1;
271     }
272     if (tsOption.interactiveState) {
273         MetaData* metaData = ts.GetMetaData();
274         metaData->SetOutputFileName("command line mode");
275         metaData->SetParserToolVersion(TRACE_STREAM_VERSION.c_str());
276         metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION.c_str());
277         metaData->SetTraceDataSize(g_loadSize);
278         ts.SearchData();
279         return 0;
280     }
281     if (ExportDatabase(ts, tsOption.sqliteFilePath)) {
282         ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
283         return 1;
284     }
285     if (!tsOption.sqliteFilePath.empty()) {
286         ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult());
287     }
288     return 0;
289 }
290