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