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 "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
36 #include "thread_state.h"
37 #include "trace_streamer/trace_streamer_selector.h"
38 #include "trace_streamer_filters.h"
39 using namespace SysTuning::TraceStreamer;
40 using namespace SysTuning;
41 namespace SysTuning {
42 namespace TraceStreamer {
43 using namespace SysTuning::TraceStreamer;
44 using namespace SysTuning::base;
45 constexpr size_t G_CHUNK_SIZE = 1024 * 1024;
46 constexpr int G_MIN_PARAM_NUM = 2;
47 constexpr size_t G_FILE_PERMISSION = 664;
48 size_t g_loadSize = 0;
49 const char* TRACE_STREAM_VERSION = "2.3.118"; // version
50 const char* TRACE_STREAM_PUBLISHVERSION = "2022/3/29"; // publish datetime
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 " -p Specify the port of HTTP server, default is 9001.\n"
79 " -i show information.\n"
80 " -v show version.",
81 argv, argv);
82 }
PrintInformation()83 void PrintInformation()
84 {
85 TraceStreamerConfig cfg;
86 cfg.PrintInfo();
87 }
PrintVersion()88 void PrintVersion()
89 {
90 fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION);
91 }
92
ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector & ta,int fd)93 bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd)
94 {
95 auto startTime =
96 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
97 .count();
98 g_loadSize = 0;
99 while (true) {
100 std::unique_ptr<uint8_t[]> buf = std::make_unique<uint8_t[]>(G_CHUNK_SIZE);
101 auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE);
102 if (rsize == 0) {
103 break;
104 }
105
106 if (rsize < 0) {
107 TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
108 return false;
109 }
110 g_loadSize += rsize;
111 if (!ta.ParseTraceDataSegment(std::move(buf), static_cast<size_t>(rsize))) {
112 return false;
113 };
114 printf("\rLoadingFile:\t%.2f MB\r", static_cast<double>(g_loadSize) / 1E6);
115 }
116 ta.WaitForParserEnd();
117 auto endTime =
118 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
119 .count();
120 fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
121 fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3));
122 return true;
123 }
OpenAndParserFile(TraceStreamerSelector & ts,const std::string & traceFilePath)124 int OpenAndParserFile(TraceStreamerSelector& ts, const std::string& traceFilePath)
125 {
126 int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION));
127 if (fd < 0) {
128 TS_LOGE("%s does not exist", traceFilePath.c_str());
129 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
130 return 1;
131 }
132 if (!ReadAndParser(ts, fd)) {
133 close(fd);
134 SetAnalysisResult(TRACE_PARSER_ABNORMAL);
135 return 1;
136 }
137 MetaData* metaData = ts.GetMetaData();
138
139 std::string fileNameTmp = traceFilePath;
140 #ifdef _WIN32
141 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
142 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
143 }
144 #endif
145 metaData->SetSourceFileName(fileNameTmp);
146 metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace");
147
148 close(fd);
149 return 0;
150 }
ExportDatabase(TraceStreamerSelector & ts,const std::string & sqliteFilePath)151 int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath)
152 {
153 auto startTime =
154 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
155 .count();
156 if (!sqliteFilePath.empty()) {
157 MetaData* metaData = ts.GetMetaData();
158 std::string fileNameTmp = sqliteFilePath;
159 #ifdef _WIN32
160 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(fileNameTmp.c_str()), fileNameTmp.length())) {
161 fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str());
162 }
163 #endif
164 metaData->SetOutputFileName(fileNameTmp);
165 metaData->SetParserToolVersion(TRACE_STREAM_VERSION);
166 metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION);
167 metaData->SetTraceDataSize(g_loadSize);
168 fprintf(stdout, "ExportDatabase begin...\n");
169 if (ts.ExportDatabase(sqliteFilePath)) {
170 fprintf(stdout, "ExportDatabase failed\n");
171 ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL);
172 return 1;
173 }
174 fprintf(stdout, "ExportDatabase end\n");
175 }
176 auto endTime =
177 (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
178 .count();
179 endTime += 1; // for any exception of endTime == startTime
180 fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast<unsigned int>(endTime - startTime));
181 fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3);
182 return 0;
183 }
184
185 struct HttpOption {
186 bool enable = false;
187 int port = 9001;
188 };
189
CheckArgs(int argc,char ** argv,bool & interactiveState,bool & exportMetaTable,std::string & traceFilePath,std::string & sqliteFilePath,HttpOption & httpOption)190 int CheckArgs(int argc,
191 char** argv,
192 bool& interactiveState,
193 bool& exportMetaTable,
194 std::string& traceFilePath,
195 std::string& sqliteFilePath,
196 HttpOption& httpOption)
197 {
198 for (int i = 1; i < argc; i++) {
199 if (!strcmp(argv[i], "-e")) {
200 if (++i == argc) {
201 ShowHelpInfo(argv[0]);
202 return 1;
203 }
204 sqliteFilePath = std::string(argv[i]);
205 continue;
206 } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) {
207 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 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 traceFilePath = std::string(argv[i]);
230 }
231 if ((traceFilePath.empty() || (!interactiveState && sqliteFilePath.empty()))
232 && !httpOption.enable) {
233 ShowHelpInfo(argv[0]);
234 return 1;
235 }
236 return 0;
237 }
238 } // namespace TraceStreamer
239 } // namespace SysTuning
240
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 std::string traceFilePath;
248 std::string sqliteFilePath;
249 bool interactiveState = false;
250 bool exportMetaTable = true;
251 HttpOption httpOption;
252 int ret = CheckArgs(argc, argv, interactiveState, exportMetaTable, traceFilePath, sqliteFilePath, httpOption);
253 if (ret) {
254 if (!sqliteFilePath.empty()) {
255 ExportStatusToLog(sqliteFilePath, GetAnalysisResult());
256 }
257 return 0;
258 }
259
260 if (httpOption.enable) {
261 RpcServer rpcServer;
262 HttpServer httpServer;
263 httpServer.RegisterRpcFunction(&rpcServer);
264 httpServer.Run(httpOption.port);
265 return 0;
266 }
267 TraceStreamerSelector ts;
268 ts.EnableMetaTable(exportMetaTable);
269 if (OpenAndParserFile(ts, traceFilePath)) {
270 if (!sqliteFilePath.empty()) {
271 ExportStatusToLog(sqliteFilePath, GetAnalysisResult());
272 }
273 return 1;
274 }
275 if (interactiveState) {
276 ts.SearchData();
277 return 0;
278 }
279 if (ExportDatabase(ts, sqliteFilePath)) {
280 ExportStatusToLog(sqliteFilePath, GetAnalysisResult());
281 return 1;
282 }
283 if (!sqliteFilePath.empty()) {
284 ExportStatusToLog(sqliteFilePath, GetAnalysisResult());
285 }
286 return 0;
287 }
288