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
20 namespace panda::ecmascript {
StartCount(size_t id, bool isAot)21 void 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
StopCount(Method *method)38 void 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
GetFullName(Method *method)52 CString 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
InitialStatAndTimer(Method *method, size_t methodId, bool isAot)60 void 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
PrintAllStats()82 void 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
ResetStat()121 void 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 }