1/* 2 * Copyright (c) 2023 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 16#include "ecmascript/dfx/vmstat/function_call_timer.h" 17 18#include <iomanip> 19 20namespace panda::ecmascript { 21void FunctionCallTimer::StartCount(size_t id, bool isAot) 22{ 23 PandaRuntimeTimer *callerTimer = currentTimer_; 24 auto calleeTimer = &callTimer_[id]; 25 if (callerTimer != nullptr) { 26 calleeTimer->SetParent(callerTimer); 27 } 28 currentTimer_ = calleeTimer; 29 FunctionCallStat *calleeStat = nullptr; 30 if (isAot) { 31 calleeStat = &aotCallStat_[id]; 32 } else { 33 calleeStat = &intCallStat_[id]; 34 } 35 calleeTimer->Start(calleeStat, callerTimer); 36} 37 38void FunctionCallTimer::StopCount(Method *method) 39{ 40 size_t id = method->GetMethodId().GetOffset(); 41 auto callee = &callTimer_[id]; 42 if (callee != currentTimer_) { 43 LOG_ECMA(INFO) << "EndCallTimer and StartCallTimer have different functions. Current function: " 44 << GetFullName(method) << "has been skipped"; 45 return; 46 } 47 48 PandaRuntimeTimer *callerTimer = callee->Stop(); 49 currentTimer_ = callerTimer; 50} 51 52CString FunctionCallTimer::GetFullName(Method *method) 53{ 54 CString funcName(method->GetMethodName()); 55 CString recordName = method->GetRecordNameStr(); 56 CString fullName = funcName + "@" + recordName; 57 return fullName; 58} 59 60void FunctionCallTimer::InitialStatAndTimer(Method *method, size_t methodId, bool isAot) 61{ 62 if (isAot) { 63 auto iter = aotCallStat_.find(methodId); 64 if (iter == aotCallStat_.end()) { 65 CString funcName = GetFullName(method); 66 FunctionCallStat stat(funcName, isAot); 67 aotCallStat_[methodId] = stat; 68 } 69 } else { 70 auto iter = intCallStat_.find(methodId); 71 if (iter == intCallStat_.end()) { 72 CString funcName = GetFullName(method); 73 FunctionCallStat stat(funcName, isAot); 74 intCallStat_[methodId] = stat; 75 } 76 } 77 78 PandaRuntimeTimer timer; 79 callTimer_[methodId] = timer; 80} 81 82void FunctionCallTimer::PrintAllStats() 83{ 84 LOG_ECMA(INFO) << "function call stat:"; 85 static constexpr int nameRightAdjustment = 45; 86 static constexpr int numberRightAdjustment = 15; 87 LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "JS && TS Function Name" 88 << std::setw(numberRightAdjustment) << "Type" 89 << std::setw(numberRightAdjustment) << "Time(ns)" << std::setw(numberRightAdjustment) << "Count" 90 << std::setw(numberRightAdjustment) << "MaxTime(ns)" 91 << std::setw(numberRightAdjustment) << "AvgTime(ns)"; 92 LOG_ECMA(INFO) << "=============================================================" 93 << "============================================================="; 94 95 CVector<FunctionCallStat> callStatVec; 96 for (auto &stat : aotCallStat_) { 97 callStatVec.emplace_back(stat.second); 98 } 99 for (auto &stat : intCallStat_) { 100 callStatVec.emplace_back(stat.second); 101 } 102 // Sort by TotalTime 103 std::sort(callStatVec.begin(), callStatVec.end(), 104 [](const FunctionCallStat &a, const FunctionCallStat &b) -> bool { 105 return a.TotalTime() > b.TotalTime(); 106 }); 107 108 for (auto &stat : callStatVec) { 109 if (stat.TotalCount() != 0) { 110 CString type = stat.IsAot() ? "Aot" : "Interpreter"; 111 LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << stat.Name() 112 << std::setw(numberRightAdjustment) << type 113 << std::setw(numberRightAdjustment) << stat.TotalTime() 114 << std::setw(numberRightAdjustment) << stat.TotalCount() 115 << std::setw(numberRightAdjustment) << stat.MaxTime() 116 << std::setw(numberRightAdjustment) << stat.TotalTime() / stat.TotalCount(); 117 } 118 } 119} 120 121void FunctionCallTimer::ResetStat() 122{ 123 for (auto &stat : aotCallStat_) { 124 stat.second.Reset(); 125 } 126 127 for (auto &stat : intCallStat_) { 128 stat.second.Reset(); 129 } 130} 131}