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 "report.h" 1848f512ceSopenharmony_ci 1948f512ceSopenharmony_ci#include <memory> 2048f512ceSopenharmony_ci#include <set> 2148f512ceSopenharmony_ci#include <sstream> 2248f512ceSopenharmony_ci 2348f512ceSopenharmony_ci#if defined(is_mingw) && is_mingw 2448f512ceSopenharmony_ci#include <windows.h> 2548f512ceSopenharmony_ci#else 2648f512ceSopenharmony_ci#include <sys/ioctl.h> 2748f512ceSopenharmony_ci#endif 2848f512ceSopenharmony_ci 2948f512ceSopenharmony_ci#include "hiperf_hilog.h" 3048f512ceSopenharmony_ci 3148f512ceSopenharmony_ciusing namespace std::placeholders; 3248f512ceSopenharmony_cinamespace OHOS { 3348f512ceSopenharmony_cinamespace Developtools { 3448f512ceSopenharmony_cinamespace HiPerf { 3548f512ceSopenharmony_ciunsigned long long ReportItem::allIndex_ = 0; 3648f512ceSopenharmony_civoid Report::AddReportItem(const PerfRecordSample &sample, bool includeCallStack) 3748f512ceSopenharmony_ci{ 3848f512ceSopenharmony_ci size_t configIndex = GetConfigIndex(sample.data_.id); 3948f512ceSopenharmony_ci HLOG_ASSERT_MESSAGE(configs_.size() > configIndex, 4048f512ceSopenharmony_ci "in %zu configs found index %zu, from ids %llu", configs_.size(), 4148f512ceSopenharmony_ci configIndex, sample.data_.id); 4248f512ceSopenharmony_ci VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid); 4348f512ceSopenharmony_ci HLOG_ASSERT(sample.callFrames_.size() > 0); 4448f512ceSopenharmony_ci if (sample.callFrames_.size() > 0) { 4548f512ceSopenharmony_ci // if we need callstack ? 4648f512ceSopenharmony_ci if (includeCallStack) { 4748f512ceSopenharmony_ci // we will use caller mode , from last to first 4848f512ceSopenharmony_ci auto frameIt = sample.callFrames_.rbegin(); 4948f512ceSopenharmony_ci ReportItem &item = configs_[configIndex].reportItems_.emplace_back( 5048f512ceSopenharmony_ci sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName, 5148f512ceSopenharmony_ci frameIt->funcName, frameIt->funcOffset, sample.data_.period); 5248f512ceSopenharmony_ci HLOGD("ReportItem: %s", item.ToDebugString().c_str()); 5348f512ceSopenharmony_ci HLOG_ASSERT(!item.func_.empty()); 5448f512ceSopenharmony_ci 5548f512ceSopenharmony_ci std::vector<ReportItemCallFrame> *currentCallFrames = &item.callStacks_; 5648f512ceSopenharmony_ci for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend(); 5748f512ceSopenharmony_ci frameIt++) { 5848f512ceSopenharmony_ci HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); 5948f512ceSopenharmony_ci // in add items case , right one should only have 1 callstack 6048f512ceSopenharmony_ci // so just new callfames and move to next level 6148f512ceSopenharmony_ci ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back( 6248f512ceSopenharmony_ci frameIt->funcName, frameIt->funcOffset, frameIt->mapName, 6348f512ceSopenharmony_ci sample.data_.period, 6448f512ceSopenharmony_ci (std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0); 6548f512ceSopenharmony_ci HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str()); 6648f512ceSopenharmony_ci currentCallFrames = &nextCallFrame.childs; 6748f512ceSopenharmony_ci } 6848f512ceSopenharmony_ci HLOGV("callstack %zu", item.callStacks_.size()); 6948f512ceSopenharmony_ci if (item.callStacks_.size() > 0) { 7048f512ceSopenharmony_ci HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size()); 7148f512ceSopenharmony_ci } 7248f512ceSopenharmony_ci } else { 7348f512ceSopenharmony_ci auto frameIt = sample.callFrames_.begin(); 7448f512ceSopenharmony_ci if (frameIt != sample.callFrames_.end()) { 7548f512ceSopenharmony_ci HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); 7648f512ceSopenharmony_ci // for arkjs frame, skip the stub.an frame 7748f512ceSopenharmony_ci if (StringEndsWith(frameIt->mapName, "stub.an") && sample.callFrames_.size() > 1) { 7848f512ceSopenharmony_ci HLOGV("stub.an frame, go to next, mapname %s", frameIt->mapName.c_str()); 7948f512ceSopenharmony_ci frameIt++; 8048f512ceSopenharmony_ci } 8148f512ceSopenharmony_ci ReportItem &item = configs_[configIndex].reportItems_.emplace_back( 8248f512ceSopenharmony_ci sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName, 8348f512ceSopenharmony_ci frameIt->funcName, frameIt->funcOffset, sample.data_.period); 8448f512ceSopenharmony_ci HLOGV("%s", item.ToDebugString().c_str()); 8548f512ceSopenharmony_ci HLOG_ASSERT(!item.func_.empty()); 8648f512ceSopenharmony_ci } 8748f512ceSopenharmony_ci } 8848f512ceSopenharmony_ci } 8948f512ceSopenharmony_ci configs_[configIndex].sampleCount_++; 9048f512ceSopenharmony_ci configs_[configIndex].eventCount_ += sample.data_.period; 9148f512ceSopenharmony_ci} 9248f512ceSopenharmony_ci 9348f512ceSopenharmony_civoid Report::AddReportItemBranch(const PerfRecordSample &sample) 9448f512ceSopenharmony_ci{ 9548f512ceSopenharmony_ci size_t configIndex = GetConfigIndex(sample.data_.id); 9648f512ceSopenharmony_ci HLOG_ASSERT(configs_.size() > configIndex); 9748f512ceSopenharmony_ci VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid); 9848f512ceSopenharmony_ci for (u64 i = 0; i < sample.data_.bnr; i++) { 9948f512ceSopenharmony_ci DfxSymbol symbolTo = 10048f512ceSopenharmony_ci virtualRuntime_.GetSymbol(sample.data_.lbr[i].to, sample.data_.pid, sample.data_.tid); 10148f512ceSopenharmony_ci DfxSymbol symbolFrom = 10248f512ceSopenharmony_ci virtualRuntime_.GetSymbol(sample.data_.lbr[i].from, sample.data_.pid, sample.data_.tid); 10348f512ceSopenharmony_ci 10448f512ceSopenharmony_ci // branch only have 1 time only for period 10548f512ceSopenharmony_ci ReportItem &item = configs_[configIndex].reportItems_.emplace_back( 10648f512ceSopenharmony_ci sample.data_.pid, sample.data_.tid, thread.name_, symbolTo.module_, symbolTo.GetName(), 10748f512ceSopenharmony_ci symbolTo.funcVaddr_, 1u); 10848f512ceSopenharmony_ci 10948f512ceSopenharmony_ci item.fromDso_ = symbolFrom.module_; 11048f512ceSopenharmony_ci item.fromFunc_ = symbolFrom.GetName(); 11148f512ceSopenharmony_ci 11248f512ceSopenharmony_ci HLOGV("%s 0x%" PRIx64 "", item.ToDebugString().c_str(), symbolTo.taskVaddr_); 11348f512ceSopenharmony_ci } 11448f512ceSopenharmony_ci configs_[configIndex].sampleCount_++; 11548f512ceSopenharmony_ci configs_[configIndex].eventCount_ += sample.data_.bnr; 11648f512ceSopenharmony_ci} 11748f512ceSopenharmony_ci 11848f512ceSopenharmony_civoid Report::StatisticsRecords() 11948f512ceSopenharmony_ci{ 12048f512ceSopenharmony_ci for (auto &config : configs_) { 12148f512ceSopenharmony_ci size_t duplicates = 0; 12248f512ceSopenharmony_ci size_t totalReportCount = config.reportItems_.size(); 12348f512ceSopenharmony_ci // merge duplicate 12448f512ceSopenharmony_ci HLOGD("uniquing %zu", totalReportCount); 12548f512ceSopenharmony_ci auto last = std::unique(config.reportItems_.begin(), config.reportItems_.end(), 12648f512ceSopenharmony_ci [this] (ReportItem &l, ReportItem &r) -> bool { 12748f512ceSopenharmony_ci return this->MultiLevelSameAndUpdateCount(l, r); 12848f512ceSopenharmony_ci }); 12948f512ceSopenharmony_ci 13048f512ceSopenharmony_ci config.reportItems_.erase(last, config.reportItems_.end()); 13148f512ceSopenharmony_ci 13248f512ceSopenharmony_ci duplicates = totalReportCount - config.reportItems_.size(); 13348f512ceSopenharmony_ci HLOGD("duplicates %zu, %zu -> %zu", duplicates, totalReportCount, 13448f512ceSopenharmony_ci config.reportItems_.size()); 13548f512ceSopenharmony_ci } 13648f512ceSopenharmony_ci} 13748f512ceSopenharmony_ci 13848f512ceSopenharmony_civoid Report::FilterDisplayRecords() 13948f512ceSopenharmony_ci{ 14048f512ceSopenharmony_ci // remove the item with not in fliter 14148f512ceSopenharmony_ci for (auto &config : configs_) { 14248f512ceSopenharmony_ci size_t filterOuts = 0; 14348f512ceSopenharmony_ci size_t totalReportCount = config.reportItems_.size(); 14448f512ceSopenharmony_ci for (const auto &reportKeyPair : reportKeyMap_) { 14548f512ceSopenharmony_ci auto reportKey = reportKeyPair.second; 14648f512ceSopenharmony_ci if (reportKey.displayFilter_.size() != 0) { 14748f512ceSopenharmony_ci auto itemIt = config.reportItems_.begin(); 14848f512ceSopenharmony_ci while (itemIt != config.reportItems_.end()) { 14948f512ceSopenharmony_ci if (!reportKey.ShouldDisplay(*itemIt)) { 15048f512ceSopenharmony_ci HLOGM("filter out %s", itemIt->ToDebugString().c_str()); 15148f512ceSopenharmony_ci 15248f512ceSopenharmony_ci // we need recalc the heating ,so also remove in total count 15348f512ceSopenharmony_ci config.eventCount_ -= itemIt->eventCount_; 15448f512ceSopenharmony_ci 15548f512ceSopenharmony_ci // after update total eventCount remove this 15648f512ceSopenharmony_ci itemIt = config.reportItems_.erase(itemIt); 15748f512ceSopenharmony_ci filterOuts++; 15848f512ceSopenharmony_ci } else { 15948f512ceSopenharmony_ci itemIt++; 16048f512ceSopenharmony_ci } 16148f512ceSopenharmony_ci } 16248f512ceSopenharmony_ci } 16348f512ceSopenharmony_ci } 16448f512ceSopenharmony_ci HLOGD("filter out %zu, %zu -> %zu", filterOuts, totalReportCount, 16548f512ceSopenharmony_ci config.reportItems_.size()); 16648f512ceSopenharmony_ci } 16748f512ceSopenharmony_ci} 16848f512ceSopenharmony_ci 16948f512ceSopenharmony_civoid Report::UpdateReportItemsAfterAdjust() 17048f512ceSopenharmony_ci{ 17148f512ceSopenharmony_ci for (auto &config : configs_) { 17248f512ceSopenharmony_ci HLOGV("percentage %zu items", config.reportItems_.size()); 17348f512ceSopenharmony_ci uint64_t totalEventCount = 0; // just for debug check 17448f512ceSopenharmony_ci for (auto &item : config.reportItems_) { 17548f512ceSopenharmony_ci item.heat = Percentage(item.eventCount_, config.eventCount_); 17648f512ceSopenharmony_ci totalEventCount += item.eventCount_; 17748f512ceSopenharmony_ci HLOGM("%s percentage from %5.2f%% %" PRIu64 "/ %" PRIu64 "", 17848f512ceSopenharmony_ci item.ToDebugString().c_str(), item.heat, item.eventCount_, config.eventCount_); 17948f512ceSopenharmony_ci for (auto keyPair : reportKeyMap_) { 18048f512ceSopenharmony_ci reportKeyMap_.at(keyPair.first).UpdateValueMaxLen(keyPair.second.GetValue(item)); 18148f512ceSopenharmony_ci } 18248f512ceSopenharmony_ci } 18348f512ceSopenharmony_ci // check again 18448f512ceSopenharmony_ci HLOGV("recalc totalEventCount is %" PRIu64 " old totalEventCount is %" PRIu64 "", 18548f512ceSopenharmony_ci totalEventCount, config.eventCount_); 18648f512ceSopenharmony_ci HLOG_ASSERT(totalEventCount == config.eventCount_); 18748f512ceSopenharmony_ci } 18848f512ceSopenharmony_ci} 18948f512ceSopenharmony_ci 19048f512ceSopenharmony_civoid Report::AdjustReportItems() 19148f512ceSopenharmony_ci{ 19248f512ceSopenharmony_ci HLOGD("Adjust Record Order ...."); 19348f512ceSopenharmony_ci for (auto &config : configs_) { 19448f512ceSopenharmony_ci uint64_t totalReportCount = config.reportItems_.size(); 19548f512ceSopenharmony_ci if (option_.debug_) { 19648f512ceSopenharmony_ci for (auto &reportItem : config.reportItems_) { 19748f512ceSopenharmony_ci HLOGV("reportItem %s", reportItem.ToDebugString().c_str()); 19848f512ceSopenharmony_ci } 19948f512ceSopenharmony_ci } 20048f512ceSopenharmony_ci // sort first. 20148f512ceSopenharmony_ci HLOGD("MultiLevelSorting %" PRIu64 "", totalReportCount); 20248f512ceSopenharmony_ci std::sort(config.reportItems_.begin(), config.reportItems_.end(), 20348f512ceSopenharmony_ci [this] (const ReportItem &a, const ReportItem &b) -> bool { 20448f512ceSopenharmony_ci return this->MultiLevelSorting(a, b); 20548f512ceSopenharmony_ci }); 20648f512ceSopenharmony_ci HLOGD("MultiLevelSorting %" PRIu64 " done", totalReportCount); 20748f512ceSopenharmony_ci // reorder the callstack 20848f512ceSopenharmony_ci if (option_.debug_) { 20948f512ceSopenharmony_ci for (auto &reportItem : config.reportItems_) { 21048f512ceSopenharmony_ci HLOGV("reportItem %s", reportItem.ToDebugString().c_str()); 21148f512ceSopenharmony_ci } 21248f512ceSopenharmony_ci } 21348f512ceSopenharmony_ci StatisticsRecords(); 21448f512ceSopenharmony_ci FilterDisplayRecords(); 21548f512ceSopenharmony_ci 21648f512ceSopenharmony_ci // reorder by count 21748f512ceSopenharmony_ci std::sort(config.reportItems_.begin(), config.reportItems_.end(), 21848f512ceSopenharmony_ci &ReportItem::CompareSortingEventCount); 21948f512ceSopenharmony_ci 22048f512ceSopenharmony_ci // reorder the callstack 22148f512ceSopenharmony_ci for (auto &reportItem : config.reportItems_) { 22248f512ceSopenharmony_ci ReportItemCallFrame::OrderCallFrames(reportItem.callStacks_); 22348f512ceSopenharmony_ci } 22448f512ceSopenharmony_ci HLOGD("afater sorting and unique, we have %zu report items,", config.reportItems_.size()); 22548f512ceSopenharmony_ci } 22648f512ceSopenharmony_ci // udpate percentage 22748f512ceSopenharmony_ci UpdateReportItemsAfterAdjust(); 22848f512ceSopenharmony_ci} 22948f512ceSopenharmony_ci 23048f512ceSopenharmony_ciint Report::MultiLevelCompare(const ReportItem &a, const ReportItem &b) 23148f512ceSopenharmony_ci{ 23248f512ceSopenharmony_ci HLOGM("MultiLevelCompare %s vs %s sort order %s", a.ToDebugString().c_str(), 23348f512ceSopenharmony_ci b.ToDebugString().c_str(), VectorToString(option_.sortKeys_).c_str()); 23448f512ceSopenharmony_ci 23548f512ceSopenharmony_ci // check each key user care 23648f512ceSopenharmony_ci for (auto it = option_.sortKeys_.begin(); it != option_.sortKeys_.end(); ++it) { 23748f512ceSopenharmony_ci int result = reportKeyMap_.at(*it).compareFunction_(a, b); 23848f512ceSopenharmony_ci if (result == 0) { 23948f512ceSopenharmony_ci // this key is same , check the next one 24048f512ceSopenharmony_ci continue; 24148f512ceSopenharmony_ci } else { 24248f512ceSopenharmony_ci // if onekey is not same , returl as not same 24348f512ceSopenharmony_ci HLOGM("not same because %s %d : %s vs %s", it->c_str(), result, 24448f512ceSopenharmony_ci reportKeyMap_.at(*it).GetValue(a).c_str(), 24548f512ceSopenharmony_ci reportKeyMap_.at(*it).GetValue(b).c_str()); 24648f512ceSopenharmony_ci return result; 24748f512ceSopenharmony_ci } 24848f512ceSopenharmony_ci } 24948f512ceSopenharmony_ci // all the key is same 25048f512ceSopenharmony_ci return 0; 25148f512ceSopenharmony_ci} 25248f512ceSopenharmony_ci 25348f512ceSopenharmony_cibool Report::MultiLevelSame(const ReportItem &a, const ReportItem &b) 25448f512ceSopenharmony_ci{ 25548f512ceSopenharmony_ci return MultiLevelCompare(a, b) == 0; 25648f512ceSopenharmony_ci} 25748f512ceSopenharmony_ci 25848f512ceSopenharmony_civoid Report::MergeCallFrameCount(ReportItem &leftItem, ReportItem &rightItem) 25948f512ceSopenharmony_ci{ 26048f512ceSopenharmony_ci // add to left (right to left) 26148f512ceSopenharmony_ci std::vector<ReportItemCallFrame> *leftCallFrames = &leftItem.callStacks_; 26248f512ceSopenharmony_ci const std::vector<ReportItemCallFrame> *rightCallFrames = &rightItem.callStacks_; 26348f512ceSopenharmony_ci uint64_t maxEventCount = leftItem.eventCount_; 26448f512ceSopenharmony_ci // right should only have one call stack 26548f512ceSopenharmony_ci int level = 0; 26648f512ceSopenharmony_ci while (rightCallFrames->size() != 0) { 26748f512ceSopenharmony_ci HLOG_ASSERT(rightCallFrames->size() == 1u); 26848f512ceSopenharmony_ci const ReportItemCallFrame &rightFrame = rightCallFrames->at(0); 26948f512ceSopenharmony_ci auto leftFrameIt = std::find(leftCallFrames->begin(), leftCallFrames->end(), rightFrame); 27048f512ceSopenharmony_ci if (leftFrameIt == leftCallFrames->end()) { 27148f512ceSopenharmony_ci // new callfames 27248f512ceSopenharmony_ci auto &leftCallFrame = leftCallFrames->emplace_back(rightFrame); 27348f512ceSopenharmony_ci HLOGV("%*s create frame %s in %s", level, "", leftCallFrame.ToDebugString().c_str(), 27448f512ceSopenharmony_ci leftItem.ToDebugString().c_str()); 27548f512ceSopenharmony_ci HLOG_ASSERT(leftCallFrame.eventCount_ <= maxEventCount); 27648f512ceSopenharmony_ci // this is a new call stack , 27748f512ceSopenharmony_ci // all the child in rightFrame has been copy to left. 27848f512ceSopenharmony_ci break; 27948f512ceSopenharmony_ci } else { 28048f512ceSopenharmony_ci // already have , add count 28148f512ceSopenharmony_ci leftFrameIt->eventCount_ += rightFrame.eventCount_; 28248f512ceSopenharmony_ci leftFrameIt->selfEventCount_ += rightFrame.selfEventCount_; 28348f512ceSopenharmony_ci // left move to next 28448f512ceSopenharmony_ci leftCallFrames = &(leftFrameIt->childs); 28548f512ceSopenharmony_ci HLOGM("%*s udpate frame +%" PRIu64 " %s in %s", level, "", rightFrame.eventCount_, 28648f512ceSopenharmony_ci leftFrameIt->ToDebugString().c_str(), leftItem.ToDebugString().c_str()); 28748f512ceSopenharmony_ci HLOG_ASSERT_MESSAGE(leftFrameIt->eventCount_ <= maxEventCount, 28848f512ceSopenharmony_ci " maxEventCount is %" PRIu64 "", maxEventCount); 28948f512ceSopenharmony_ci maxEventCount = leftFrameIt->eventCount_; 29048f512ceSopenharmony_ci } 29148f512ceSopenharmony_ci // move to next level 29248f512ceSopenharmony_ci rightCallFrames = &(rightFrame.childs); 29348f512ceSopenharmony_ci level++; 29448f512ceSopenharmony_ci } 29548f512ceSopenharmony_ci} 29648f512ceSopenharmony_ci 29748f512ceSopenharmony_cibool Report::MultiLevelSameAndUpdateCount(ReportItem &l, ReportItem &r) 29848f512ceSopenharmony_ci{ 29948f512ceSopenharmony_ci if (MultiLevelCompare(l, r) == 0) { 30048f512ceSopenharmony_ci l.eventCount_ += r.eventCount_; 30148f512ceSopenharmony_ci HLOGM("l %" PRIu64 " %s c:%zu vs r %" PRIu64 " %s c:%zu", l.eventCount_, l.func_.data(), 30248f512ceSopenharmony_ci l.callStacks_.size(), r.eventCount_, r.func_.data(), r.callStacks_.size()); 30348f512ceSopenharmony_ci // if it have call stack? 30448f512ceSopenharmony_ci if (r.callStacks_.size() != 0) { 30548f512ceSopenharmony_ci // add to left (right to left) 30648f512ceSopenharmony_ci MergeCallFrameCount(l, r); 30748f512ceSopenharmony_ci } 30848f512ceSopenharmony_ci return true; 30948f512ceSopenharmony_ci } else { 31048f512ceSopenharmony_ci return false; 31148f512ceSopenharmony_ci } 31248f512ceSopenharmony_ci} 31348f512ceSopenharmony_ci 31448f512ceSopenharmony_cibool Report::MultiLevelSorting(const ReportItem &a, const ReportItem &b) 31548f512ceSopenharmony_ci{ 31648f512ceSopenharmony_ci /* 31748f512ceSopenharmony_ci The value returned indicates whether the element passed as first argument is 31848f512ceSopenharmony_ci considered to go before the second in the specific strict weak ordering it defines. 31948f512ceSopenharmony_ci */ 32048f512ceSopenharmony_ci bool result = MultiLevelCompare(a, b) > 0; 32148f512ceSopenharmony_ci#ifdef HIPERF_DEBUG 32248f512ceSopenharmony_ci if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) { 32348f512ceSopenharmony_ci bool result2 = MultiLevelCompare(b, a) > 0; 32448f512ceSopenharmony_ci if (result and result == result2) { 32548f512ceSopenharmony_ci HLOGE("MultiLevelSorting a->b %d vs b->a %d", result, result2); 32648f512ceSopenharmony_ci HLOGE("left %s", a.ToDebugString().c_str()); 32748f512ceSopenharmony_ci HLOGE("right %s", b.ToDebugString().c_str()); 32848f512ceSopenharmony_ci HLOG_ASSERT(false); 32948f512ceSopenharmony_ci } 33048f512ceSopenharmony_ci } 33148f512ceSopenharmony_ci#endif 33248f512ceSopenharmony_ci return result; 33348f512ceSopenharmony_ci} 33448f512ceSopenharmony_ci 33548f512ceSopenharmony_civoid Report::OutputStdStatistics(ReportEventConfigItem &config) 33648f512ceSopenharmony_ci{ 33748f512ceSopenharmony_ci if (fprintf(output_, "\n") < 0) { 33848f512ceSopenharmony_ci return; 33948f512ceSopenharmony_ci } // make a blank line for new event 34048f512ceSopenharmony_ci if (fprintf(output_, "Event: %s (type %" PRIu32 " id %" PRIu64 ")\n", config.eventName_.c_str(), 34148f512ceSopenharmony_ci config.type_, config.config_) < 0) { 34248f512ceSopenharmony_ci return; 34348f512ceSopenharmony_ci } 34448f512ceSopenharmony_ci if (fprintf(output_, "Samples Count: %" PRIu64 "\n", config.sampleCount_) < 0) { 34548f512ceSopenharmony_ci return; 34648f512ceSopenharmony_ci } 34748f512ceSopenharmony_ci if (!config.coutMode_) { 34848f512ceSopenharmony_ci fprintf(output_, "Time in ns: "); 34948f512ceSopenharmony_ci } else { 35048f512ceSopenharmony_ci fprintf(output_, "Event Count: "); 35148f512ceSopenharmony_ci } 35248f512ceSopenharmony_ci fprintf(output_, "%" PRIu64 "\n", config.eventCount_); 35348f512ceSopenharmony_ci} 35448f512ceSopenharmony_ci 35548f512ceSopenharmony_civoid Report::OutputStdHead(ReportEventConfigItem &config, bool diffMode) 35648f512ceSopenharmony_ci{ 35748f512ceSopenharmony_ci // head print 35848f512ceSopenharmony_ci const std::string head = "Heating"; 35948f512ceSopenharmony_ci if (fprintf(output_, "%-*s ", FULL_PERCENTAGE_LEN, head.c_str()) < 0) { 36048f512ceSopenharmony_ci return; 36148f512ceSopenharmony_ci } 36248f512ceSopenharmony_ci 36348f512ceSopenharmony_ci if (diffMode) { 36448f512ceSopenharmony_ci const std::string diff = "Diff"; 36548f512ceSopenharmony_ci fprintf(output_, "%-*s ", FULL_PERCENTAGE_DIFF_LEN, diff.c_str()); 36648f512ceSopenharmony_ci } 36748f512ceSopenharmony_ci 36848f512ceSopenharmony_ci // merge sort key and no-sort key (like count) 36948f512ceSopenharmony_ci 37048f512ceSopenharmony_ci displayKeyNames_ = option_.sortKeys_; 37148f512ceSopenharmony_ci if (!option_.hideCount_) { 37248f512ceSopenharmony_ci displayKeyNames_.insert(displayKeyNames_.begin(), "count"); 37348f512ceSopenharmony_ci } 37448f512ceSopenharmony_ci 37548f512ceSopenharmony_ci unsigned int remainingWidth = consoleWidth_; 37648f512ceSopenharmony_ci // sort key head 37748f512ceSopenharmony_ci for (auto &keyName : displayKeyNames_) { 37848f512ceSopenharmony_ci auto &key = reportKeyMap_.at(keyName); 37948f512ceSopenharmony_ci remainingWidth -= key.maxLen_; 38048f512ceSopenharmony_ci if (remainingWidth == 0) { 38148f512ceSopenharmony_ci key.maxLen_ = 0; 38248f512ceSopenharmony_ci } 38348f512ceSopenharmony_ci if (fprintf(output_, "%-*s ", (remainingWidth > 0) ? static_cast<unsigned int>(key.maxLen_) : 0, 38448f512ceSopenharmony_ci key.keyName_.c_str()) < 0) { 38548f512ceSopenharmony_ci return; 38648f512ceSopenharmony_ci } 38748f512ceSopenharmony_ci HLOGD("'%s' max len %zu(from '%s') console width %d", key.keyName_.c_str(), key.maxLen_, 38848f512ceSopenharmony_ci key.maxValue_.c_str(), remainingWidth); 38948f512ceSopenharmony_ci } 39048f512ceSopenharmony_ci if (fprintf(output_, "\n") < 0) { 39148f512ceSopenharmony_ci return; 39248f512ceSopenharmony_ci } 39348f512ceSopenharmony_ci} 39448f512ceSopenharmony_ci 39548f512ceSopenharmony_cibool Report::OutputStdCallFrame(int indent, const std::string_view &funcName, uint64_t eventCount, 39648f512ceSopenharmony_ci uint64_t totalEventCount) 39748f512ceSopenharmony_ci{ 39848f512ceSopenharmony_ci float heat = Percentage(eventCount, totalEventCount); 39948f512ceSopenharmony_ci float num = 100.0; 40048f512ceSopenharmony_ci HLOGV("frame %f indent %d at %s", heat, indent, funcName.data()); 40148f512ceSopenharmony_ci 40248f512ceSopenharmony_ci CHECK_TRUE(heat < option_.callStackHeatLimit_, false, 0, ""); // don't print this three anymore 40348f512ceSopenharmony_ci 40448f512ceSopenharmony_ci if (abs(heat - num) < ALMOST_ZERO) { 40548f512ceSopenharmony_ci fprintf(output_, "%*s", indent, " "); 40648f512ceSopenharmony_ci fprintf(output_, "%*s ", FULL_PERCENTAGE_NUM_LEN, " "); 40748f512ceSopenharmony_ci } else { 40848f512ceSopenharmony_ci fprintf(output_, "%*s", indent, "|- "); 40948f512ceSopenharmony_ci fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); 41048f512ceSopenharmony_ci } 41148f512ceSopenharmony_ci if (option_.debug_) { 41248f512ceSopenharmony_ci fprintf(output_, "%" PRIu64 "/%" PRIu64 " %s\n", eventCount, totalEventCount, 41348f512ceSopenharmony_ci funcName.data()); 41448f512ceSopenharmony_ci } else { 41548f512ceSopenharmony_ci fprintf(output_, "%s\n", funcName.data()); 41648f512ceSopenharmony_ci } 41748f512ceSopenharmony_ci return true; 41848f512ceSopenharmony_ci} 41948f512ceSopenharmony_ci 42048f512ceSopenharmony_civoid Report::PrepareConsole() 42148f512ceSopenharmony_ci{ 42248f512ceSopenharmony_ci#if defined(is_mingw) && is_mingw 42348f512ceSopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO csbi; 42448f512ceSopenharmony_ci GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 42548f512ceSopenharmony_ci consoleWidth_ = static_cast<unsigned int>(csbi.srWindow.Right - csbi.srWindow.Left + 1); 42648f512ceSopenharmony_ci const auto handle = GetStdHandle(STD_OUTPUT_HANDLE); 42748f512ceSopenharmony_ci DWORD mode; 42848f512ceSopenharmony_ci GetConsoleMode(handle, &mode); 42948f512ceSopenharmony_ci mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; 43048f512ceSopenharmony_ci SetConsoleMode(handle, mode); 43148f512ceSopenharmony_ci#else 43248f512ceSopenharmony_ci struct winsize w = {0, 0, 0, 0}; 43348f512ceSopenharmony_ci ioctl(fileno(stdout), TIOCGWINSZ, &w); 43448f512ceSopenharmony_ci consoleWidth_ = static_cast<unsigned int>(w.ws_col); 43548f512ceSopenharmony_ci#endif 43648f512ceSopenharmony_ci if (consoleWidth_ == 0) { 43748f512ceSopenharmony_ci consoleWidth_ = ConsoleDefaultWidth; 43848f512ceSopenharmony_ci } 43948f512ceSopenharmony_ci HLOGD("consoleWidth_:%d", consoleWidth_); 44048f512ceSopenharmony_ci} 44148f512ceSopenharmony_ci 44248f512ceSopenharmony_civoid Report::OutputStdCallFrames(int indent, const ReportItemCallFrame &callFrame, uint64_t totalEventCount) 44348f512ceSopenharmony_ci{ 44448f512ceSopenharmony_ci /* 44548f512ceSopenharmony_ci 90% a 44648f512ceSopenharmony_ci |- 80% b 44748f512ceSopenharmony_ci c 44848f512ceSopenharmony_ci d 44948f512ceSopenharmony_ci |- 50% e 45048f512ceSopenharmony_ci |- 50% f 45148f512ceSopenharmony_ci g 45248f512ceSopenharmony_ci */ 45348f512ceSopenharmony_ci // this is the first call frame 45448f512ceSopenharmony_ci // this tree will skipped. 45548f512ceSopenharmony_ci CHECK_TRUE(!OutputStdCallFrame(indent, callFrame.func_, callFrame.eventCount_, totalEventCount), 45648f512ceSopenharmony_ci NO_RETVAL, 0, ""); 45748f512ceSopenharmony_ci 45848f512ceSopenharmony_ci // print it self 45948f512ceSopenharmony_ci if (callFrame.selfEventCount_ != 0 and callFrame.selfEventCount_ != callFrame.eventCount_) { 46048f512ceSopenharmony_ci OutputStdCallFrame(indent + CALLSTACK_INDENT, "[run in self function]", 46148f512ceSopenharmony_ci callFrame.selfEventCount_, callFrame.eventCount_); 46248f512ceSopenharmony_ci } 46348f512ceSopenharmony_ci 46448f512ceSopenharmony_ci // printf children 46548f512ceSopenharmony_ci // if only one children 46648f512ceSopenharmony_ci if (callFrame.childs.size() == 1u and 46748f512ceSopenharmony_ci callFrame.childs[0].eventCount_ == callFrame.eventCount_) { 46848f512ceSopenharmony_ci HLOGV("childCallFream %*c %s", indent, ' ', callFrame.childs[0].func_.data()); 46948f512ceSopenharmony_ci // don't indent if same count (only one 100% children) 47048f512ceSopenharmony_ci OutputStdCallFrames(indent, callFrame.childs[0], callFrame.eventCount_); 47148f512ceSopenharmony_ci } else { 47248f512ceSopenharmony_ci // else a lot children 47348f512ceSopenharmony_ci for (const ReportItemCallFrame &childCallFrame : callFrame.childs) { 47448f512ceSopenharmony_ci HLOGV("childCallFream %*c %s", indent, ' ', childCallFrame.func_.data()); 47548f512ceSopenharmony_ci OutputStdCallFrames(indent + CALLSTACK_INDENT, childCallFrame, callFrame.eventCount_); 47648f512ceSopenharmony_ci } 47748f512ceSopenharmony_ci } 47848f512ceSopenharmony_ci} 47948f512ceSopenharmony_ci 48048f512ceSopenharmony_civoid Report::OutputStdContent(ReportEventConfigItem &config) 48148f512ceSopenharmony_ci{ 48248f512ceSopenharmony_ci // content print 48348f512ceSopenharmony_ci auto it = config.reportItems_.begin(); 48448f512ceSopenharmony_ci while (it != config.reportItems_.end()) { 48548f512ceSopenharmony_ci const ReportItem &reportItem = it.operator*(); 48648f512ceSopenharmony_ci // if we need skip it ? 48748f512ceSopenharmony_ci if (reportItem.heat < option_.heatLimit_) { 48848f512ceSopenharmony_ci it++; 48948f512ceSopenharmony_ci continue; // below limit 49048f512ceSopenharmony_ci } else { 49148f512ceSopenharmony_ci fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, reportItem.heat); 49248f512ceSopenharmony_ci } 49348f512ceSopenharmony_ci OutputStdContentItem(reportItem); 49448f512ceSopenharmony_ci if (reportItem.callStacks_.size() != 0) { 49548f512ceSopenharmony_ci HLOGV("reportItem.callStacks_ %zu %s", reportItem.callStacks_.size(), 49648f512ceSopenharmony_ci reportItem.ToDebugString().c_str()); 49748f512ceSopenharmony_ci HLOG_ASSERT(reportItem.callStacks_.size() == 1u); 49848f512ceSopenharmony_ci for (auto &callFrame : reportItem.callStacks_) { 49948f512ceSopenharmony_ci OutputStdCallFrames(CALLSTACK_INDENT, callFrame, reportItem.eventCount_); 50048f512ceSopenharmony_ci } 50148f512ceSopenharmony_ci } 50248f512ceSopenharmony_ci it++; 50348f512ceSopenharmony_ci } 50448f512ceSopenharmony_ci} 50548f512ceSopenharmony_ci 50648f512ceSopenharmony_civoid Report::OutputStdContentItem(const ReportItem &reportItem) 50748f512ceSopenharmony_ci{ 50848f512ceSopenharmony_ci // output by sort keys 50948f512ceSopenharmony_ci for (auto sortKey : displayKeyNames_) { 51048f512ceSopenharmony_ci ReportKey &reportKey = Report::reportKeyMap_.at(sortKey); 51148f512ceSopenharmony_ci if (fprintf(output_, "%s ", reportKey.GetValue(reportItem).c_str()) < 0) { 51248f512ceSopenharmony_ci return; 51348f512ceSopenharmony_ci } 51448f512ceSopenharmony_ci } 51548f512ceSopenharmony_ci if (fprintf(output_, "\n") < 0) { 51648f512ceSopenharmony_ci return; 51748f512ceSopenharmony_ci } 51848f512ceSopenharmony_ci} 51948f512ceSopenharmony_ci 52048f512ceSopenharmony_civoid Report::OutputStdItemHeating(float heat, float heat2) 52148f512ceSopenharmony_ci{ 52248f512ceSopenharmony_ci if (heat == heat2 and heat == 0.0f) { 52348f512ceSopenharmony_ci fprintf(output_, "something error , all it is end.\n"); 52448f512ceSopenharmony_ci } else if (heat2 == 0) { 52548f512ceSopenharmony_ci // only have first 52648f512ceSopenharmony_ci fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); 52748f512ceSopenharmony_ci fprintf(output_, "%*s ", FULL_PERCENTAGE_DIFF_LEN, ""); 52848f512ceSopenharmony_ci } else if (heat == 0) { 52948f512ceSopenharmony_ci // only have second 53048f512ceSopenharmony_ci fprintf(output_, "%*s ", FULL_PERCENTAGE_LEN, ""); 53148f512ceSopenharmony_ci fprintf(output_, "%+*.2f%% ", FULL_PERCENTAGE_DIFF_NUM_LEN, heat2); 53248f512ceSopenharmony_ci } else if (heat2 > heat) { 53348f512ceSopenharmony_ci fprintf(output_, "%s%*.2f%%%s ", TEXT_RED.c_str(), FULL_PERCENTAGE_NUM_LEN, heat, 53448f512ceSopenharmony_ci TEXT_RESET.c_str()); 53548f512ceSopenharmony_ci fprintf(output_, "%s%+*.2f%%%s ", TEXT_GREEN.c_str(), FULL_PERCENTAGE_DIFF_NUM_LEN, 53648f512ceSopenharmony_ci heat2 - heat, TEXT_RESET.c_str()); 53748f512ceSopenharmony_ci } else if (heat2 < heat) { 53848f512ceSopenharmony_ci fprintf(output_, "%s%*.2f%%%s ", TEXT_GREEN.c_str(), FULL_PERCENTAGE_NUM_LEN, heat, 53948f512ceSopenharmony_ci TEXT_RESET.c_str()); 54048f512ceSopenharmony_ci fprintf(output_, "%s%+*.2f%%%s ", TEXT_RED.c_str(), FULL_PERCENTAGE_DIFF_NUM_LEN, 54148f512ceSopenharmony_ci heat2 - heat, TEXT_RESET.c_str()); 54248f512ceSopenharmony_ci } else { 54348f512ceSopenharmony_ci // same heating 54448f512ceSopenharmony_ci fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); 54548f512ceSopenharmony_ci fprintf(output_, "%+*.2f%% ", FULL_PERCENTAGE_DIFF_NUM_LEN, heat2 - heat); 54648f512ceSopenharmony_ci } 54748f512ceSopenharmony_ci} 54848f512ceSopenharmony_ci 54948f512ceSopenharmony_civoid Report::OutputStdContentDiff(ReportEventConfigItem &left, ReportEventConfigItem &right) 55048f512ceSopenharmony_ci{ 55148f512ceSopenharmony_ci // first we need found the match config 55248f512ceSopenharmony_ci HLOGD("first count %zu second count %zu", left.reportItems_.size(), right.reportItems_.size()); 55348f512ceSopenharmony_ci ReportItemsConstIt it = left.reportItems_.begin(); 55448f512ceSopenharmony_ci ReportItemsConstIt it2 = right.reportItems_.begin(); 55548f512ceSopenharmony_ci while (it != left.reportItems_.end()) { 55648f512ceSopenharmony_ci // still have it2 ? 55748f512ceSopenharmony_ci if (it2 != right.reportItems_.end()) { 55848f512ceSopenharmony_ci // find the same item in it2 by same sort key 55948f512ceSopenharmony_ci while (it2 != right.reportItems_.end()) { 56048f512ceSopenharmony_ci if (MultiLevelSame(*it, *it2)) { 56148f512ceSopenharmony_ci // we found the same item 56248f512ceSopenharmony_ci // output the diff heating 56348f512ceSopenharmony_ci if (it->heat > option_.heatLimit_ and it2->heat > option_.heatLimit_) { 56448f512ceSopenharmony_ci OutputStdItemHeating(it->heat, it2->heat); 56548f512ceSopenharmony_ci OutputStdContentItem(*it); 56648f512ceSopenharmony_ci } 56748f512ceSopenharmony_ci it++; 56848f512ceSopenharmony_ci it2++; 56948f512ceSopenharmony_ci break; // next it 57048f512ceSopenharmony_ci } else { 57148f512ceSopenharmony_ci // only print it2 item 57248f512ceSopenharmony_ci if (it2->heat > option_.heatLimit_) { 57348f512ceSopenharmony_ci OutputStdItemHeating(0.0f, it2->heat); 57448f512ceSopenharmony_ci OutputStdContentItem(*it2); 57548f512ceSopenharmony_ci } 57648f512ceSopenharmony_ci it2++; 57748f512ceSopenharmony_ci continue; // next it2 57848f512ceSopenharmony_ci } 57948f512ceSopenharmony_ci } 58048f512ceSopenharmony_ci } else { 58148f512ceSopenharmony_ci // no more it2, go on print all the it 58248f512ceSopenharmony_ci if (it->heat > option_.heatLimit_) { 58348f512ceSopenharmony_ci OutputStdItemHeating(it->heat, 0.0f); 58448f512ceSopenharmony_ci OutputStdContentItem(*it); 58548f512ceSopenharmony_ci } 58648f512ceSopenharmony_ci it++; 58748f512ceSopenharmony_ci continue; // next it 58848f512ceSopenharmony_ci } 58948f512ceSopenharmony_ci } 59048f512ceSopenharmony_ci while (it2 != right.reportItems_.end()) { 59148f512ceSopenharmony_ci // if diff still have some item in it2 ,print it 59248f512ceSopenharmony_ci OutputStdItemHeating(0, it2->heat); 59348f512ceSopenharmony_ci OutputStdContentItem(*it2); 59448f512ceSopenharmony_ci it2++; 59548f512ceSopenharmony_ci } 59648f512ceSopenharmony_ci} 59748f512ceSopenharmony_ci 59848f512ceSopenharmony_civoid Report::OutputStd(FILE *output) 59948f512ceSopenharmony_ci{ 60048f512ceSopenharmony_ci output_ = output; 60148f512ceSopenharmony_ci PrepareConsole(); 60248f512ceSopenharmony_ci 60348f512ceSopenharmony_ci for (auto &config : configs_) { 60448f512ceSopenharmony_ci OutputStdStatistics(config); 60548f512ceSopenharmony_ci OutputStdHead(config); 60648f512ceSopenharmony_ci OutputStdContent(config); 60748f512ceSopenharmony_ci } 60848f512ceSopenharmony_ci} 60948f512ceSopenharmony_ci 61048f512ceSopenharmony_civoid Report::OutputStdDiff(FILE *output, Report &other) 61148f512ceSopenharmony_ci{ 61248f512ceSopenharmony_ci output_ = output; 61348f512ceSopenharmony_ci PrepareConsole(); 61448f512ceSopenharmony_ci 61548f512ceSopenharmony_ci auto left = configs_.begin(); 61648f512ceSopenharmony_ci while (left != configs_.end()) { 61748f512ceSopenharmony_ci auto right = other.configs_.begin(); 61848f512ceSopenharmony_ci while (right != other.configs_.end()) { 61948f512ceSopenharmony_ci if (*left == *right) { 62048f512ceSopenharmony_ci OutputStdStatistics(*left); 62148f512ceSopenharmony_ci OutputStdHead(*left, true); 62248f512ceSopenharmony_ci OutputStdContentDiff(*left, *right); 62348f512ceSopenharmony_ci break; // check next left 62448f512ceSopenharmony_ci } 62548f512ceSopenharmony_ci right++; 62648f512ceSopenharmony_ci } 62748f512ceSopenharmony_ci left++; // go on left 62848f512ceSopenharmony_ci } 62948f512ceSopenharmony_ci} 63048f512ceSopenharmony_ci} // namespace HiPerf 63148f512ceSopenharmony_ci} // namespace Developtools 63248f512ceSopenharmony_ci} // namespace OHOS 633