• 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 #ifndef ECMASCRIPT_JIT_JIT_DFX_H
17 #define ECMASCRIPT_JIT_JIT_DFX_H
18 
19 #include <fstream>
20 #include <map>
21 #include <atomic>
22 
23 #include "ecmascript/log.h"
24 #include "ecmascript/mem/c_string.h"
25 #include "ecmascript/jit/compile_decision.h"
26 
27 namespace panda::ecmascript {
28 using Clock = std::chrono::high_resolution_clock;
29 using Duration = std::chrono::duration<uint64_t, std::nano>;
30 
31 struct JitEventParams {
32     std::atomic<int> totalBaselineJitTimes_;
33     std::atomic<int> totalFastoptJitTimes_;
34     std::atomic<int> jitDeoptTimes_;
35     std::atomic<int> longtimeLockTimes_;
36     std::atomic<int> singleTimeOnMainThread_;
37     std::atomic<int> totalTimeOnMainThread_;
38     std::atomic<int> singleTimeOnJitThread_;
39     std::atomic<int> totalTimeOnJitThread_;
40     std::atomic<int> totalLockHoldingTime_;
41     std::atomic<int> maxLockHoldingTime_;
42     Clock::time_point start_;
43     Clock::time_point blockUIEventstart_;
44 
JitEventParamsJitEventParams45     JitEventParams() : totalBaselineJitTimes_(0), totalFastoptJitTimes_(0), jitDeoptTimes_(0),
46         longtimeLockTimes_(0), singleTimeOnMainThread_(0), totalTimeOnMainThread_(0),
47         singleTimeOnJitThread_(0), totalTimeOnJitThread_(0), totalLockHoldingTime_(0),
48         maxLockHoldingTime_(0), start_(Clock::now()), blockUIEventstart_(Clock::now()) {}
49 };
50 
51 class Method;
52 class JitDfx {
53 public:
54     using ThreadId = uint32_t;
55     static JitDfx *GetInstance();
56     void Init(const JSRuntimeOptions &options, std::string &bundleName);
57     void EnableDump();
IsEnableDump()58     bool IsEnableDump() const
59     {
60         return isEnableDump_;
61     }
62 
63     std::ostream &GetLogFileStream();
64 
65     void DumpBytecodeInst(Method *method);
66     void TraceJitCode(Method *method, bool isEntry);
67 
SetBundleName(CString bundleName)68     void SetBundleName(CString bundleName)
69     {
70         bundleName_ = bundleName;
71     }
72 
GetBundleName()73     CString GetBundleName() const
74     {
75         return bundleName_;
76     }
77 
SetPidNumber(ThreadId number)78     void SetPidNumber(ThreadId number)
79     {
80         pidNum_ = number;
81     }
82 
GetPidNumber()83     ThreadId GetPidNumber() const
84     {
85         return pidNum_;
86     }
87 
RecordSpentTimeAndPrintStatsLogInJsThread(int time)88     void RecordSpentTimeAndPrintStatsLogInJsThread(int time)
89     {
90         SetTotalTimeOnMainThread(time);
91         PrintJitStatsLog();
92     }
93 
RecordSpentTimeAndPrintStatsLogInJitThread(int compilerTime,CString methodName,bool isBaselineJit,int mainThreadCompileTime)94     void RecordSpentTimeAndPrintStatsLogInJitThread(int compilerTime, CString methodName, bool isBaselineJit,
95         int mainThreadCompileTime)
96     {
97         SetTotalTimeOnJitThread(compilerTime);
98         if (ReportBlockUIEvent(mainThreadCompileTime)) {
99             SetBlockUIEventInfo(methodName, isBaselineJit, mainThreadCompileTime, compilerTime);
100         }
101         PrintJitStatsLog();
102     }
103 
SetTotalTimeOnMainThread(int time)104     void SetTotalTimeOnMainThread(int time)
105     {
106         jitEventParams.totalTimeOnMainThread_.fetch_add(time);
107     }
108 
GetTotalTimeOnMainThread()109     int GetTotalTimeOnMainThread() const
110     {
111         return jitEventParams.totalTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND;
112     }
113 
SetSingleTimeOnMainThread(int time)114     void SetSingleTimeOnMainThread(int time)
115     {
116         jitEventParams.singleTimeOnMainThread_.store(time);
117     }
118 
GetSingleTimeOnMainThread()119     int GetSingleTimeOnMainThread() const
120     {
121         return jitEventParams.singleTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND;
122     }
123 
SetTotalTimeOnJitThread(int time)124     void SetTotalTimeOnJitThread(int time)
125     {
126         jitEventParams.totalTimeOnJitThread_.fetch_add(time);
127     }
128 
GetTotalTimeOnJitThread()129     int GetTotalTimeOnJitThread() const
130     {
131         return jitEventParams.totalTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND;
132     }
133 
SetSingleTimeOnJitThread(int time)134     void SetSingleTimeOnJitThread(int time)
135     {
136         jitEventParams.singleTimeOnJitThread_.store(time);
137     }
138 
GetSingleTimeOnJitThread()139     int GetSingleTimeOnJitThread() const
140     {
141         return jitEventParams.singleTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND;
142     }
143 
SetTriggerCount(CompilerTier tier)144     void SetTriggerCount(CompilerTier tier)
145     {
146         if (tier.IsBaseLine()) {
147             jitEventParams.totalBaselineJitTimes_.fetch_add(1);
148         } else {
149             jitEventParams.totalFastoptJitTimes_.fetch_add(1);
150         }
151     }
152 
GetTotalBaselineJitCount()153     int GetTotalBaselineJitCount() const
154     {
155         return jitEventParams.totalBaselineJitTimes_.load();
156     }
157 
GetTotalFastoptJitCount()158     int GetTotalFastoptJitCount() const
159     {
160         return jitEventParams.totalFastoptJitTimes_.load();
161     }
162 
SetIsBaselineJit(bool isBaselineJit)163     void SetIsBaselineJit(bool isBaselineJit)
164     {
165         isBaselineJit_ = isBaselineJit;
166     }
167 
GetIsBaselineJit()168     bool GetIsBaselineJit() const
169     {
170         return isBaselineJit_;
171     }
172 
SetMethodInfo(CString method)173     void SetMethodInfo(CString method)
174     {
175         methodInfo_ = method;
176     }
177 
GetMethodInfo()178     CString GetMethodInfo() const
179     {
180         return methodInfo_;
181     }
182 
SetLockHoldingTime(int time)183     void SetLockHoldingTime(int time)
184     {
185         jitEventParams.totalLockHoldingTime_.fetch_add(time);
186         if (time > jitEventParams.maxLockHoldingTime_.load()) {
187             jitEventParams.maxLockHoldingTime_.store(time);
188         }
189         if (time > HOLD_LOCK_LIMIT) {
190             jitEventParams.longtimeLockTimes_.fetch_add(1);
191         }
192     }
193 
GetTotalLockHoldingTime()194     int GetTotalLockHoldingTime() const
195     {
196         return jitEventParams.totalLockHoldingTime_.load() / CONVERT_TO_MILLISECOND;
197     }
198 
GetMaxLockHoldingTime()199     int GetMaxLockHoldingTime() const
200     {
201         return jitEventParams.maxLockHoldingTime_.load() / CONVERT_TO_MILLISECOND;
202     }
203 
GetLongtimeLockCount()204     int GetLongtimeLockCount() const
205     {
206         return jitEventParams.longtimeLockTimes_.load();
207     }
208 
SetJitDeoptCount()209     void SetJitDeoptCount()
210     {
211         jitEventParams.jitDeoptTimes_.fetch_add(1);
212     }
213 
GetJitDeoptCount()214     int GetJitDeoptCount() const
215     {
216         return jitEventParams.jitDeoptTimes_.load();
217     }
218 
ResetCompilerTime()219     void ResetCompilerTime()
220     {
221         jitEventParams.start_ = Clock::now();
222     }
223 
ResetBlockUIEventTime()224     void ResetBlockUIEventTime()
225     {
226         jitEventParams.blockUIEventstart_ = Clock::now();
227     }
228 
ReportBlockUIEvent(int time)229     bool ReportBlockUIEvent(int time)
230     {
231         return std::chrono::duration_cast<std::chrono::seconds>(Clock::now() -
232             jitEventParams.blockUIEventstart_).count() >= MIN_SEND_INTERVAL && (time >= MAX_OCCUPY_MAIN_THREAD_TIME);
233     }
234 
SetBlockUIEventInfo(CString info,bool isBaselineJit,int mainThreadTime,int jitThreadTime)235     void SetBlockUIEventInfo(CString info, bool isBaselineJit, int mainThreadTime, int jitThreadTime)
236     {
237         SetMethodInfo(info);
238         SetIsBaselineJit(isBaselineJit);
239         SetSingleTimeOnMainThread(mainThreadTime);
240         SetSingleTimeOnJitThread(jitThreadTime);
241         PrintJitBlockUILog();
242     }
243 
244     void PrintJitStatsLog();
245     void PrintJitBlockUILog();
246 
247 private:
248     void OpenLogFile(uint32_t threadId);
249     void InitializeRecord();
250     void InitializeBlockUIRecord();
251     void SendJitStatsEvent() const;
252     void SendJitBlockUIEvent() const;
checkUploadConditions()253     bool checkUploadConditions() const
254     {
255         return std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - jitEventParams.start_).count() >=
256             MIN_SEND_INTERVAL && (jitEventParams.totalBaselineJitTimes_.load() +
257             jitEventParams.totalFastoptJitTimes_.load()) >= MAX_TRIGGER_TIMES;
258     }
259 
260     static JitDfx instance;
261     bool isEnableDump_ {false};
262     bool isBaselineJit_ {true};
263     std::map<uint32_t, std::ofstream> logFiles_;
264     static thread_local uint32_t prefixOffset_;
265 
266     CString bundleName_ = "";
267     CString methodInfo_ = "";
268     ThreadId pidNum_ {0};
269     JitEventParams jitEventParams;
270     static constexpr int MAX_TRIGGER_TIMES = 100;
271     static constexpr int MIN_SEND_INTERVAL = 60; // seconds
272     static constexpr int HOLD_LOCK_LIMIT = 1000; // microseconds
273     static constexpr int MAX_OCCUPY_MAIN_THREAD_TIME = 3000; // microseconds
274     static constexpr int CONVERT_TO_MILLISECOND = 1000;
275 };
276 }  // namespace panda::ecmascript
277 #endif  // ECMASCRIPT_JIT_JIT_DFX_H
278