/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "codec_cov.h" #include "file.h" #include "filter/slice_filter.h" #include "http_server.h" #include "log.h" #include "meta.h" #include "parser/bytrace_parser/bytrace_event_parser.h" #include "parser/bytrace_parser/bytrace_parser.h" #include "parting_string.h" #include "rpc_server.h" #include "thread_state.h" #include "trace_streamer/trace_streamer_selector.h" #include "trace_streamer_filters.h" using namespace SysTuning::TraceStreamer; using namespace SysTuning; namespace SysTuning { namespace TraceStreamer { using namespace SysTuning::TraceStreamer; using namespace SysTuning::base; constexpr size_t G_CHUNK_SIZE = 1024 * 1024; constexpr int G_MIN_PARAM_NUM = 2; constexpr size_t G_FILE_PERMISSION = 664; // set version info in meta.cpp please void ExportStatusToLog(const std::string& dbPath, TraceParserStatus status) { std::string path = dbPath + ".ohos.ts"; std::ofstream out(path, std::ios_base::trunc); out << (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) .count() << ":" << status << std::endl; using std::chrono::system_clock; system_clock::time_point today = system_clock::now(); std::time_t tt = system_clock::to_time_t(today); out << "last running time is: " << ctime(&tt); out << "last running status is: " << status; out.close(); } void ShowHelpInfo(const char* argv) { TS_LOGI( "trace analyze tool, it can transfer a bytrace/htrace file into a " "SQLite database and save result to a local file trace_streamer.log.\n" "Usage: %s FILE -e sqlite_out.pb\n" " or %s FILE -c\n" "Options:\n" " -e transfer a bytrace file into a SQLiteBased DB. with -nm to except meta table\n" " -c command line mode.\n" " -h start HTTP server.\n" " -p Specify the port of HTTP server, default is 9001.\n" " -i show information.\n" " -v show version.", argv, argv); } void PrintInformation() { TraceStreamerConfig cfg; cfg.PrintInfo(); } void PrintVersion() { fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION.c_str()); } bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd) { auto startTime = (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) .count(); g_loadSize = 0; while (true) { std::unique_ptr buf = std::make_unique(G_CHUNK_SIZE); auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE); if (rsize == 0) { break; } if (rsize < 0) { TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno)); return false; } g_loadSize += rsize; if (!ta.ParseTraceDataSegment(std::move(buf), static_cast(rsize))) { return false; }; printf("\rLoadingFile:\t%.2f MB\r", static_cast(g_loadSize) / 1E6); } ta.WaitForParserEnd(); auto endTime = (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) .count(); fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast(endTime - startTime)); fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3)); return true; } int OpenAndParserFile(TraceStreamerSelector& ts, const std::string& traceFilePath) { int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION)); if (fd < 0) { TS_LOGE("%s does not exist", traceFilePath.c_str()); SetAnalysisResult(TRACE_PARSER_ABNORMAL); return 1; } if (!ReadAndParser(ts, fd)) { close(fd); SetAnalysisResult(TRACE_PARSER_ABNORMAL); return 1; } MetaData* metaData = ts.GetMetaData(); std::string fileNameTmp = traceFilePath; #ifdef _WIN32 if (!base::GetCoding(reinterpret_cast(fileNameTmp.c_str()), fileNameTmp.length())) { fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str()); } #endif metaData->SetSourceFileName(fileNameTmp); metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace"); close(fd); return 0; } int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath) { auto startTime = (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) .count(); if (!sqliteFilePath.empty()) { MetaData* metaData = ts.GetMetaData(); std::string fileNameTmp = sqliteFilePath; #ifdef _WIN32 if (!base::GetCoding(reinterpret_cast(fileNameTmp.c_str()), fileNameTmp.length())) { fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str()); } #endif metaData->SetOutputFileName(fileNameTmp); metaData->SetParserToolVersion(TRACE_STREAM_VERSION); metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION); metaData->SetTraceDataSize(g_loadSize); fprintf(stdout, "ExportDatabase begin...\n"); if (ts.ExportDatabase(sqliteFilePath)) { fprintf(stdout, "ExportDatabase failed\n"); ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL); return 1; } fprintf(stdout, "ExportDatabase end\n"); } auto endTime = (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) .count(); endTime += 1; // for any exception of endTime == startTime fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast(endTime - startTime)); fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3); return 0; } struct TraceExportOption { std::string traceFilePath; std::string sqliteFilePath; bool interactiveState = false; bool exportMetaTable = true; }; struct HttpOption { bool enable = false; int port = 9001; }; int CheckArgs(int argc, char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption) { for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-e")) { i++; if (i == argc) { ShowHelpInfo(argv[0]); return 1; } traceExportOption.sqliteFilePath = std::string(argv[i]); continue; } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) { traceExportOption.interactiveState = true; continue; } else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) { PrintInformation(); } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) { traceExportOption.exportMetaTable = false; continue; } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--v") || !strcmp(argv[i], "-version") || !strcmp(argv[i], "--version")) { PrintVersion(); return 1; } else if (!strcmp(argv[i], "-h")) { httpOption.enable = true; continue; } else if (!strcmp(argv[i], "-p")) { if (++i == argc) { ShowHelpInfo(argv[0]); return 1; } httpOption.port = std::stoi(argv[i]); continue; } traceExportOption.traceFilePath = std::string(argv[i]); } if ((traceExportOption.traceFilePath.empty() || (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) && !httpOption.enable) { ShowHelpInfo(argv[0]); return 1; } return 0; } } // namespace TraceStreamer } // namespace SysTuning int main(int argc, char** argv) { if (argc < G_MIN_PARAM_NUM) { ShowHelpInfo(argv[0]); return 1; } TraceExportOption tsOption; HttpOption httpOption; int ret = CheckArgs(argc, argv, tsOption, httpOption); if (ret) { if (!tsOption.sqliteFilePath.empty()) { ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 0; } if (httpOption.enable) { RpcServer rpcServer; HttpServer httpServer; httpServer.RegisterRpcFunction(&rpcServer); httpServer.Run(httpOption.port); return 0; } TraceStreamerSelector ts; ts.EnableMetaTable(tsOption.exportMetaTable); if (OpenAndParserFile(ts, tsOption.traceFilePath)) { if (!tsOption.sqliteFilePath.empty()) { ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 1; } if (tsOption.interactiveState) { MetaData* metaData = ts.GetMetaData(); metaData->SetOutputFileName("command line mode"); metaData->SetParserToolVersion(TRACE_STREAM_VERSION.c_str()); metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION.c_str()); metaData->SetTraceDataSize(g_loadSize); ts.SearchData(); return 0; } if (ExportDatabase(ts, tsOption.sqliteFilePath)) { ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); return 1; } if (!tsOption.sqliteFilePath.empty()) { ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 0; }