diff --git a/BUILD.gn b/BUILD.gn index 9cbaf7f7cc..facf6f1cce 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -682,6 +682,7 @@ ecma_source = [ "ecmascript/interpreter/slow_runtime_stub.cpp", "ecmascript/intl/locale_helper.cpp", "ecmascript/jit/jit.cpp", + "ecmascript/jit/jit_dfx.cpp", "ecmascript/jit/jit_task.cpp", "ecmascript/jit/jit_thread.cpp", "ecmascript/jit/jit_profiler.cpp", diff --git a/ecmascript/compiler/file_generators.cpp b/ecmascript/compiler/file_generators.cpp index c43690fbf9..f32fd050cd 100644 --- a/ecmascript/compiler/file_generators.cpp +++ b/ecmascript/compiler/file_generators.cpp @@ -609,6 +609,10 @@ void AOTFileGenerator::GetMemoryCodeInfos(MachineCodeDesc &machineCodeDesc) LOG_COMPILER(WARN) << "error: code size of generated an file is empty!"; return; } + + if (log_->OutputASM()) { + PrintMergedCodeComment(); + } GenerateMergedStackmapSection(); // get func entry Map diff --git a/ecmascript/deoptimizer/deoptimizer.cpp b/ecmascript/deoptimizer/deoptimizer.cpp index 0b9b4d7942..94ac846d46 100644 --- a/ecmascript/deoptimizer/deoptimizer.cpp +++ b/ecmascript/deoptimizer/deoptimizer.cpp @@ -544,6 +544,9 @@ void Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type) method->SetDeoptThreshold(--deoptThreshold); } else { method->ClearAOTStatusWhenDeopt(); + if (func->GetMachineCode().IsMachineCodeObject()) { + Jit::GetInstance()->GetJitDfx()->SetJitDeoptCount(); + } func->SetCodeEntry(reinterpret_cast(nullptr)); } } diff --git a/ecmascript/jit/jit.cpp b/ecmascript/jit/jit.cpp index d1b21f79f8..64af7cbfe5 100644 --- a/ecmascript/jit/jit.cpp +++ b/ecmascript/jit/jit.cpp @@ -70,6 +70,13 @@ void Jit::SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJ isApp_ = options.IsEnableAPPJIT(); initJitCompiler_(options); JitTaskpool::GetCurrentTaskpool()->Initialize(); + + jitDfx_ = JitDfx::GetInstance(); + if (options.IsEnableJitDfxDump()) { + jitDfx_->EnableDump(); + } + jitDfx_->ResetCompilerTime(); + jitDfx_->ResetBlockUIEventTime(); } } } @@ -236,11 +243,14 @@ void Jit::Compile(EcmaVM *vm, JSHandle &jsFunction, CompilerTier tie return; } + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compile"); Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject()); CString fileDesc = method->GetJSPandaFile()->GetJSPandaFileDesc(); CString methodName = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName()); uint32_t codeSize = method->GetCodeSize(); - CString methodInfo = methodName + ", code size:" + ToCString(codeSize); + jit->GetJitDfx()->SetBundleName(vm->GetBundleName()); + jit->GetJitDfx()->SetPidNumber(vm->GetJSThread()->GetThreadId()); + CString methodInfo = methodName + ", bytecode size:" + ToCString(codeSize); constexpr uint32_t maxSize = 9000; if (codeSize > maxSize) { if (tier == CompilerTier::BASELINE) { @@ -251,6 +261,9 @@ void Jit::Compile(EcmaVM *vm, JSHandle &jsFunction, CompilerTier tie return; } + + CString msg = "compile method:" + methodInfo + ", in work thread"; + TimeScope scope(msg, tier); if (vm->GetJSThread()->IsMachineCodeLowMemory()) { if (tier == CompilerTier::BASELINE) { LOG_BASELINEJIT(DEBUG) << "skip jit task, as low code memory:" << methodInfo; @@ -281,18 +294,18 @@ void Jit::Compile(EcmaVM *vm, JSHandle &jsFunction, CompilerTier tie // using hole value to indecate compiling. todo: reset when failed if (tier == CompilerTier::FAST) { jsFunction->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole()); + jit->GetJitDfx()->SetTriggerCount(false); } else { ASSERT(tier == CompilerTier::BASELINE); jsFunction->SetBaselineCode(vm->GetJSThread(), JSTaggedValue::Hole()); + jit->GetJitDfx()->SetTriggerCount(true); } { - CString msg = "compile method:" + methodInfo + ", in work thread"; - TimeScope scope(msg, tier); JitTaskpool::GetCurrentTaskpool()->WaitForJitTaskPoolReady(); EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm(); std::shared_ptr jitTask = std::make_shared(vm->GetJSThread(), compilerVm->GetJSThread(), - jit, jsFunction, tier, methodName, offset, vm->GetJSThread()->GetThreadId(), mode); + jit, jsFunction, tier, methodName, offset, vm->GetJSThread()->GetThreadId(), mode, jit->GetJitDfx()); jitTask->PrepareCompile(); JitTaskpool::GetCurrentTaskpool()->PostTask( @@ -303,6 +316,10 @@ void Jit::Compile(EcmaVM *vm, JSHandle &jsFunction, CompilerTier tie jitTask->WaitFinish(); jitTask->InstallCode(); } + int spendTime = scope.TotalSpentTimeInMicroseconds(); + jitTask->SetMainThreadCompilerTime(spendTime); + jit->GetJitDfx()->SetTotalTimeOnMainThread(spendTime); + jit->GetJitDfx()->PrintJitStatsLog(); } } diff --git a/ecmascript/jit/jit.h b/ecmascript/jit/jit.h index a2fd05a88c..b6ddf2be67 100644 --- a/ecmascript/jit/jit.h +++ b/ecmascript/jit/jit.h @@ -24,6 +24,7 @@ #include "ecmascript/mem/machine_code.h" #include "ecmascript/compiler/compiler_log.h" #include "ecmascript/jit/jit_thread.h" +#include "ecmascript/jit/jit_dfx.h" namespace panda::ecmascript { class JitTask; @@ -87,6 +88,11 @@ public: { return isProfileNeedDump_; } + + JitDfx *GetJitDfx() const + { + return jitDfx_; + } NO_COPY_SEMANTIC(Jit); NO_MOVE_SEMANTIC(Jit); @@ -156,7 +162,10 @@ public: { ASSERT(!thread->IsJitThread()); if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { + Clock::time_point start = Clock::now(); thread_->GetJitLock()->Lock(); + Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( + std::chrono::duration_cast(Clock::now() - start).count()); locked_ = true; } } @@ -188,6 +197,8 @@ private: std::unordered_map>> installJitTasks_; Mutex installJitTasksDequeMtx_; Mutex setEnableLock_; + + JitDfx *jitDfx_ { nullptr }; static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; static void (*initJitCompiler_)(JSRuntimeOptions); diff --git a/ecmascript/jit/jit_dfx.cpp b/ecmascript/jit/jit_dfx.cpp new file mode 100644 index 0000000000..8b4c69ee99 --- /dev/null +++ b/ecmascript/jit/jit_dfx.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/jit/jit_dfx.h" +#include "ecmascript/runtime.h" +#include "libpandafile/file.h" +#include "libpandafile/code_data_accessor.h" +#include "libpandafile/class_data_accessor-inl.h" + +#ifdef ENABLE_HISYSEVENT +#include "hisysevent.h" +#endif + +namespace panda::ecmascript { +JitDfx JitDfx::instance; +thread_local uint32_t JitDfx::prefixOffset_ = 0; +class NullStream : public std::ostream { +public: + NullStream() : std::ostream(&buffer_) {} + +private: + class NullBuffer : public std::streambuf { + public: + int overflow(int c) override + { + return c; + } + }; + NullBuffer buffer_; +}; + +JitDfx *JitDfx::GetInstance() +{ + return &instance; +} + +void JitDfx::EnableDump() +{ + isEnableDump_ = true; +} + +void JitDfx::OpenLogFile(uint32_t threadId) +{ +#ifdef PANDA_TARGET_OHOS + CString path = CString("/data/storage/ark-profile/jit_dfx_") + ToCString(threadId) + CString(".log"); +#else + CString path = CString("jit_dfx_") + ToCString(threadId) + CString(".log"); +#endif + logFiles_[threadId].open(path.c_str(), std::ios::out); +} + +std::ostream &JitDfx::GetLogFileStream() +{ + if (!isEnableDump_) { + static NullStream nullStream_; + return nullStream_; + } + uint32_t threadId = os::thread::GetCurrentThreadId(); + auto it = logFiles_.find(threadId); + if (it == logFiles_.end()) { + OpenLogFile(threadId); + } + return logFiles_[threadId]; +} + +void JitDfx::DumpBytecodeInst(Method *method) +{ + if (!isEnableDump_) { + return; + } + CString methodInfo = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); + MethodLiteral *methodLiteral = method->GetMethodLiteral(); + auto jsPandaFile = method->GetJSPandaFile(); + const panda_file::File *pf = jsPandaFile->GetPandaFile(); + panda_file::File::EntityId methodIdx = methodLiteral->GetMethodId(); + panda_file::MethodDataAccessor mda(*pf, methodIdx); + auto codeId = mda.GetCodeId(); + panda_file::CodeDataAccessor codeDataAccessor(*pf, codeId.value()); + uint32_t codeSize = codeDataAccessor.GetCodeSize(); + const uint8_t *insns = codeDataAccessor.GetInstructions(); + + std::ostringstream ss; + ss << "BytecodeInst func:" << methodInfo << "\n"; + auto bcIns = BytecodeInst(insns); + auto bcInsLast = bcIns.JumpTo(codeSize); + while (bcIns.GetAddress() != bcInsLast.GetAddress()) { + ss << bcIns << std::endl; + auto nextInst = bcIns.GetNext(); + bcIns = nextInst; + } + + GetLogFileStream() << ss.str() << std::endl; +} + +void JitDfx::TraceJitCode(Method *method, bool isEntry) +{ + if (!isEnableDump_) { + return; + } + if (!isEntry) { + prefixOffset_ -= 1; + } + CString prefixStr = isEntry ? CString("JitCodeEntry:") : CString("JitCodeExit :"); + CString methodInfo = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); + static CString blackSpace(" "); + CString prefix; + for (uint32_t i = 0; i < prefixOffset_; i++) { + prefix += blackSpace; + } + if (isEntry) { + prefixOffset_ += 1; + } + LOG_JIT(INFO) << prefixStr << prefix << methodInfo; +} + +void JitDfx::PrintJitStatsLog() +{ + if (checkUploadConditions()) { + LOG_JIT(DEBUG) << "Jit Compiler stats Log: " + << " bundleName: " << GetBundleName() + << " pid: " << GetPidNumber() + << " total main thread time: " << GetTotalTimeOnMainThread() + << " total Jit thread time: " << GetTotalTimeOnJitThread() + << " total Baseline Jit times: " << GetTotalBaselineJitCount() + << " total Fastopt Jit times: " << GetTotalFastoptJitCount() + << " report time interval:" + << std::chrono::duration_cast(Clock::now() - jitEventParams.start_).count() + << " total time on hold lock: " << GetTotalLockHoldingTime() + << " max time on hold lock: " << GetMaxLockHoldingTime() + << " longtime of hold lock: " << GetLongtimeLockCount() + << " JitDeopt times: " << GetJitDeoptCount() + << "\n"; + SendJitStatsEvent(); + InitializeRecord(); + } +} + +void JitDfx::SendJitStatsEvent() const +{ +#ifdef ENABLE_HISYSEVENT + int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME, + "ARK_STATS_JIT", + OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, + "BUNDLE_NAME", ConvertToStdString(GetBundleName()), + "PID", GetPidNumber(), + "TIME_INTERVAL", + std::chrono::duration_cast(Clock::now() - jitEventParams.start_).count(), + "TOTAL_BASELINE_JIT_TIMES", GetTotalBaselineJitCount(), + "TOTAL_FASTOPT_JIT_TIMES", GetTotalFastoptJitCount(), + "TOTAL_TIME_ON_MAIN_THREAD", GetTotalTimeOnMainThread(), + "TOTAL_TIME_ON_JIT_THREAD", GetTotalTimeOnJitThread(), + "TOTAL_TIME_ON_HOLD_LOCK", GetTotalLockHoldingTime(), + "MAX_TIME_ON_HOLD_LOCK", GetMaxLockHoldingTime(), + "LONG_TIME_OF_HOLD_LOCK", GetLongtimeLockCount(), + "UNINSTALL_TIME", GetJitDeoptCount()); + if (ret != 0) { + LOG_JIT(ERROR) << "Jit Compiler Stats send stats event failed! ret = " << ret; + } +#endif +} + +void JitDfx::PrintJitBlockUILog() +{ + std::string jitType = isBaselineJit_ ? "Baseline JIT" : "Fast optimization JIT"; + LOG_JIT(DEBUG) << "Jit BlockUI Event Log: " + << " bundleName: " << GetBundleName() + << " pid: " << GetPidNumber() + << " Single main thread time: " << GetSingleTimeOnMainThread() + << " Single Jit thread time: " << GetSingleTimeOnJitThread() + << " Jit type: " << jitType + << " method info: " << GetMethodInfo() + << "\n"; + SendJitBlockUIEvent(); + InitializeBlockUIRecord(); +} + +void JitDfx::SendJitBlockUIEvent() const +{ +#ifdef ENABLE_HISYSEVENT + std::string jitType = isBaselineJit_ ? "Baseline JIT" : "Fast optimization JIT"; + int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME, + "ARK_BLOCKUI_JIT", + OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, + "BUNDLE_NAME", ConvertToStdString(GetBundleName()), + "PID", GetPidNumber(), + "JIT_TYPE", jitType, + "JIT_FUNCTION_NAME", ConvertToStdString(GetMethodInfo()), + "TIME_ON_MAIN_THREAD", GetSingleTimeOnMainThread(), + "TIME_ON_JIT_THREAD", GetSingleTimeOnJitThread()); + if (ret != 0) { + LOG_JIT(ERROR) << "Jit Compiler Stats send jit blockUI event failed! ret = " << ret; + } +#endif +} + +void JitDfx::InitializeRecord() +{ + jitEventParams.totalBaselineJitTimes_.store(0); + jitEventParams.totalFastoptJitTimes_.store(0); + jitEventParams.jitDeoptTimes_.store(0); + jitEventParams.longtimeLockTimes_.store(0); + jitEventParams.totalTimeOnMainThread_.store(0); + jitEventParams.totalTimeOnJitThread_.store(0); + jitEventParams.totalLockHoldingTime_.store(0); + jitEventParams.maxLockHoldingTime_ .store(0); + ResetCompilerTime(); +} + +void JitDfx::InitializeBlockUIRecord() +{ + jitEventParams.singleTimeOnMainThread_.store(0); + jitEventParams.singleTimeOnJitThread_.store(0); + isBaselineJit_ = true; + methodInfo_ = ""; + ResetBlockUIEventTime(); +} +} // namespace panda::ecmascript diff --git a/ecmascript/jit/jit_dfx.h b/ecmascript/jit/jit_dfx.h new file mode 100644 index 0000000000..326ea76e54 --- /dev/null +++ b/ecmascript/jit/jit_dfx.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_JIT_JIT_DFX_H +#define ECMASCRIPT_JIT_JIT_DFX_H + +#include +#include +#include + +#include "ecmascript/log.h" +#include "ecmascript/mem/c_string.h" + +namespace panda::ecmascript { +using Clock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration; + +struct JitEventParams { + std::atomic totalBaselineJitTimes_; + std::atomic totalFastoptJitTimes_; + std::atomic jitDeoptTimes_; + std::atomic longtimeLockTimes_; + std::atomic singleTimeOnMainThread_; + std::atomic totalTimeOnMainThread_; + std::atomic singleTimeOnJitThread_; + std::atomic totalTimeOnJitThread_; + std::atomic totalLockHoldingTime_; + std::atomic maxLockHoldingTime_; + Clock::time_point start_; + Clock::time_point blockUIEventstart_; + + JitEventParams() : totalBaselineJitTimes_(0), totalFastoptJitTimes_(0), jitDeoptTimes_(0), + longtimeLockTimes_(0), singleTimeOnMainThread_(0), totalTimeOnMainThread_(0), + singleTimeOnJitThread_(0), totalTimeOnJitThread_(0), totalLockHoldingTime_(0), + maxLockHoldingTime_(0), start_(Clock::now()), blockUIEventstart_(Clock::now()) {} +}; + +class Method; +class JitDfx { +public: + using ThreadId = uint32_t; + static JitDfx *GetInstance(); + void EnableDump(); + bool IsEnableDump() const + { + return isEnableDump_; + } + + std::ostream &GetLogFileStream(); + + void DumpBytecodeInst(Method *method); + void TraceJitCode(Method *method, bool isEntry); + + void SetBundleName(CString bundleName) + { + bundleName_ = bundleName; + } + + CString GetBundleName() const + { + return bundleName_; + } + + void SetPidNumber(ThreadId number) + { + pidNum_ = number; + } + + ThreadId GetPidNumber() const + { + return pidNum_; + } + + void SetTotalTimeOnMainThread(int time) + { + jitEventParams.totalTimeOnMainThread_.fetch_add(time); + } + + int GetTotalTimeOnMainThread() const + { + return jitEventParams.totalTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND; + } + + void SetSingleTimeOnMainThread(int time) + { + jitEventParams.singleTimeOnMainThread_.store(time); + } + + int GetSingleTimeOnMainThread() const + { + return jitEventParams.singleTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND; + } + + void SetTotalTimeOnJitThread(int time) + { + jitEventParams.totalTimeOnJitThread_.fetch_add(time); + } + + int GetTotalTimeOnJitThread() const + { + return jitEventParams.totalTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND; + } + + void SetSingleTimeOnJitThread(int time) + { + jitEventParams.singleTimeOnJitThread_.store(time); + } + + int GetSingleTimeOnJitThread() const + { + return jitEventParams.singleTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND; + } + + void SetTriggerCount(bool isBaselineJit) + { + if (isBaselineJit) { + jitEventParams.totalBaselineJitTimes_.fetch_add(1); + } else { + jitEventParams.totalFastoptJitTimes_.fetch_add(1); + } + } + + int GetTotalBaselineJitCount() const + { + return jitEventParams.totalBaselineJitTimes_.load(); + } + + int GetTotalFastoptJitCount() const + { + return jitEventParams.totalFastoptJitTimes_.load(); + } + + void SetIsBaselineJit(bool isBaselineJit) + { + isBaselineJit_ = isBaselineJit; + } + + bool GetIsBaselineJit() const + { + return isBaselineJit_; + } + + void SetMethodInfo(CString method) + { + methodInfo_ = method; + } + + CString GetMethodInfo() const + { + return methodInfo_; + } + + void SetLockHoldingTime(int time) + { + jitEventParams.totalLockHoldingTime_.fetch_add(time); + if (time > jitEventParams.maxLockHoldingTime_.load()) { + jitEventParams.maxLockHoldingTime_.store(time); + } + if (time > HOLD_LOCK_LIMIT) { + jitEventParams.longtimeLockTimes_.fetch_add(1); + } + } + + int GetTotalLockHoldingTime() const + { + return jitEventParams.totalLockHoldingTime_.load() / CONVERT_TO_MILLISECOND; + } + + int GetMaxLockHoldingTime() const + { + return jitEventParams.maxLockHoldingTime_.load() / CONVERT_TO_MILLISECOND; + } + + int GetLongtimeLockCount() const + { + return jitEventParams.longtimeLockTimes_.load(); + } + + void SetJitDeoptCount() + { + jitEventParams.jitDeoptTimes_.fetch_add(1); + } + + int GetJitDeoptCount() const + { + return jitEventParams.jitDeoptTimes_.load(); + } + + void ResetCompilerTime() + { + jitEventParams.start_ = Clock::now(); + } + + void ResetBlockUIEventTime() + { + jitEventParams.blockUIEventstart_ = Clock::now(); + } + + bool ReportBlockUIEvent(int time) + { + return std::chrono::duration_cast(Clock::now() - + jitEventParams.blockUIEventstart_).count() >= MIN_SEND_INTERVAL && (time >= MAX_OCCUPY_MAIN_THREAD_TIME); + } + + void SetBlockUIEventInfo(CString info, bool isBaselineJit, int mainThreadTime, int jitThreadTime) + { + SetMethodInfo(info); + SetIsBaselineJit(isBaselineJit); + SetSingleTimeOnMainThread(mainThreadTime); + SetSingleTimeOnJitThread(jitThreadTime); + PrintJitBlockUILog(); + } + + void PrintJitStatsLog(); + void PrintJitBlockUILog(); + +private: + void OpenLogFile(uint32_t threadId); + void InitializeRecord(); + void InitializeBlockUIRecord(); + void SendJitStatsEvent() const; + void SendJitBlockUIEvent() const; + bool checkUploadConditions() const + { + return std::chrono::duration_cast(Clock::now() - jitEventParams.start_).count() >= + MIN_SEND_INTERVAL && (jitEventParams.totalBaselineJitTimes_.load() + + jitEventParams.totalFastoptJitTimes_.load()) >= MAX_TRIGGER_TIMES; + } + + static JitDfx instance; + bool isEnableDump_ {false}; + bool isBaselineJit_ {true}; + std::map logFiles_; + static thread_local uint32_t prefixOffset_; + + CString bundleName_ = ""; + CString methodInfo_ = ""; + ThreadId pidNum_ {0}; + JitEventParams jitEventParams; + static constexpr int MAX_TRIGGER_TIMES = 100; + static constexpr int MIN_SEND_INTERVAL = 60; // seconds + static constexpr int HOLD_LOCK_LIMIT = 1000; // microseconds + static constexpr int MAX_OCCUPY_MAIN_THREAD_TIME = 3000; // microseconds + static constexpr int CONVERT_TO_MILLISECOND = 1000; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_JIT_JIT_DFX_H diff --git a/ecmascript/jit/jit_task.cpp b/ecmascript/jit/jit_task.cpp index 249addb42e..c7d4bf405a 100644 --- a/ecmascript/jit/jit_task.cpp +++ b/ecmascript/jit/jit_task.cpp @@ -37,7 +37,8 @@ uint32_t JitTaskpool::TheMostSuitableThreadNum([[maybe_unused]]uint32_t threadNu } JitTask::JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHandle &jsFunction, - CompilerTier tier, CString &methodName, int32_t offset, uint32_t taskThreadId, JitCompileMode mode) + CompilerTier tier, CString &methodName, int32_t offset, uint32_t taskThreadId, + JitCompileMode mode, JitDfx *JitDfx) : hostThread_(hostThread), compilerThread_(compilerThread), jit_(jit), @@ -50,6 +51,7 @@ JitTask::JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHan taskThreadId_(taskThreadId), ecmaContext_(nullptr), jitCompileMode_(mode), + jitDfx_(JitDfx), runState_(RunState::INIT) { ecmaContext_ = hostThread->GetCurrentEcmaContext(); @@ -73,6 +75,7 @@ void JitTask::PrepareCompile() void JitTask::Optimize() { + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compiler frontend"); bool res = jit_->JitCompile(compilerTask_, this); if (!res) { SetCompileFailed(); @@ -85,6 +88,7 @@ void JitTask::Finalize() return; } + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compiler backend"); bool res = jit_->JitFinalize(compilerTask_, this); if (!res) { SetCompileFailed(); @@ -200,7 +204,9 @@ void JitTask::InstallCode() methodHandle->GetMethodId(), std::make_pair(methodHandle.GetTaggedType(), machineCodeObj.GetTaggedType())); } - LOG_JIT(DEBUG) <<"Install fast jit machine code:" << GetMethodName(); + uintptr_t codeAddrEnd = codeAddr + machineCodeObj->GetInstructionsSize(); + LOG_JIT(DEBUG) <<"Install fast jit machine code:" << GetMethodName() << ", code range:" << + reinterpret_cast(codeAddr) <<"--" << reinterpret_cast(codeAddrEnd); #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER auto &profMap = JitWarmupProfiler::GetInstance()->profMap_; if (profMap.find(GetMethodName()) != profMap.end()) { @@ -276,6 +282,7 @@ bool JitTask::AsyncTask::Run([[maybe_unused]] uint32_t threadIndex) } DISALLOW_HEAP_ACCESS; + ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compile"); // JitCompileMode ASYNC // check init ok jitTask_->SetRunState(RunState::RUNNING); @@ -299,6 +306,15 @@ bool JitTask::AsyncTask::Run([[maybe_unused]] uint32_t threadIndex) // info main thread compile complete jitTask_->jit_->RequestInstallCode(jitTask_); } + int compilerTime = scope.TotalSpentTimeInMicroseconds(); + jitTask_->jitDfx_->SetTotalTimeOnJitThread(compilerTime); + if (jitTask_->jitDfx_->ReportBlockUIEvent(jitTask_->mainThreadCompileTime_)) { + jitTask_->jitDfx_->SetBlockUIEventInfo( + jitTask_->methodName_, + jitTask_->compilerTier_ == CompilerTier::BASELINE ? true : false, + jitTask_->mainThreadCompileTime_, compilerTime); + } + jitTask_->jitDfx_->PrintJitStatsLog(); } jitvm->ReSetHostVM(); jitTask_->SetRunStateFinish(); diff --git a/ecmascript/jit/jit_task.h b/ecmascript/jit/jit_task.h index cb3c505589..a4d161e6b4 100644 --- a/ecmascript/jit/jit_task.h +++ b/ecmascript/jit/jit_task.h @@ -91,7 +91,7 @@ class JitTask { public: JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHandle &jsFunction, CompilerTier tier, CString &methodName, int32_t offset, - uint32_t taskThreadId, JitCompileMode mode); + uint32_t taskThreadId, JitCompileMode mode, JitDfx *jitDfx); // for ut JitTask(EcmaVM *hVm, EcmaVM *cVm, Jit *jit, uint32_t taskThreadId, JitCompileMode mode); ~JitTask(); @@ -213,6 +213,16 @@ public: return jitCompileMode_ == JitCompileMode::ASYNC; } + void SetMainThreadCompilerTime(int time) + { + mainThreadCompileTime_ = time; + } + + int GetMainThreadCompilerTime() const + { + return mainThreadCompileTime_; + } + class AsyncTask : public Task { public: explicit AsyncTask(std::shared_ptrjitTask, int32_t id) : Task(id), jitTask_(jitTask) { } @@ -278,6 +288,8 @@ private: std::unique_ptr sustainingJSHandle_; EcmaContext *ecmaContext_; JitCompileMode jitCompileMode_; + JitDfx *jitDfx_ { nullptr }; + int mainThreadCompileTime_ {0}; std::atomic runState_; Mutex runStateMutex_; diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 3f0ebe1d17..fc5f480574 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -1107,6 +1107,16 @@ public: return enableAPPJIT_; } + bool IsEnableJitDfxDump() const + { + return isEnableJitDfxDump_; + } + + void SetEnableJitDfxDump(bool value) + { + isEnableJitDfxDump_ = value; + } + void SetEnableOSR(bool value) { enableOSR_ = value; @@ -1786,6 +1796,7 @@ private: bool enableOptPGOType_ {true}; bool enableFastJIT_{false}; bool enableAPPJIT_{false}; + bool isEnableJitDfxDump_ {false}; bool enableOSR_{false}; uint16_t jitHotnessThreshold_ {2}; uint16_t osrHotnessThreshold_ {2}; diff --git a/ecmascript/mem/clock_scope.h b/ecmascript/mem/clock_scope.h index 1cad873ac9..91c2cca5d1 100644 --- a/ecmascript/mem/clock_scope.h +++ b/ecmascript/mem/clock_scope.h @@ -41,6 +41,11 @@ public: return (float) duration.count() / MILLION_TIME; } + int TotalSpentTimeInMicroseconds() const + { + return std::chrono::duration_cast(Clock::now() - start_).count(); + } + double GetCurTime() const { auto curTime_ = Duration(start_.time_since_epoch()); diff --git a/hisysevent.yaml b/hisysevent.yaml index 413ff1e1f5..9fd6bd61a7 100644 --- a/hisysevent.yaml +++ b/hisysevent.yaml @@ -41,3 +41,26 @@ ARK_COMPILER_LOG: IS_LITECG: {type: BOOL, desc: codegen type is litecg} COMPILER_METHOD_COUNT: {type: UINT32, desc: compiler method count} PGO_FILE_LEGAL: {type: BOOL, desc: pgo file is legal} + +ARK_STATS_JIT: + __BASE: {type: STATISTIC, level: MINOR, desc: ARKTSRUNTIME JIT COMPILER KEY STATS, preserve: true} + BUNDLE_NAME: {type: STRING, desc: Application bundle name} + PID: {type: INT32, desc: pid} + TIME_INTERVAL: {type: INT32, desc: Interval for reporting the event} + TOTAL_BASELINE_JIT_TIMES: {type: INT32, desc: Number of baseline JIT triggering times within this period} + TOTAL_FASTOPT_JIT_TIMES: {type: INT32, desc: Number of fast optimization JIT triggering times within this period} + TOTAL_TIME_ON_MAIN_THREAD: {type: INT32, desc: The total time occupied by JIT on the main thread within this period} + TOTAL_TIME_ON_JIT_THREAD: {type: INT32, desc: The total time occupied on the JIT thread within this period} + TOTAL_TIME_ON_HOLD_LOCK: {type: INT32, desc: Total lock holding time within this period} + MAX_TIME_ON_HOLD_LOCK: {type: INT32, desc: Maximum lock holding time within this period} + LONG_TIME_OF_HOLD_LOCK: {type: INT32, desc: Times of long-time lock holding within this period} + UNINSTALL_TIME: {type: INT32, desc: JIT deoptimizer times within this period} + +ARK_BLOCKUI_JIT: + __BASE: {type: STATISTIC, level: MINOR, desc: ARKTSRUNTIME JIT COMPILER BLOCKUI EVENT, preserve: true} + BUNDLE_NAME: {type: STRING, desc: Application bundle name} + PID: {type: INT32, desc: pid} + JIT_TYPE: {type: STRING, desc: Triggered jit type} + JIT_FUNCTION_NAME: {type: STRING, desc: JIT compiled function name} + TIME_ON_MAIN_THREAD: {type: INT32, desc: The time occupied by JIT on the main thread} + TIME_ON_JIT_THREAD: {type: INT32, desc: The time occupied on JIT thread} \ No newline at end of file