add jit event

Signed-off-by: zoumujia <zoumujia0920@163.com>
This commit is contained in:
zoumujia 2024-05-11 12:31:04 +08:00
parent 8c2e576664
commit 18e474aedc
12 changed files with 598 additions and 7 deletions

View File

@ -682,6 +682,7 @@ ecma_source = [
"ecmascript/interpreter/slow_runtime_stub.cpp", "ecmascript/interpreter/slow_runtime_stub.cpp",
"ecmascript/intl/locale_helper.cpp", "ecmascript/intl/locale_helper.cpp",
"ecmascript/jit/jit.cpp", "ecmascript/jit/jit.cpp",
"ecmascript/jit/jit_dfx.cpp",
"ecmascript/jit/jit_task.cpp", "ecmascript/jit/jit_task.cpp",
"ecmascript/jit/jit_thread.cpp", "ecmascript/jit/jit_thread.cpp",
"ecmascript/jit/jit_profiler.cpp", "ecmascript/jit/jit_profiler.cpp",

View File

@ -609,6 +609,10 @@ void AOTFileGenerator::GetMemoryCodeInfos(MachineCodeDesc &machineCodeDesc)
LOG_COMPILER(WARN) << "error: code size of generated an file is empty!"; LOG_COMPILER(WARN) << "error: code size of generated an file is empty!";
return; return;
} }
if (log_->OutputASM()) {
PrintMergedCodeComment();
}
GenerateMergedStackmapSection(); GenerateMergedStackmapSection();
// get func entry Map // get func entry Map

View File

@ -544,6 +544,9 @@ void Deoptimizier::UpdateAndDumpDeoptInfo(kungfu::DeoptType type)
method->SetDeoptThreshold(--deoptThreshold); method->SetDeoptThreshold(--deoptThreshold);
} else { } else {
method->ClearAOTStatusWhenDeopt(); method->ClearAOTStatusWhenDeopt();
if (func->GetMachineCode().IsMachineCodeObject()) {
Jit::GetInstance()->GetJitDfx()->SetJitDeoptCount();
}
func->SetCodeEntry(reinterpret_cast<uintptr_t>(nullptr)); func->SetCodeEntry(reinterpret_cast<uintptr_t>(nullptr));
} }
} }

View File

@ -70,6 +70,13 @@ void Jit::SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJ
isApp_ = options.IsEnableAPPJIT(); isApp_ = options.IsEnableAPPJIT();
initJitCompiler_(options); initJitCompiler_(options);
JitTaskpool::GetCurrentTaskpool()->Initialize(); 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> &jsFunction, CompilerTier tie
return; return;
} }
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compile");
Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject()); Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
CString fileDesc = method->GetJSPandaFile()->GetJSPandaFileDesc(); CString fileDesc = method->GetJSPandaFile()->GetJSPandaFileDesc();
CString methodName = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName()); CString methodName = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName());
uint32_t codeSize = method->GetCodeSize(); 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; constexpr uint32_t maxSize = 9000;
if (codeSize > maxSize) { if (codeSize > maxSize) {
if (tier == CompilerTier::BASELINE) { if (tier == CompilerTier::BASELINE) {
@ -251,6 +261,9 @@ void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tie
return; return;
} }
CString msg = "compile method:" + methodInfo + ", in work thread";
TimeScope scope(msg, tier);
if (vm->GetJSThread()->IsMachineCodeLowMemory()) { if (vm->GetJSThread()->IsMachineCodeLowMemory()) {
if (tier == CompilerTier::BASELINE) { if (tier == CompilerTier::BASELINE) {
LOG_BASELINEJIT(DEBUG) << "skip jit task, as low code memory:" << methodInfo; LOG_BASELINEJIT(DEBUG) << "skip jit task, as low code memory:" << methodInfo;
@ -281,18 +294,18 @@ void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tie
// using hole value to indecate compiling. todo: reset when failed // using hole value to indecate compiling. todo: reset when failed
if (tier == CompilerTier::FAST) { if (tier == CompilerTier::FAST) {
jsFunction->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole()); jsFunction->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole());
jit->GetJitDfx()->SetTriggerCount(false);
} else { } else {
ASSERT(tier == CompilerTier::BASELINE); ASSERT(tier == CompilerTier::BASELINE);
jsFunction->SetBaselineCode(vm->GetJSThread(), JSTaggedValue::Hole()); 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(); JitTaskpool::GetCurrentTaskpool()->WaitForJitTaskPoolReady();
EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm(); EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm();
std::shared_ptr<JitTask> jitTask = std::make_shared<JitTask>(vm->GetJSThread(), compilerVm->GetJSThread(), std::shared_ptr<JitTask> jitTask = std::make_shared<JitTask>(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(); jitTask->PrepareCompile();
JitTaskpool::GetCurrentTaskpool()->PostTask( JitTaskpool::GetCurrentTaskpool()->PostTask(
@ -303,6 +316,10 @@ void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tie
jitTask->WaitFinish(); jitTask->WaitFinish();
jitTask->InstallCode(); jitTask->InstallCode();
} }
int spendTime = scope.TotalSpentTimeInMicroseconds();
jitTask->SetMainThreadCompilerTime(spendTime);
jit->GetJitDfx()->SetTotalTimeOnMainThread(spendTime);
jit->GetJitDfx()->PrintJitStatsLog();
} }
} }

View File

@ -24,6 +24,7 @@
#include "ecmascript/mem/machine_code.h" #include "ecmascript/mem/machine_code.h"
#include "ecmascript/compiler/compiler_log.h" #include "ecmascript/compiler/compiler_log.h"
#include "ecmascript/jit/jit_thread.h" #include "ecmascript/jit/jit_thread.h"
#include "ecmascript/jit/jit_dfx.h"
namespace panda::ecmascript { namespace panda::ecmascript {
class JitTask; class JitTask;
@ -87,6 +88,11 @@ public:
{ {
return isProfileNeedDump_; return isProfileNeedDump_;
} }
JitDfx *GetJitDfx() const
{
return jitDfx_;
}
NO_COPY_SEMANTIC(Jit); NO_COPY_SEMANTIC(Jit);
NO_MOVE_SEMANTIC(Jit); NO_MOVE_SEMANTIC(Jit);
@ -156,7 +162,10 @@ public:
{ {
ASSERT(!thread->IsJitThread()); ASSERT(!thread->IsJitThread());
if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) {
Clock::time_point start = Clock::now();
thread_->GetJitLock()->Lock(); thread_->GetJitLock()->Lock();
Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime(
std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start).count());
locked_ = true; locked_ = true;
} }
} }
@ -188,6 +197,8 @@ private:
std::unordered_map<uint32_t, std::deque<std::shared_ptr<JitTask>>> installJitTasks_; std::unordered_map<uint32_t, std::deque<std::shared_ptr<JitTask>>> installJitTasks_;
Mutex installJitTasksDequeMtx_; Mutex installJitTasksDequeMtx_;
Mutex setEnableLock_; Mutex setEnableLock_;
JitDfx *jitDfx_ { nullptr };
static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; static constexpr int MIN_CODE_SPACE_SIZE = 1_KB;
static void (*initJitCompiler_)(JSRuntimeOptions); static void (*initJitCompiler_)(JSRuntimeOptions);

229
ecmascript/jit/jit_dfx.cpp Normal file
View File

@ -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<std::chrono::seconds>(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<std::chrono::seconds>(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

259
ecmascript/jit/jit_dfx.h Normal file
View File

@ -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 <fstream>
#include <map>
#include <atomic>
#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<uint64_t, std::nano>;
struct JitEventParams {
std::atomic<int> totalBaselineJitTimes_;
std::atomic<int> totalFastoptJitTimes_;
std::atomic<int> jitDeoptTimes_;
std::atomic<int> longtimeLockTimes_;
std::atomic<int> singleTimeOnMainThread_;
std::atomic<int> totalTimeOnMainThread_;
std::atomic<int> singleTimeOnJitThread_;
std::atomic<int> totalTimeOnJitThread_;
std::atomic<int> totalLockHoldingTime_;
std::atomic<int> 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<std::chrono::seconds>(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<std::chrono::seconds>(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<uint32_t, std::ofstream> 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

View File

@ -37,7 +37,8 @@ uint32_t JitTaskpool::TheMostSuitableThreadNum([[maybe_unused]]uint32_t threadNu
} }
JitTask::JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHandle<JSFunction> &jsFunction, JitTask::JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHandle<JSFunction> &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), : hostThread_(hostThread),
compilerThread_(compilerThread), compilerThread_(compilerThread),
jit_(jit), jit_(jit),
@ -50,6 +51,7 @@ JitTask::JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JSHan
taskThreadId_(taskThreadId), taskThreadId_(taskThreadId),
ecmaContext_(nullptr), ecmaContext_(nullptr),
jitCompileMode_(mode), jitCompileMode_(mode),
jitDfx_(JitDfx),
runState_(RunState::INIT) runState_(RunState::INIT)
{ {
ecmaContext_ = hostThread->GetCurrentEcmaContext(); ecmaContext_ = hostThread->GetCurrentEcmaContext();
@ -73,6 +75,7 @@ void JitTask::PrepareCompile()
void JitTask::Optimize() void JitTask::Optimize()
{ {
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compiler frontend");
bool res = jit_->JitCompile(compilerTask_, this); bool res = jit_->JitCompile(compilerTask_, this);
if (!res) { if (!res) {
SetCompileFailed(); SetCompileFailed();
@ -85,6 +88,7 @@ void JitTask::Finalize()
return; return;
} }
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compiler backend");
bool res = jit_->JitFinalize(compilerTask_, this); bool res = jit_->JitFinalize(compilerTask_, this);
if (!res) { if (!res) {
SetCompileFailed(); SetCompileFailed();
@ -200,7 +204,9 @@ void JitTask::InstallCode()
methodHandle->GetMethodId(), methodHandle->GetMethodId(),
std::make_pair(methodHandle.GetTaggedType(), machineCodeObj.GetTaggedType())); 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<void*>(codeAddr) <<"--" << reinterpret_cast<void*>(codeAddrEnd);
#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
auto &profMap = JitWarmupProfiler::GetInstance()->profMap_; auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
if (profMap.find(GetMethodName()) != profMap.end()) { if (profMap.find(GetMethodName()) != profMap.end()) {
@ -276,6 +282,7 @@ bool JitTask::AsyncTask::Run([[maybe_unused]] uint32_t threadIndex)
} }
DISALLOW_HEAP_ACCESS; DISALLOW_HEAP_ACCESS;
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "JIT::Compile");
// JitCompileMode ASYNC // JitCompileMode ASYNC
// check init ok // check init ok
jitTask_->SetRunState(RunState::RUNNING); jitTask_->SetRunState(RunState::RUNNING);
@ -299,6 +306,15 @@ bool JitTask::AsyncTask::Run([[maybe_unused]] uint32_t threadIndex)
// info main thread compile complete // info main thread compile complete
jitTask_->jit_->RequestInstallCode(jitTask_); 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(); jitvm->ReSetHostVM();
jitTask_->SetRunStateFinish(); jitTask_->SetRunStateFinish();

View File

@ -91,7 +91,7 @@ class JitTask {
public: public:
JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit, JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit,
JSHandle<JSFunction> &jsFunction, CompilerTier tier, CString &methodName, int32_t offset, JSHandle<JSFunction> &jsFunction, CompilerTier tier, CString &methodName, int32_t offset,
uint32_t taskThreadId, JitCompileMode mode); uint32_t taskThreadId, JitCompileMode mode, JitDfx *jitDfx);
// for ut // for ut
JitTask(EcmaVM *hVm, EcmaVM *cVm, Jit *jit, uint32_t taskThreadId, JitCompileMode mode); JitTask(EcmaVM *hVm, EcmaVM *cVm, Jit *jit, uint32_t taskThreadId, JitCompileMode mode);
~JitTask(); ~JitTask();
@ -213,6 +213,16 @@ public:
return jitCompileMode_ == JitCompileMode::ASYNC; return jitCompileMode_ == JitCompileMode::ASYNC;
} }
void SetMainThreadCompilerTime(int time)
{
mainThreadCompileTime_ = time;
}
int GetMainThreadCompilerTime() const
{
return mainThreadCompileTime_;
}
class AsyncTask : public Task { class AsyncTask : public Task {
public: public:
explicit AsyncTask(std::shared_ptr<JitTask>jitTask, int32_t id) : Task(id), jitTask_(jitTask) { } explicit AsyncTask(std::shared_ptr<JitTask>jitTask, int32_t id) : Task(id), jitTask_(jitTask) { }
@ -278,6 +288,8 @@ private:
std::unique_ptr<SustainingJSHandle> sustainingJSHandle_; std::unique_ptr<SustainingJSHandle> sustainingJSHandle_;
EcmaContext *ecmaContext_; EcmaContext *ecmaContext_;
JitCompileMode jitCompileMode_; JitCompileMode jitCompileMode_;
JitDfx *jitDfx_ { nullptr };
int mainThreadCompileTime_ {0};
std::atomic<RunState> runState_; std::atomic<RunState> runState_;
Mutex runStateMutex_; Mutex runStateMutex_;

View File

@ -1107,6 +1107,16 @@ public:
return enableAPPJIT_; return enableAPPJIT_;
} }
bool IsEnableJitDfxDump() const
{
return isEnableJitDfxDump_;
}
void SetEnableJitDfxDump(bool value)
{
isEnableJitDfxDump_ = value;
}
void SetEnableOSR(bool value) void SetEnableOSR(bool value)
{ {
enableOSR_ = value; enableOSR_ = value;
@ -1786,6 +1796,7 @@ private:
bool enableOptPGOType_ {true}; bool enableOptPGOType_ {true};
bool enableFastJIT_{false}; bool enableFastJIT_{false};
bool enableAPPJIT_{false}; bool enableAPPJIT_{false};
bool isEnableJitDfxDump_ {false};
bool enableOSR_{false}; bool enableOSR_{false};
uint16_t jitHotnessThreshold_ {2}; uint16_t jitHotnessThreshold_ {2};
uint16_t osrHotnessThreshold_ {2}; uint16_t osrHotnessThreshold_ {2};

View File

@ -41,6 +41,11 @@ public:
return (float) duration.count() / MILLION_TIME; return (float) duration.count() / MILLION_TIME;
} }
int TotalSpentTimeInMicroseconds() const
{
return std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start_).count();
}
double GetCurTime() const double GetCurTime() const
{ {
auto curTime_ = Duration(start_.time_since_epoch()); auto curTime_ = Duration(start_.time_since_epoch());

View File

@ -41,3 +41,26 @@ ARK_COMPILER_LOG:
IS_LITECG: {type: BOOL, desc: codegen type is litecg} IS_LITECG: {type: BOOL, desc: codegen type is litecg}
COMPILER_METHOD_COUNT: {type: UINT32, desc: compiler method count} COMPILER_METHOD_COUNT: {type: UINT32, desc: compiler method count}
PGO_FILE_LEGAL: {type: BOOL, desc: pgo file is legal} 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}