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 }