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