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