14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/dfx/vmstat/opt_code_profiler.h" 174514f5e3Sopenharmony_ci#include <iomanip> 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 204514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile.h" 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_cinamespace panda::ecmascript { 234514f5e3Sopenharmony_ciusing EcmaOpcode = kungfu::EcmaOpcode; 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_civoid OptCodeProfiler::PrintAndReset() 264514f5e3Sopenharmony_ci{ 274514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_OPT_CODE_PROFILER 284514f5e3Sopenharmony_ci std::vector<std::pair<EcmaOpcode, Value>> profVec; 294514f5e3Sopenharmony_ci for (auto it = profMap_.begin(); it != profMap_.end(); it++) { 304514f5e3Sopenharmony_ci profVec.emplace_back(std::make_pair(it->first, it->second)); 314514f5e3Sopenharmony_ci it->second.ResetStat(); 324514f5e3Sopenharmony_ci } 334514f5e3Sopenharmony_ci std::sort(profVec.begin(), profVec.end(), 344514f5e3Sopenharmony_ci [](std::pair<EcmaOpcode, Value> &x, std::pair<EcmaOpcode, Value> &y) -> bool { 354514f5e3Sopenharmony_ci return x.second.Count() > y.second.Count(); 364514f5e3Sopenharmony_ci }); 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "Runtime Statistics of optimized code path:"; 394514f5e3Sopenharmony_ci static constexpr int nameRightAdjustment = 46; 404514f5e3Sopenharmony_ci static constexpr int numberRightAdjustment = 15; 414514f5e3Sopenharmony_ci static constexpr int hundred = 100; 424514f5e3Sopenharmony_ci LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Bytecode" 434514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "bcIndex" 444514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "Count" 454514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "TypedPathCount" 464514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "SlowPathCount" 474514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment + 1) << "TypedPathRate"; 484514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "============================================================" 494514f5e3Sopenharmony_ci << "========================================================="; 504514f5e3Sopenharmony_ci 514514f5e3Sopenharmony_ci uint64_t totalCount = 0; 524514f5e3Sopenharmony_ci uint64_t totalTypedPathCount = 0; 534514f5e3Sopenharmony_ci uint64_t totalSlowPathCount = 0; 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ci for (auto it = profVec.begin(); it != profVec.end(); it++) { 564514f5e3Sopenharmony_ci Value val = it->second; 574514f5e3Sopenharmony_ci if (val.Count() == 0) { 584514f5e3Sopenharmony_ci break; 594514f5e3Sopenharmony_ci } 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ci LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << kungfu::GetEcmaOpcodeStr(it->first) 624514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "NA" 634514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << val.Count() 644514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << val.TypedPathCount() 654514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << val.SlowPathCount() 664514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << val.TypedPathCount() * hundred / val.Count() << "%"; 674514f5e3Sopenharmony_ci 684514f5e3Sopenharmony_ci totalCount += val.Count(); 694514f5e3Sopenharmony_ci totalTypedPathCount += val.TypedPathCount(); 704514f5e3Sopenharmony_ci totalSlowPathCount += val.SlowPathCount(); 714514f5e3Sopenharmony_ci } 724514f5e3Sopenharmony_ci 734514f5e3Sopenharmony_ci if (totalCount != 0) { 744514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "------------------------------------------------------------" 754514f5e3Sopenharmony_ci << "---------------------------------------------------------"; 764514f5e3Sopenharmony_ci LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << "Total" 774514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << "NA" 784514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << totalCount 794514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << totalTypedPathCount 804514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << totalSlowPathCount 814514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << totalTypedPathCount * hundred / totalCount << "%"; 824514f5e3Sopenharmony_ci } 834514f5e3Sopenharmony_ci 844514f5e3Sopenharmony_ci FilterMethodToPrint(); 854514f5e3Sopenharmony_ci ResetMethodInfo(); 864514f5e3Sopenharmony_ci#endif 874514f5e3Sopenharmony_ci} 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_civoid OptCodeProfiler::FilterMethodToPrint() 904514f5e3Sopenharmony_ci{ 914514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER 924514f5e3Sopenharmony_ci std::vector<CString> methods; 934514f5e3Sopenharmony_ci auto &profMap = JitWarmupProfiler::GetInstance()->profMap_; 944514f5e3Sopenharmony_ci for (auto it = profMap.begin(); it != profMap.end();) { 954514f5e3Sopenharmony_ci if (it->second == false) { 964514f5e3Sopenharmony_ci methods.push_back(it->first); 974514f5e3Sopenharmony_ci profMap.erase(it++); 984514f5e3Sopenharmony_ci } else { 994514f5e3Sopenharmony_ci it++; 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci for (auto &methodName : methods) { 1034514f5e3Sopenharmony_ci if (methodName.find("func_main_") != methodName.npos) { 1044514f5e3Sopenharmony_ci continue; 1054514f5e3Sopenharmony_ci } 1064514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << methodName << " has not been fully jit warmed up."; 1074514f5e3Sopenharmony_ci } 1084514f5e3Sopenharmony_ci#endif 1094514f5e3Sopenharmony_ci std::vector<std::pair<uint64_t, Name>> profVec; 1104514f5e3Sopenharmony_ci for (auto it = methodIdToName_.begin(); it != methodIdToName_.end(); it++) { 1114514f5e3Sopenharmony_ci profVec.emplace_back(std::make_pair(it->first, it->second)); 1124514f5e3Sopenharmony_ci } 1134514f5e3Sopenharmony_ci std::sort(profVec.begin(), profVec.end(), 1144514f5e3Sopenharmony_ci [](std::pair<uint64_t, Name> &x, std::pair<uint64_t, Name> &y) -> bool { 1154514f5e3Sopenharmony_ci return x.second.Count() > y.second.Count(); 1164514f5e3Sopenharmony_ci }); 1174514f5e3Sopenharmony_ci 1184514f5e3Sopenharmony_ci auto itr = profVec.begin(); 1194514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER 1204514f5e3Sopenharmony_ci while (itr != profVec.end()) { 1214514f5e3Sopenharmony_ci#else 1224514f5e3Sopenharmony_ci for (int i = 0; i < printMehodCount_ && itr != profVec.end(); i++) { 1234514f5e3Sopenharmony_ci#endif 1244514f5e3Sopenharmony_ci PrintMethodRecord(itr->first, itr->second.GetName()); 1254514f5e3Sopenharmony_ci itr++; 1264514f5e3Sopenharmony_ci } 1274514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER 1284514f5e3Sopenharmony_ci if (profMap.size() != 0) { 1294514f5e3Sopenharmony_ci for (auto it = profMap.begin(); it != profMap.end(); it++) { 1304514f5e3Sopenharmony_ci if (it->first.find("func_main_") != it->first.npos) { 1314514f5e3Sopenharmony_ci continue; 1324514f5e3Sopenharmony_ci } 1334514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "There exists compiled function " << it->first 1344514f5e3Sopenharmony_ci << ", but it has not been jit executed, please " 1354514f5e3Sopenharmony_ci "warm up strongly."; 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci } 1384514f5e3Sopenharmony_ci#endif 1394514f5e3Sopenharmony_ci} 1404514f5e3Sopenharmony_ci 1414514f5e3Sopenharmony_civoid OptCodeProfiler::PrintMethodRecord(Key key, std::string methodName) 1424514f5e3Sopenharmony_ci{ 1434514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER 1444514f5e3Sopenharmony_ci CString methodInfo = abcNames_[key.GetAbcId()] + ":" + CString(methodName); 1454514f5e3Sopenharmony_ci auto &profMap = JitWarmupProfiler::GetInstance()->profMap_; 1464514f5e3Sopenharmony_ci if (profMap.find(methodInfo) != profMap.end()) { 1474514f5e3Sopenharmony_ci profMap.erase(methodInfo); 1484514f5e3Sopenharmony_ci } 1494514f5e3Sopenharmony_ci#endif 1504514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "==== methodId: " << key.GetMethodId() 1514514f5e3Sopenharmony_ci << ", methodName: " << methodName.c_str() 1524514f5e3Sopenharmony_ci << ", abcName: " << abcNames_[key.GetAbcId()] << " ===="; 1534514f5e3Sopenharmony_ci 1544514f5e3Sopenharmony_ci static constexpr int nameRightAdjustment = 46; 1554514f5e3Sopenharmony_ci static constexpr int numberRightAdjustment = 15; 1564514f5e3Sopenharmony_ci static constexpr int hundred = 100; 1574514f5e3Sopenharmony_ci BcRecord& bcRecord = methodIdToRecord_[key.Value()]; 1584514f5e3Sopenharmony_ci for (auto it = bcRecord.begin(); it != bcRecord.end(); it++) { 1594514f5e3Sopenharmony_ci Record record = it->second; 1604514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER == 0 1614514f5e3Sopenharmony_ci if (record.Count() == 0) { 1624514f5e3Sopenharmony_ci break; 1634514f5e3Sopenharmony_ci } 1644514f5e3Sopenharmony_ci#endif 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci LOG_ECMA(INFO) << std::right << std::setw(nameRightAdjustment) << kungfu::GetEcmaOpcodeStr(record.GetOpCode()) 1674514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << it->first 1684514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << record.Count() 1694514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << record.GetFast() 1704514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << record.GetSlow() 1714514f5e3Sopenharmony_ci << std::setw(numberRightAdjustment) << record.GetFast() * hundred / record.Count() << "%"; 1724514f5e3Sopenharmony_ci } 1734514f5e3Sopenharmony_ci} 1744514f5e3Sopenharmony_ci 1754514f5e3Sopenharmony_civoid OptCodeProfiler::Update(JSHandle<JSTaggedValue> &func, int bcIndex, EcmaOpcode opcode, Mode mode) 1764514f5e3Sopenharmony_ci{ 1774514f5e3Sopenharmony_ci auto it = profMap_.find(opcode); 1784514f5e3Sopenharmony_ci if (it != profMap_.end()) { 1794514f5e3Sopenharmony_ci (mode == Mode::TYPED_PATH) ? (it->second.typedPathValue++) : (it->second.slowPathValue++); 1804514f5e3Sopenharmony_ci } 1814514f5e3Sopenharmony_ci 1824514f5e3Sopenharmony_ci if (func->IsUndefined()) { 1834514f5e3Sopenharmony_ci return; 1844514f5e3Sopenharmony_ci } 1854514f5e3Sopenharmony_ci 1864514f5e3Sopenharmony_ci // methodId & methodName 1874514f5e3Sopenharmony_ci auto funcPoint = JSFunction::Cast(func->GetTaggedObject()); 1884514f5e3Sopenharmony_ci auto method = funcPoint->GetMethod(); 1894514f5e3Sopenharmony_ci if (!method.IsMethod()) { 1904514f5e3Sopenharmony_ci return; 1914514f5e3Sopenharmony_ci } 1924514f5e3Sopenharmony_ci auto methodPoint = Method::Cast(method); 1934514f5e3Sopenharmony_ci auto methodId = methodPoint->GetMethodId().GetOffset(); 1944514f5e3Sopenharmony_ci auto methodName = ConvertToStdString(methodPoint->GetRecordNameStr()) + "." + methodPoint->GetMethodName(); 1954514f5e3Sopenharmony_ci 1964514f5e3Sopenharmony_ci const auto *pf = methodPoint->GetJSPandaFile(); 1974514f5e3Sopenharmony_ci ASSERT(pf != nullptr); 1984514f5e3Sopenharmony_ci auto pfName = pf->GetJSPandaFileDesc(); 1994514f5e3Sopenharmony_ci auto itr = std::find(abcNames_.begin(), abcNames_.end(), pfName); 2004514f5e3Sopenharmony_ci uint32_t index = 0; 2014514f5e3Sopenharmony_ci if (itr != abcNames_.end()) { 2024514f5e3Sopenharmony_ci index = static_cast<uint32_t>(std::distance(abcNames_.begin(), itr)); 2034514f5e3Sopenharmony_ci } else { 2044514f5e3Sopenharmony_ci index = abcNames_.size(); 2054514f5e3Sopenharmony_ci abcNames_.emplace_back(pfName); 2064514f5e3Sopenharmony_ci } 2074514f5e3Sopenharmony_ci 2084514f5e3Sopenharmony_ci Key key(index, methodId); 2094514f5e3Sopenharmony_ci // deal methodIdToName 2104514f5e3Sopenharmony_ci auto result = methodIdToName_.find(key.Value()); 2114514f5e3Sopenharmony_ci if (result != methodIdToName_.end()) { 2124514f5e3Sopenharmony_ci result->second.Inc(); 2134514f5e3Sopenharmony_ci } else { 2144514f5e3Sopenharmony_ci methodIdToName_.emplace(key.Value(), Name(methodName)); 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci 2174514f5e3Sopenharmony_ci // deal methodIdToRecord_ 2184514f5e3Sopenharmony_ci auto result2 = methodIdToRecord_.find(key.Value()); 2194514f5e3Sopenharmony_ci if (result2 == methodIdToRecord_.end()) { 2204514f5e3Sopenharmony_ci BcRecord bcRecord; 2214514f5e3Sopenharmony_ci bcRecord.emplace(bcIndex, Record(opcode)); 2224514f5e3Sopenharmony_ci methodIdToRecord_.emplace(key.Value(), bcRecord); 2234514f5e3Sopenharmony_ci } 2244514f5e3Sopenharmony_ci result2 = methodIdToRecord_.find(key.Value()); 2254514f5e3Sopenharmony_ci 2264514f5e3Sopenharmony_ci auto result3 = result2->second.find(bcIndex); 2274514f5e3Sopenharmony_ci if (result3 != result2->second.end()) { 2284514f5e3Sopenharmony_ci (mode == Mode::TYPED_PATH) ? (result3->second.IncFast()) : (result3->second.IncSlow()); 2294514f5e3Sopenharmony_ci } else { 2304514f5e3Sopenharmony_ci auto record = Record(opcode); 2314514f5e3Sopenharmony_ci (mode == Mode::TYPED_PATH) ? (record.IncFast()) : (record.IncSlow()); 2324514f5e3Sopenharmony_ci result2->second.emplace(bcIndex, record); 2334514f5e3Sopenharmony_ci } 2344514f5e3Sopenharmony_ci} 2354514f5e3Sopenharmony_ci 2364514f5e3Sopenharmony_ciOptCodeProfiler::~OptCodeProfiler() 2374514f5e3Sopenharmony_ci{ 2384514f5e3Sopenharmony_ci PrintAndReset(); 2394514f5e3Sopenharmony_ci} 2404514f5e3Sopenharmony_ci} // namespace panda::ecmascript 241