1 /*
2  * Copyright (c) 2021-2024 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 <iomanip>
17 
18 #include "ecmascript/runtime_call_id.h"
19 
20 namespace panda::ecmascript {
21 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
EcmaRuntimeStat(const char *const runtimeCallerNames[], int count)22 EcmaRuntimeStat::EcmaRuntimeStat(const char *const runtimeCallerNames[], int count)
23 {
24     for (int i = 0; i < count; i++) {
25         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
26         callerStat_.emplace_back(PandaRuntimeCallerStat(CString(runtimeCallerNames[i])));
27     }
28 }
29 
StartCount(PandaRuntimeTimer *timer, int callerId)30 void EcmaRuntimeStat::StartCount(PandaRuntimeTimer *timer, int callerId)
31 {
32     if (currentTimer_ != nullptr) {
33         timer->SetParent(currentTimer_);
34     }
35     PandaRuntimeTimer *parent = currentTimer_;
36     currentTimer_ = timer;
37     PandaRuntimeCallerStat *callerStat = &callerStat_[callerId];
38     timer->Start(callerStat, parent);
39 }
40 
StopCount(const PandaRuntimeTimer *nowTimer)41 void EcmaRuntimeStat::StopCount(const PandaRuntimeTimer *nowTimer)
42 {
43     if (nowTimer != currentTimer_) {
44         return;
45     }
46     PandaRuntimeTimer *parentTimer = currentTimer_->Stop();
47     currentTimer_ = parentTimer;
48 }
49 
Print() const50 void EcmaRuntimeStat::Print() const
51 {
52     if (currentTimer_ != nullptr) {
53         currentTimer_->Snapshot();
54     }
55     PrintAllStats();
56 }
57 
ResetAllCount()58 void EcmaRuntimeStat::ResetAllCount()
59 {
60     while (currentTimer_ != nullptr) {
61         StopCount(currentTimer_);
62     }
63     for (auto &runCallerStat : callerStat_) {
64         runCallerStat.Reset();
65     }
66 }
67 
PrintAllStats() const68 void EcmaRuntimeStat::PrintAllStats() const
69 {
70     LOG_ECMA(INFO) << "panda runtime stat:";
71     static constexpr int nameRightAdjustment = 45;
72     static constexpr int numberRightAdjustment = 12;
73     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "InterPreter && GC && C++ Builtin Function"
74                        << std::setw(numberRightAdjustment) << "Time(ns)" << std::setw(numberRightAdjustment) << "Count"
75                        << std::setw(numberRightAdjustment) << "MaxTime(ns)"
76                        << std::setw(numberRightAdjustment) << "AvgTime(ns)";
77     LOG_ECMA(INFO) << "============================================================"
78                        << "=========================================================";
79 
80     CVector<PandaRuntimeCallerStat> callerStat;
81     for (auto &runCallerStat : callerStat_) {
82         callerStat.push_back(runCallerStat);
83     }
84     // Sort by TotalTime
85     std::sort(callerStat.begin(), callerStat.end(),
86         [](const PandaRuntimeCallerStat &a, const PandaRuntimeCallerStat &b) -> bool {
87             return a.TotalTime() > b.TotalTime();
88     });
89 
90     uint64_t totalTime = 0;
91     uint64_t interpreterTotalTime = 0;
92     uint64_t builtinTotalTime = 0;
93     uint64_t abstractOperationTotalTime = 0;
94     uint64_t memoryTotalTime = 0;
95     uint64_t runtimeTotalTime = 0;
96     for (auto &runCallerStat : callerStat) {
97         if (runCallerStat.TotalCount() != 0) {
98             totalTime += runCallerStat.TotalTime();
99             CString header = runCallerStat.GetHeaderOfName();
100             if (header == CString("Interpreter")) {
101                 interpreterTotalTime += runCallerStat.TotalTime();
102             } else if (header == CString("BuiltinsApi")) {
103                 builtinTotalTime += runCallerStat.TotalTime();
104             } else if (header == CString("AbstractOperation")) {
105                 abstractOperationTotalTime += runCallerStat.TotalTime();
106             } else if (header == CString("Memory")) {
107                 memoryTotalTime += runCallerStat.TotalTime();
108             } else if (header == CString("Runtime")) {
109                 runtimeTotalTime += runCallerStat.TotalTime();
110             }
111             LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << runCallerStat.Name()
112                                << std::setw(numberRightAdjustment) << runCallerStat.TotalTime()
113                                << std::setw(numberRightAdjustment) << runCallerStat.TotalCount()
114                                << std::setw(numberRightAdjustment) << runCallerStat.MaxTime()
115                                << std::setw(numberRightAdjustment)
116                                << runCallerStat.TotalTime() / runCallerStat.TotalCount();
117         }
118     }
119     LOG_ECMA(INFO) << "------------------------------------------------------------"
120                        << "---------------------------------------------------------";
121     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Interpreter Total Time(ns)"
122                        << std::setw(numberRightAdjustment) << interpreterTotalTime;
123     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "BuiltinsApi Total Time(ns)"
124                        << std::setw(numberRightAdjustment) << builtinTotalTime;
125     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "AbstractOperation Total Time(ns)"
126                        << std::setw(numberRightAdjustment) << abstractOperationTotalTime;
127     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Memory Total Time(ns)"
128                        << std::setw(numberRightAdjustment) << memoryTotalTime;
129     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Runtime Total Time(ns)"
130                        << std::setw(numberRightAdjustment) << runtimeTotalTime;
131     LOG_ECMA(INFO) << "------------------------------------------------------------"
132                        << "---------------------------------------------------------";
133     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Total Time(ns)"
134                        << std::setw(numberRightAdjustment) << totalTime;
135 }
136 
EcmaRuntimeStatScope(EcmaVM *vm)137 EcmaRuntimeStatScope::EcmaRuntimeStatScope(EcmaVM *vm) : vm_(vm)
138 {
139     if (vm_->GetJSOptions().IsEnableRuntimeStat()) {
140         vm_->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(true);
141     }
142 }
143 
~EcmaRuntimeStatScope()144 EcmaRuntimeStatScope::~EcmaRuntimeStatScope()
145 {
146     if (vm_->GetJSOptions().IsEnableRuntimeStat()) {
147         vm_->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(false);
148     }
149     vm_ = nullptr;
150 }
151 }  // namespace panda::ecmascript
152