148f512ceSopenharmony_ci/* 248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 448f512ceSopenharmony_ci * you may not use this file except in compliance with the License. 548f512ceSopenharmony_ci * You may obtain a copy of the License at 648f512ceSopenharmony_ci * 748f512ceSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 848f512ceSopenharmony_ci * 948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and 1348f512ceSopenharmony_ci * limitations under the License. 1448f512ceSopenharmony_ci */ 1548f512ceSopenharmony_ci#define HILOG_TAG "Report" 1648f512ceSopenharmony_ci 1748f512ceSopenharmony_ci#include <set> 1848f512ceSopenharmony_ci#include "report_json_file.h" 1948f512ceSopenharmony_ci 2048f512ceSopenharmony_ci#if defined(is_mingw) && is_mingw 2148f512ceSopenharmony_ci#include <windows.h> 2248f512ceSopenharmony_ci#else 2348f512ceSopenharmony_ci#include <sys/ioctl.h> 2448f512ceSopenharmony_ci#endif 2548f512ceSopenharmony_ci 2648f512ceSopenharmony_ci#include "hiperf_hilog.h" 2748f512ceSopenharmony_ci 2848f512ceSopenharmony_cinamespace OHOS { 2948f512ceSopenharmony_cinamespace Developtools { 3048f512ceSopenharmony_cinamespace HiPerf { 3148f512ceSopenharmony_cibool ReportJsonFile::debug_ = false; 3248f512ceSopenharmony_ci 3348f512ceSopenharmony_civoid ReportJsonFile::AddNewFunction(int libId, std::string name) 3448f512ceSopenharmony_ci{ 3548f512ceSopenharmony_ci auto it = functionMap_.find(libId); 3648f512ceSopenharmony_ci if (it == functionMap_.end()) { 3748f512ceSopenharmony_ci it = functionMap_.try_emplace(libId).first; 3848f512ceSopenharmony_ci } 3948f512ceSopenharmony_ci it->second.insert_or_assign(name, ReportFuncMapItem(libId, name, functionId_++)); 4048f512ceSopenharmony_ci} 4148f512ceSopenharmony_ci 4248f512ceSopenharmony_civoid ReportJsonFile::OutputJsonFunctionMap(FILE *output) 4348f512ceSopenharmony_ci{ 4448f512ceSopenharmony_ci std::string key = "SymbolMap"; 4548f512ceSopenharmony_ci if (fprintf(output, "\"%s\":{", key.c_str()) != -1) { 4648f512ceSopenharmony_ci bool first = true; 4748f512ceSopenharmony_ci 4848f512ceSopenharmony_ci for (const auto& [libId, funcMap] : functionMap_) { 4948f512ceSopenharmony_ci for (const auto& [_, reportFuncMapItem] : funcMap) { 5048f512ceSopenharmony_ci OutputJsonPair(output, reportFuncMapItem.reportFuncId_, reportFuncMapItem, first); 5148f512ceSopenharmony_ci first = false; 5248f512ceSopenharmony_ci } 5348f512ceSopenharmony_ci } 5448f512ceSopenharmony_ci 5548f512ceSopenharmony_ci fprintf(output, "}"); 5648f512ceSopenharmony_ci } 5748f512ceSopenharmony_ci} 5848f512ceSopenharmony_ci 5948f512ceSopenharmony_civoid ReportJsonFile::ProcessSymbolsFiles( 6048f512ceSopenharmony_ci const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles) 6148f512ceSopenharmony_ci{ 6248f512ceSopenharmony_ci auto symbolsFileIt = symbolsFiles.begin(); 6348f512ceSopenharmony_ci while (symbolsFileIt != symbolsFiles.end()) { 6448f512ceSopenharmony_ci size_t libId = libList_.size(); 6548f512ceSopenharmony_ci libList_.emplace_back(symbolsFileIt->get()->filePath_); 6648f512ceSopenharmony_ci const auto &symbols = symbolsFileIt->get()->GetSymbols(); 6748f512ceSopenharmony_ci auto symbolIt = symbols.begin(); 6848f512ceSopenharmony_ci while (symbolIt != symbols.end()) { 6948f512ceSopenharmony_ci AddNewFunction(libId, std::string(symbolIt->GetName())); 7048f512ceSopenharmony_ci symbolIt++; 7148f512ceSopenharmony_ci } 7248f512ceSopenharmony_ci symbolsFileIt++; 7348f512ceSopenharmony_ci } 7448f512ceSopenharmony_ci} 7548f512ceSopenharmony_ci 7648f512ceSopenharmony_civoid ReportJsonFile::UpdateCallNodeEventCount() 7748f512ceSopenharmony_ci{ 7848f512ceSopenharmony_ci for (auto &config : reportConfigItems_) { 7948f512ceSopenharmony_ci HLOGV("Config %s", config.second.eventName_.c_str()); 8048f512ceSopenharmony_ci for (auto &process : config.second.processes_) { 8148f512ceSopenharmony_ci for (auto &thread : process.second.threads_) { 8248f512ceSopenharmony_ci thread.second.callNode.UpdateChildrenEventCount(); 8348f512ceSopenharmony_ci thread.second.callNodeReverse.UpdateChildrenEventCount(); 8448f512ceSopenharmony_ci } 8548f512ceSopenharmony_ci } 8648f512ceSopenharmony_ci } 8748f512ceSopenharmony_ci} 8848f512ceSopenharmony_ci 8948f512ceSopenharmony_ciReportConfigItem &ReportJsonFile::GetConfig(uint64_t id) 9048f512ceSopenharmony_ci{ 9148f512ceSopenharmony_ci for (auto &configpair : reportConfigItems_) { 9248f512ceSopenharmony_ci if (find(configpair.first.begin(), configpair.first.end(), id) != configpair.first.end()) { 9348f512ceSopenharmony_ci return configpair.second; 9448f512ceSopenharmony_ci } 9548f512ceSopenharmony_ci } 9648f512ceSopenharmony_ci HLOGE("unable found config item for config id %" PRIu64 "", id); 9748f512ceSopenharmony_ci // return default one 9848f512ceSopenharmony_ci return reportConfigItems_.begin()->second; 9948f512ceSopenharmony_ci} 10048f512ceSopenharmony_ci 10148f512ceSopenharmony_ciint ReportJsonFile::GetFunctionID(int libId, const std::string &function) 10248f512ceSopenharmony_ci{ 10348f512ceSopenharmony_ci auto functionMapIt = functionMap_.find(libId); 10448f512ceSopenharmony_ci if (functionMapIt == functionMap_.end()) { 10548f512ceSopenharmony_ci functionMapIt = functionMap_.try_emplace(libId).first; 10648f512ceSopenharmony_ci } 10748f512ceSopenharmony_ci auto funcMapIt = functionMapIt->second.find(function); 10848f512ceSopenharmony_ci if (funcMapIt == functionMapIt->second.end()) { 10948f512ceSopenharmony_ci HLOGW("'%s' not found in function list in lib %d", function.data(), libId); 11048f512ceSopenharmony_ci // make a new function for unknown name 11148f512ceSopenharmony_ci AddNewFunction(libId, function); 11248f512ceSopenharmony_ci // return the last index 11348f512ceSopenharmony_ci return functionId_ - 1; 11448f512ceSopenharmony_ci } 11548f512ceSopenharmony_ci return funcMapIt->second.reportFuncId_; 11648f512ceSopenharmony_ci} 11748f512ceSopenharmony_ci 11848f512ceSopenharmony_civoid ReportJsonFile::UpdateReportSample(uint64_t id, pid_t pid, pid_t tid, uint64_t eventCount) 11948f512ceSopenharmony_ci{ 12048f512ceSopenharmony_ci auto &config = GetConfig(id); 12148f512ceSopenharmony_ci 12248f512ceSopenharmony_ci config.eventCount_ += eventCount; 12348f512ceSopenharmony_ci auto &process = GetOrCreateMapItem(config.processes_, pid); 12448f512ceSopenharmony_ci process.eventCount_ += eventCount; 12548f512ceSopenharmony_ci auto &thread = GetOrCreateMapItem(process.threads_, tid); 12648f512ceSopenharmony_ci thread.eventCount_ += eventCount; 12748f512ceSopenharmony_ci thread.sampleCount_++; 12848f512ceSopenharmony_ci sampleCount_++; 12948f512ceSopenharmony_ci} 13048f512ceSopenharmony_ci 13148f512ceSopenharmony_civoid ReportJsonFile::AddReportCallStack(uint64_t eventCount, ReportCallNodeItem &callNode, 13248f512ceSopenharmony_ci const std::vector<DfxFrame> &frames) 13348f512ceSopenharmony_ci{ 13448f512ceSopenharmony_ci std::map<int, ReportCallNodeItem> *child = &callNode.childrenMap; 13548f512ceSopenharmony_ci auto it = frames.begin(); 13648f512ceSopenharmony_ci while (it != frames.end()) { 13748f512ceSopenharmony_ci int libId = GetLibID(it->mapName); 13848f512ceSopenharmony_ci if (libId >= 0) { 13948f512ceSopenharmony_ci int funcId = GetFunctionID(libId, it->funcName); 14048f512ceSopenharmony_ci // new children funid 14148f512ceSopenharmony_ci ReportCallNodeItem &grandchildren = GetOrCreateMapItem(*child, funcId); 14248f512ceSopenharmony_ci if (debug_) { 14348f512ceSopenharmony_ci grandchildren.nodeIndex_ = nodeIndex_++; 14448f512ceSopenharmony_ci grandchildren.funcName_ = it->funcName; 14548f512ceSopenharmony_ci grandchildren.reverseCaller_ = true; 14648f512ceSopenharmony_ci } 14748f512ceSopenharmony_ci // only the last one need count 14848f512ceSopenharmony_ci if (it + 1 == frames.end()) { 14948f512ceSopenharmony_ci grandchildren.selfEventCount_ += eventCount; 15048f512ceSopenharmony_ci } 15148f512ceSopenharmony_ci // new children's children 15248f512ceSopenharmony_ci child = &grandchildren.childrenMap; 15348f512ceSopenharmony_ci 15448f512ceSopenharmony_ci HLOGV("add child %*s %d-%d %s @%d %s", static_cast<int>(it - frames.begin()), "", libId, 15548f512ceSopenharmony_ci funcId, it->funcName.data(), grandchildren.nodeIndex_, it->mapName.data()); 15648f512ceSopenharmony_ci } else { 15748f512ceSopenharmony_ci HLOGV("add child failed at %s", it->ToSymbolString().c_str()); 15848f512ceSopenharmony_ci } 15948f512ceSopenharmony_ci it++; 16048f512ceSopenharmony_ci } 16148f512ceSopenharmony_ci} 16248f512ceSopenharmony_ci 16348f512ceSopenharmony_civoid ReportJsonFile::AddReportCallStackReverse(uint64_t eventCount, ReportCallNodeItem &callNode, 16448f512ceSopenharmony_ci const std::vector<DfxFrame> &frames) 16548f512ceSopenharmony_ci{ 16648f512ceSopenharmony_ci std::map<int, ReportCallNodeItem> *child = &callNode.childrenMap; 16748f512ceSopenharmony_ci auto it = frames.rbegin(); 16848f512ceSopenharmony_ci while (it != frames.rend()) { 16948f512ceSopenharmony_ci int libId = GetLibID(it->mapName); 17048f512ceSopenharmony_ci if (libId >= 0) { 17148f512ceSopenharmony_ci int funcId = GetFunctionID(libId, it->funcName); 17248f512ceSopenharmony_ci // new children funid 17348f512ceSopenharmony_ci ReportCallNodeItem &grandchildren = GetOrCreateMapItem(*child, funcId); 17448f512ceSopenharmony_ci if (debug_) { 17548f512ceSopenharmony_ci grandchildren.nodeIndex_ = nodeIndex_++; 17648f512ceSopenharmony_ci grandchildren.funcName_ = it->funcName; 17748f512ceSopenharmony_ci } 17848f512ceSopenharmony_ci // only the last one need count 17948f512ceSopenharmony_ci if (it + 1 == frames.rend()) { 18048f512ceSopenharmony_ci grandchildren.selfEventCount_ += eventCount; 18148f512ceSopenharmony_ci } 18248f512ceSopenharmony_ci // new children's children 18348f512ceSopenharmony_ci child = &grandchildren.childrenMap; 18448f512ceSopenharmony_ci 18548f512ceSopenharmony_ci HLOGV("add child %*s %d-%d %s @%d %s", static_cast<int>(it - frames.rbegin()), "", 18648f512ceSopenharmony_ci libId, funcId, it->funcName.data(), grandchildren.nodeIndex_, 18748f512ceSopenharmony_ci it->mapName.data()); 18848f512ceSopenharmony_ci } else { 18948f512ceSopenharmony_ci HLOGV("add child failed at %s", it->ToSymbolString().c_str()); 19048f512ceSopenharmony_ci } 19148f512ceSopenharmony_ci it++; 19248f512ceSopenharmony_ci } 19348f512ceSopenharmony_ci} 19448f512ceSopenharmony_ci 19548f512ceSopenharmony_ciuint32_t ReportJsonFile::GetConfigIndex(uint64_t id) 19648f512ceSopenharmony_ci{ 19748f512ceSopenharmony_ci return GetConfig(id).index_; 19848f512ceSopenharmony_ci} 19948f512ceSopenharmony_ci 20048f512ceSopenharmony_cistd::string ReportJsonFile::GetConfigName(uint64_t id) 20148f512ceSopenharmony_ci{ 20248f512ceSopenharmony_ci auto &config = GetConfig(id); 20348f512ceSopenharmony_ci return config.eventName_; 20448f512ceSopenharmony_ci} 20548f512ceSopenharmony_ci 20648f512ceSopenharmony_ciint ReportJsonFile::GetLibID(std::string_view filepath) 20748f512ceSopenharmony_ci{ 20848f512ceSopenharmony_ci auto it = find(libList_.begin(), libList_.end(), filepath); 20948f512ceSopenharmony_ci if (it != libList_.end()) { 21048f512ceSopenharmony_ci return it - libList_.begin(); 21148f512ceSopenharmony_ci } else { 21248f512ceSopenharmony_ci HLOGE("'%s' not found in lib list", filepath.data()); 21348f512ceSopenharmony_ci return -1; 21448f512ceSopenharmony_ci } 21548f512ceSopenharmony_ci} 21648f512ceSopenharmony_ci 21748f512ceSopenharmony_civoid ReportJsonFile::UpdateReportCallStack(uint64_t id, pid_t pid, pid_t tid, uint64_t eventCount, 21848f512ceSopenharmony_ci std::vector<DfxFrame> &frames) 21948f512ceSopenharmony_ci{ 22048f512ceSopenharmony_ci auto &config = GetConfig(id); 22148f512ceSopenharmony_ci std::set<int> RepeatFunctionId; 22248f512ceSopenharmony_ci CHECK_TRUE(frames.size() == 0, NO_RETVAL, 0, ""); // do nothing with no frame 22348f512ceSopenharmony_ci auto &process = GetOrCreateMapItem(config.processes_, pid); 22448f512ceSopenharmony_ci auto &thread = GetOrCreateMapItem(process.threads_, tid); 22548f512ceSopenharmony_ci auto it = frames.begin(); 22648f512ceSopenharmony_ci bool jsFrame = StringEndsWith(it->mapName, "stub.an"); 22748f512ceSopenharmony_ci size_t skipFrame = 0; 22848f512ceSopenharmony_ci while (it != frames.end()) { 22948f512ceSopenharmony_ci int libId = GetLibID(it->mapName); 23048f512ceSopenharmony_ci if (libId < 0) { 23148f512ceSopenharmony_ci HLOGW("not found lib path %s", it->mapName.data()); 23248f512ceSopenharmony_ci it++; 23348f512ceSopenharmony_ci continue; 23448f512ceSopenharmony_ci } 23548f512ceSopenharmony_ci ReportLibItem &lib = thread.libs_[libId]; 23648f512ceSopenharmony_ci lib.libId_ = libId; 23748f512ceSopenharmony_ci int funcId = GetFunctionID(libId, it->funcName); 23848f512ceSopenharmony_ci // we will always have a funId, it will create a new one if not found 23948f512ceSopenharmony_ci // so that we can see abc+0x123 in the html 24048f512ceSopenharmony_ci HLOG_ASSERT(funcId >= 0); 24148f512ceSopenharmony_ci if (RepeatFunctionId.count(funcId) != 0) { 24248f512ceSopenharmony_ci it++; 24348f512ceSopenharmony_ci continue; 24448f512ceSopenharmony_ci } else { 24548f512ceSopenharmony_ci RepeatFunctionId.emplace(funcId); 24648f512ceSopenharmony_ci } 24748f512ceSopenharmony_ci 24848f512ceSopenharmony_ci ReportFuncItem &func = GetOrCreateMapItem(lib.funcs_, funcId); 24948f512ceSopenharmony_ci 25048f512ceSopenharmony_ci // always count subtree 25148f512ceSopenharmony_ci func.subTreeEventCount_ += eventCount; 25248f512ceSopenharmony_ci 25348f512ceSopenharmony_ci // only calc the first frame event count 25448f512ceSopenharmony_ci if (jsFrame && frames.size() > 1) { 25548f512ceSopenharmony_ci skipFrame = 1; // 1 : for arkjs frame,skip the stub.an frame 25648f512ceSopenharmony_ci } 25748f512ceSopenharmony_ci if (it == frames.begin() + skipFrame) { 25848f512ceSopenharmony_ci func.eventCount_ += eventCount; 25948f512ceSopenharmony_ci func.sampleCount_ += 1; 26048f512ceSopenharmony_ci lib.eventCount_ += eventCount; 26148f512ceSopenharmony_ci } 26248f512ceSopenharmony_ci // go on next frame 26348f512ceSopenharmony_ci it++; 26448f512ceSopenharmony_ci } 26548f512ceSopenharmony_ci /* 26648f512ceSopenharmony_ci frames are the other way around 26748f512ceSopenharmony_ci 0 is the last called. 26848f512ceSopenharmony_ci So the order of json callstack should be 0 at the end 26948f512ceSopenharmony_ci callNode is Reverse Order of frames 27048f512ceSopenharmony_ci callNodeReverse is Normal Order frames 27148f512ceSopenharmony_ci */ 27248f512ceSopenharmony_ci AddReportCallStackReverse(eventCount, thread.callNode, frames); 27348f512ceSopenharmony_ci AddReportCallStack(eventCount, thread.callNodeReverse, frames); 27448f512ceSopenharmony_ci} 27548f512ceSopenharmony_ci 27648f512ceSopenharmony_civoid ReportJsonFile::OutputJsonFeatureString() 27748f512ceSopenharmony_ci{ 27848f512ceSopenharmony_ci OutputJsonPair(output_, "deviceTime", 27948f512ceSopenharmony_ci recordFileReader_->GetFeatureString(FEATURE::HIPERF_RECORD_TIME), true); 28048f512ceSopenharmony_ci std::string device = recordFileReader_->GetFeatureString(FEATURE::HOSTNAME); 28148f512ceSopenharmony_ci device.append(" " + recordFileReader_->GetFeatureString(FEATURE::OSRELEASE)); 28248f512ceSopenharmony_ci device.append(" " + recordFileReader_->GetFeatureString(FEATURE::ARCH)); 28348f512ceSopenharmony_ci 28448f512ceSopenharmony_ci OutputJsonPair(output_, "deviceType", device); 28548f512ceSopenharmony_ci 28648f512ceSopenharmony_ci OutputJsonPair(output_, "osVersion", recordFileReader_->GetFeatureString(FEATURE::OSRELEASE)); 28748f512ceSopenharmony_ci 28848f512ceSopenharmony_ci OutputJsonPair(output_, "deviceCommandLine", 28948f512ceSopenharmony_ci recordFileReader_->GetFeatureString(FEATURE::CMDLINE)); 29048f512ceSopenharmony_ci 29148f512ceSopenharmony_ci OutputJsonPair(output_, "totalRecordSamples", sampleCount_); 29248f512ceSopenharmony_ci} 29348f512ceSopenharmony_ci 29448f512ceSopenharmony_civoid ReportJsonFile::OutputJsonRuntimeInfo() 29548f512ceSopenharmony_ci{ 29648f512ceSopenharmony_ci const auto &threadMaps = virtualRuntime_.GetThreads(); 29748f512ceSopenharmony_ci std::map<std::string, std::string> jsonProcesses; 29848f512ceSopenharmony_ci std::map<std::string, std::string> jsonThreads; 29948f512ceSopenharmony_ci for (const auto &pair : threadMaps) { 30048f512ceSopenharmony_ci const VirtualThread &thread = pair.second; 30148f512ceSopenharmony_ci if (thread.pid_ == thread.tid_) { 30248f512ceSopenharmony_ci jsonProcesses.emplace(std::to_string(thread.pid_), thread.name_); 30348f512ceSopenharmony_ci } 30448f512ceSopenharmony_ci // process also is a thread. 30548f512ceSopenharmony_ci jsonThreads.emplace(std::to_string(thread.tid_), thread.name_); 30648f512ceSopenharmony_ci } 30748f512ceSopenharmony_ci 30848f512ceSopenharmony_ci OutputJsonMap(output_, "processNameMap", jsonProcesses); 30948f512ceSopenharmony_ci 31048f512ceSopenharmony_ci OutputJsonMap(output_, "threadNameMap", jsonThreads); 31148f512ceSopenharmony_ci 31248f512ceSopenharmony_ci const auto &symbolsFiles = virtualRuntime_.GetSymbolsFiles(); 31348f512ceSopenharmony_ci jsonStringVector jsonFilePaths; 31448f512ceSopenharmony_ci for (const auto &symbolsFile : symbolsFiles) { 31548f512ceSopenharmony_ci jsonFilePaths.emplace_back(symbolsFile->filePath_); 31648f512ceSopenharmony_ci } 31748f512ceSopenharmony_ci 31848f512ceSopenharmony_ci OutputJsonVectorList(output_, "symbolsFileList", jsonFilePaths); 31948f512ceSopenharmony_ci if (fprintf(output_, ",") < 0) { 32048f512ceSopenharmony_ci return; 32148f512ceSopenharmony_ci } 32248f512ceSopenharmony_ci 32348f512ceSopenharmony_ci OutputJsonFunctionMap(output_); 32448f512ceSopenharmony_ci if (fprintf(output_, ",") < 0) { 32548f512ceSopenharmony_ci return; 32648f512ceSopenharmony_ci } 32748f512ceSopenharmony_ci 32848f512ceSopenharmony_ci OutputJsonMapList(output_, "recordSampleInfo", reportConfigItems_, true); 32948f512ceSopenharmony_ci} 33048f512ceSopenharmony_ci 33148f512ceSopenharmony_cibool ReportJsonFile::OutputJson(FILE *output) 33248f512ceSopenharmony_ci{ 33348f512ceSopenharmony_ci CHECK_TRUE(output == nullptr, false, 0, ""); 33448f512ceSopenharmony_ci output_ = output; 33548f512ceSopenharmony_ci if (fprintf(output, "{") < 0) { 33648f512ceSopenharmony_ci return false; 33748f512ceSopenharmony_ci } 33848f512ceSopenharmony_ci OutputJsonFeatureString(); 33948f512ceSopenharmony_ci OutputJsonRuntimeInfo(); 34048f512ceSopenharmony_ci 34148f512ceSopenharmony_ci if (fprintf(output, "}") < 0) { 34248f512ceSopenharmony_ci return false; 34348f512ceSopenharmony_ci } 34448f512ceSopenharmony_ci return true; 34548f512ceSopenharmony_ci} 34648f512ceSopenharmony_ci} // namespace HiPerf 34748f512ceSopenharmony_ci} // namespace Developtools 34848f512ceSopenharmony_ci} // namespace OHOS 349