• 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(Method * method)95 void 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 
TraceJitCode(Method * method,bool isEntry)125 void 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 
PrintJitStatsLog()146 void 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 
SendJitStatsEvent() const168 void 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 
PrintJitBlockUILog()192 void 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 
SendJitBlockUIEvent() const207 void 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 
InitializeRecord()226 void 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 
InitializeBlockUIRecord()239 void 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