1/* 2 * Copyright (c) 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/jit/jit_dfx.h" 17#include "ecmascript/runtime.h" 18#include "libpandafile/bytecode_instruction-inl.h" 19#include "libpandafile/code_data_accessor.h" 20#include "libpandafile/class_data_accessor-inl.h" 21#include "ecmascript/platform/file.h" 22 23#ifdef ENABLE_HISYSEVENT 24#include "hisysevent.h" 25#endif 26 27namespace panda::ecmascript { 28JitDfx JitDfx::instance; 29thread_local uint32_t JitDfx::prefixOffset_ = 0; 30class NullStream : public std::ostream { 31public: 32 NullStream() : std::ostream(&buffer_) {} 33 34private: 35 class NullBuffer : public std::streambuf { 36 public: 37 int overflow(int c) override 38 { 39 return c; 40 } 41 }; 42 NullBuffer buffer_; 43}; 44 45JitDfx *JitDfx::GetInstance() 46{ 47 return &instance; 48} 49 50void JitDfx::Init(const JSRuntimeOptions &options, std::string &bundleName) 51{ 52 if (options.IsEnableJitDfxDump()) { 53 EnableDump(); 54 } 55 ResetCompilerTime(); 56 ResetBlockUIEventTime(); 57 SetBundleName(ConvertToString(bundleName)); 58 // main thread 59 SetPidNumber(JSThread::GetCurrentThreadId()); 60} 61 62void JitDfx::EnableDump() 63{ 64 isEnableDump_ = true; 65} 66 67void JitDfx::OpenLogFile(uint32_t threadId) 68{ 69#ifdef PANDA_TARGET_OHOS 70 CString path = CString("/data/storage/ark-profile/jit_dfx_") + ToCString(threadId) + CString(".log"); 71#else 72 CString path = CString("jit_dfx_") + ToCString(threadId) + CString(".log"); 73#endif 74 std::string realOutPath; 75 if (!ecmascript::RealPath(path.c_str(), realOutPath, false)) { 76 return; 77 } 78 logFiles_[threadId].open(realOutPath, std::ios::out); 79} 80 81std::ostream &JitDfx::GetLogFileStream() 82{ 83 if (!isEnableDump_) { 84 static NullStream nullStream_; 85 return nullStream_; 86 } 87 uint32_t threadId = os::thread::GetCurrentThreadId(); 88 auto it = logFiles_.find(threadId); 89 if (it == logFiles_.end()) { 90 OpenLogFile(threadId); 91 } 92 return logFiles_[threadId]; 93} 94 95void JitDfx::DumpBytecodeInst(Method *method) 96{ 97 if (!isEnableDump_) { 98 return; 99 } 100 CString methodInfo = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 101 MethodLiteral *methodLiteral = method->GetMethodLiteral(); 102 auto jsPandaFile = method->GetJSPandaFile(); 103 const panda_file::File *pf = jsPandaFile->GetPandaFile(); 104 ASSERT(methodLiteral != nullptr); 105 panda_file::File::EntityId methodIdx = methodLiteral->GetMethodId(); 106 panda_file::MethodDataAccessor mda(*pf, methodIdx); 107 auto codeId = mda.GetCodeId(); 108 panda_file::CodeDataAccessor codeDataAccessor(*pf, codeId.value()); 109 uint32_t codeSize = codeDataAccessor.GetCodeSize(); 110 const uint8_t *insns = codeDataAccessor.GetInstructions(); 111 112 std::ostringstream ss; 113 ss << "BytecodeInst func:" << methodInfo << "\n"; 114 auto bcIns = BytecodeInst(insns); 115 auto bcInsLast = bcIns.JumpTo(codeSize); 116 while (bcIns.GetAddress() != bcInsLast.GetAddress()) { 117 ss << bcIns << std::endl; 118 auto nextInst = bcIns.GetNext(); 119 bcIns = nextInst; 120 } 121 122 GetLogFileStream() << ss.str() << std::endl; 123} 124 125void JitDfx::TraceJitCode(Method *method, bool isEntry) 126{ 127 if (!isEnableDump_) { 128 return; 129 } 130 if (!isEntry) { 131 prefixOffset_ -= 1; 132 } 133 CString prefixStr = isEntry ? CString("JitCodeEntry:") : CString("JitCodeExit :"); 134 CString methodInfo = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 135 static CString blackSpace(" "); 136 CString prefix; 137 for (uint32_t i = 0; i < prefixOffset_; i++) { 138 prefix += blackSpace; 139 } 140 if (isEntry) { 141 prefixOffset_ += 1; 142 } 143 LOG_JIT(INFO) << prefixStr << prefix << methodInfo; 144} 145 146void JitDfx::PrintJitStatsLog() 147{ 148 if (checkUploadConditions()) { 149 LOG_JIT(DEBUG) << "Jit Compiler stats Log: " 150 << " bundleName: " << GetBundleName() 151 << " pid: " << GetPidNumber() 152 << " total main thread time: " << GetTotalTimeOnMainThread() 153 << " total Jit thread time: " << GetTotalTimeOnJitThread() 154 << " total Baseline Jit times: " << GetTotalBaselineJitCount() 155 << " total Fastopt Jit times: " << GetTotalFastoptJitCount() 156 << " report time interval:" 157 << std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - jitEventParams.start_).count() 158 << " total time on hold lock: " << GetTotalLockHoldingTime() 159 << " max time on hold lock: " << GetMaxLockHoldingTime() 160 << " longtime of hold lock: " << GetLongtimeLockCount() 161 << " JitDeopt times: " << GetJitDeoptCount() 162 << "\n"; 163 SendJitStatsEvent(); 164 InitializeRecord(); 165 } 166} 167 168void JitDfx::SendJitStatsEvent() const 169{ 170#ifdef ENABLE_HISYSEVENT 171 int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME, 172 "ARK_STATS_JIT", 173 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, 174 "BUNDLE_NAME", ConvertToStdString(GetBundleName()), 175 "PID", GetPidNumber(), 176 "TIME_INTERVAL", 177 std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - jitEventParams.start_).count(), 178 "TOTAL_BASELINE_JIT_TIMES", GetTotalBaselineJitCount(), 179 "TOTAL_FASTOPT_JIT_TIMES", GetTotalFastoptJitCount(), 180 "TOTAL_TIME_ON_MAIN_THREAD", GetTotalTimeOnMainThread(), 181 "TOTAL_TIME_ON_JIT_THREAD", GetTotalTimeOnJitThread(), 182 "TOTAL_TIME_ON_HOLD_LOCK", GetTotalLockHoldingTime(), 183 "MAX_TIME_ON_HOLD_LOCK", GetMaxLockHoldingTime(), 184 "LONG_TIME_OF_HOLD_LOCK", GetLongtimeLockCount(), 185 "UNINSTALL_TIME", GetJitDeoptCount()); 186 if (ret != 0) { 187 LOG_JIT(ERROR) << "Jit Compiler Stats send stats event failed! ret = " << ret; 188 } 189#endif 190} 191 192void JitDfx::PrintJitBlockUILog() 193{ 194 std::string jitType = isBaselineJit_ ? "Baseline JIT" : "Fast optimization JIT"; 195 LOG_JIT(DEBUG) << "Jit BlockUI Event Log: " 196 << " bundleName: " << GetBundleName() 197 << " pid: " << GetPidNumber() 198 << " Single main thread time: " << GetSingleTimeOnMainThread() 199 << " Single Jit thread time: " << GetSingleTimeOnJitThread() 200 << " Jit type: " << jitType 201 << " method info: " << GetMethodInfo() 202 << "\n"; 203 SendJitBlockUIEvent(); 204 InitializeBlockUIRecord(); 205} 206 207void JitDfx::SendJitBlockUIEvent() const 208{ 209#ifdef ENABLE_HISYSEVENT 210 std::string jitType = isBaselineJit_ ? "Baseline JIT" : "Fast optimization JIT"; 211 int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME, 212 "ARK_BLOCKUI_JIT", 213 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, 214 "BUNDLE_NAME", ConvertToStdString(GetBundleName()), 215 "PID", GetPidNumber(), 216 "JIT_TYPE", jitType, 217 "JIT_FUNCTION_NAME", ConvertToStdString(GetMethodInfo()), 218 "TIME_ON_MAIN_THREAD", GetSingleTimeOnMainThread(), 219 "TIME_ON_JIT_THREAD", GetSingleTimeOnJitThread()); 220 if (ret != 0) { 221 LOG_JIT(ERROR) << "Jit Compiler Stats send jit blockUI event failed! ret = " << ret; 222 } 223#endif 224} 225 226void JitDfx::InitializeRecord() 227{ 228 jitEventParams.totalBaselineJitTimes_.store(0); 229 jitEventParams.totalFastoptJitTimes_.store(0); 230 jitEventParams.jitDeoptTimes_.store(0); 231 jitEventParams.longtimeLockTimes_.store(0); 232 jitEventParams.totalTimeOnMainThread_.store(0); 233 jitEventParams.totalTimeOnJitThread_.store(0); 234 jitEventParams.totalLockHoldingTime_.store(0); 235 jitEventParams.maxLockHoldingTime_ .store(0); 236 ResetCompilerTime(); 237} 238 239void JitDfx::InitializeBlockUIRecord() 240{ 241 jitEventParams.singleTimeOnMainThread_.store(0); 242 jitEventParams.singleTimeOnJitThread_.store(0); 243 isBaselineJit_ = true; 244 methodInfo_ = ""; 245 ResetBlockUIEventTime(); 246} 247} // namespace panda::ecmascript 248