• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "ecmascript/dfx/vmstat/opt_code_profiler.h"
17 
18 #include "ecmascript/js_function.h"
19 #include "ecmascript/jspandafile/js_pandafile.h"
20 
21 namespace panda::ecmascript {
22 using EcmaOpcode = kungfu::EcmaOpcode;
23 
PrintAndReset()24 void OptCodeProfiler::PrintAndReset()
25 {
26 #if ECMASCRIPT_ENABLE_OPT_CODE_PROFILER
27     std::vector<std::pair<EcmaOpcode, Value>> profVec;
28     for (auto it = profMap_.begin(); it != profMap_.end(); it++) {
29         profVec.emplace_back(std::make_pair(it->first, it->second));
30         it->second.ResetStat();
31     }
32     std::sort(profVec.begin(), profVec.end(),
33               [](std::pair<EcmaOpcode, Value> &x, std::pair<EcmaOpcode, Value> &y) -> bool {
34                   return x.second.Count() > y.second.Count();
35               });
36 
37     LOG_ECMA(INFO) << "Runtime Statistics of optimized code path:";
38     static constexpr int nameRightAdjustment = 46;
39     static constexpr int numberRightAdjustment = 15;
40     static constexpr int hundred = 100;
41     LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Bytecode"
42                    << std::setw(numberRightAdjustment) << "bcIndex"
43                    << std::setw(numberRightAdjustment) << "Count"
44                    << std::setw(numberRightAdjustment) << "TypedPathCount"
45                    << std::setw(numberRightAdjustment) << "SlowPathCount"
46                    << std::setw(numberRightAdjustment + 1) << "TypedPathRate";
47     LOG_ECMA(INFO) << "============================================================"
48                    << "=========================================================";
49 
50     uint64_t totalCount = 0;
51     uint64_t totalTypedPathCount = 0;
52     uint64_t totalSlowPathCount = 0;
53 
54     for (auto it = profVec.begin(); it != profVec.end(); it++) {
55         Value val = it->second;
56         if (val.Count() == 0) {
57             break;
58         }
59 
60         LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << kungfu::GetEcmaOpcodeStr(it->first)
61                        << std::setw(numberRightAdjustment) << "NA"
62                        << std::setw(numberRightAdjustment) << val.Count()
63                        << std::setw(numberRightAdjustment) << val.TypedPathCount()
64                        << std::setw(numberRightAdjustment) << val.SlowPathCount()
65                        << std::setw(numberRightAdjustment) << val.TypedPathCount() * hundred / val.Count() << "%";
66 
67         totalCount += val.Count();
68         totalTypedPathCount += val.TypedPathCount();
69         totalSlowPathCount += val.SlowPathCount();
70     }
71 
72     if (totalCount != 0) {
73         LOG_ECMA(INFO) << "------------------------------------------------------------"
74                        << "---------------------------------------------------------";
75         LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Total"
76                        << std::setw(numberRightAdjustment) << "NA"
77                        << std::setw(numberRightAdjustment) << totalCount
78                        << std::setw(numberRightAdjustment) << totalTypedPathCount
79                        << std::setw(numberRightAdjustment) << totalSlowPathCount
80                        << std::setw(numberRightAdjustment) << totalTypedPathCount * hundred / totalCount << "%";
81     }
82 
83     FilterMethodToPrint();
84     ResetMethodInfo();
85 #endif
86 }
87 
FilterMethodToPrint()88 void OptCodeProfiler::FilterMethodToPrint()
89 {
90 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
91     std::vector<CString> methods;
92     auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
93     for (auto it = profMap.begin(); it != profMap.end();) {
94         if (it->second == false) {
95             methods.push_back(it->first);
96             profMap.erase(it++);
97         } else {
98             it++;
99         }
100     }
101     for (auto &methodName : methods) {
102         if (methodName.find("func_main_") != methodName.npos) {
103             continue;
104         }
105         LOG_ECMA(ERROR) << methodName << " has not been fully jit warmed up.";
106     }
107 #endif
108     std::vector<std::pair<uint64_t, Name>> profVec;
109     for (auto it = methodIdToName_.begin(); it != methodIdToName_.end(); it++) {
110         profVec.emplace_back(std::make_pair(it->first, it->second));
111     }
112     std::sort(profVec.begin(), profVec.end(),
113               [](std::pair<uint64_t, Name> &x, std::pair<uint64_t, Name> &y) -> bool {
114                   return x.second.Count() > y.second.Count();
115               });
116 
117     auto itr = profVec.begin();
118 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
119     while (itr != profVec.end()) {
120 #else
121     for (int i = 0; i < printMehodCount_ && itr != profVec.end(); i++) {
122 #endif
123         PrintMethodRecord(itr->first, itr->second.GetName());
124         itr++;
125     }
126 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
127     if (profMap.size() != 0) {
128         for (auto it = profMap.begin(); it != profMap.end(); it++) {
129             if (it->first.find("func_main_") != it->first.npos) {
130                 continue;
131             }
132             LOG_ECMA(ERROR) << "There exists compiled function " << it->first
133                             << ", but it has not been jit executed, please "
134                                "warm up strongly.";
135         }
136     }
137 #endif
138 }
139 
140 void OptCodeProfiler::PrintMethodRecord(Key key, std::string methodName)
141 {
142 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
143     CString methodInfo = abcNames_[key.GetAbcId()] + ":" + CString(methodName);
144     auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
145     if (profMap.find(methodInfo) != profMap.end()) {
146         profMap.erase(methodInfo);
147     }
148 #endif
149     LOG_ECMA(INFO) << "==== methodId: " << key.GetMethodId()
150                    << ", methodName: " << methodName.c_str()
151                    << ", abcName: " << abcNames_[key.GetAbcId()] << " ====";
152 
153     static constexpr int nameRightAdjustment = 46;
154     static constexpr int numberRightAdjustment = 15;
155     static constexpr int hundred = 100;
156     BcRecord& bcRecord = methodIdToRecord_[key.Value()];
157     for (auto it = bcRecord.begin(); it != bcRecord.end(); it++) {
158         Record record = it->second;
159 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER == 0
160         if (record.Count() == 0) {
161             break;
162         }
163 #endif
164 
165         LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << kungfu::GetEcmaOpcodeStr(record.GetOpCode())
166                        << std::setw(numberRightAdjustment) << it->first
167                        << std::setw(numberRightAdjustment) << record.Count()
168                        << std::setw(numberRightAdjustment) << record.GetFast()
169                        << std::setw(numberRightAdjustment) << record.GetSlow()
170                        << std::setw(numberRightAdjustment) << record.GetFast() * hundred / record.Count() << "%";
171     }
172 }
173 
174 void OptCodeProfiler::Update(JSThread *thread, JSHandle<JSTaggedValue> &func, int bcIndex,
175                              EcmaOpcode opcode, Mode mode)
176 {
177     auto it = profMap_.find(opcode);
178     if (it != profMap_.end()) {
179         (mode == Mode::TYPED_PATH) ? (it->second.typedPathValue++) : (it->second.slowPathValue++);
180     }
181 
182     if (func->IsUndefined()) {
183         return;
184     }
185 
186     // methodId & methodName
187     auto funcPoint = JSFunction::Cast(func->GetTaggedObject());
188     auto method = funcPoint->GetMethod(thread);
189     if (!method.IsMethod()) {
190         return;
191     }
192     auto methodPoint = Method::Cast(method);
193     auto methodId = methodPoint->GetMethodId().GetOffset();
194     auto methodName =
195         ConvertToStdString(methodPoint->GetRecordNameStr(thread)) + "." + methodPoint->GetMethodName(thread);
196 
197     const auto *pf = methodPoint->GetJSPandaFile(thread);
198     ASSERT(pf != nullptr);
199     auto pfName = pf->GetJSPandaFileDesc();
200     auto itr = std::find(abcNames_.begin(), abcNames_.end(), pfName);
201     uint32_t index = 0;
202     if (itr != abcNames_.end()) {
203         index = static_cast<uint32_t>(std::distance(abcNames_.begin(), itr));
204     } else {
205         index = abcNames_.size();
206         abcNames_.emplace_back(pfName);
207     }
208 
209     Key key(index, methodId);
210     // deal methodIdToName
211     auto result = methodIdToName_.find(key.Value());
212     if (result != methodIdToName_.end()) {
213         result->second.Inc();
214     } else {
215         methodIdToName_.emplace(key.Value(), Name(methodName));
216     }
217 
218     // deal methodIdToRecord_
219     auto result2 = methodIdToRecord_.find(key.Value());
220     if (result2 == methodIdToRecord_.end()) {
221         BcRecord bcRecord;
222         bcRecord.emplace(bcIndex, Record(opcode));
223         methodIdToRecord_.emplace(key.Value(), bcRecord);
224     }
225     result2 = methodIdToRecord_.find(key.Value());
226 
227     auto result3 = result2->second.find(bcIndex);
228     if (result3 != result2->second.end()) {
229         (mode == Mode::TYPED_PATH) ? (result3->second.IncFast()) : (result3->second.IncSlow());
230     } else {
231         auto record = Record(opcode);
232         (mode == Mode::TYPED_PATH) ? (record.IncFast()) : (record.IncSlow());
233         result2->second.emplace(bcIndex, record);
234     }
235 }
236 
237 OptCodeProfiler::~OptCodeProfiler()
238 {
239     PrintAndReset();
240 }
241 } // namespace panda::ecmascript
242