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