1 /* 2 * Copyright (c) 2023 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 #ifndef FFRT_TRACE_RECORD_H 16 #define FFRT_TRACE_RECORD_H 17 18 #include "util/ffrt_ring_buffer.h" 19 #include "dfx/log/ffrt_log_api.h" 20 #include "internal_inc/osal.h" 21 #include "tm/task_base.h" 22 #include "tm/cpu_task.h" 23 #include "tm/queue_task.h" 24 25 #define FFRT_TRACE_RECORD_LEVEL_1 (1) 26 #define FFRT_TRACE_RECORD_LEVEL_2 (2) 27 #define FFRT_TRACE_RECORD_LEVEL_3 (3) 28 29 namespace ffrt { 30 typedef struct ffrt_record_task_counter { 31 alignas(cacheline_size) std::atomic<unsigned int> submitCounter{0}; 32 alignas(cacheline_size) std::atomic<unsigned int> enqueueCounter{0}; 33 alignas(cacheline_size) std::atomic<unsigned int> coSwitchCounter{0}; 34 alignas(cacheline_size) std::atomic<unsigned int> runCounter{0}; 35 alignas(cacheline_size) std::atomic<unsigned int> doneCounter{0}; 36 alignas(cacheline_size) std::atomic<unsigned int> cancelCounter{0}; 37 } ffrt_record_task_counter_t; 38 39 typedef struct ffrt_record_task_time { 40 std::atomic<uint64_t> waitTime{0}; 41 std::atomic<uint64_t> runDuration{0}; 42 std::atomic<uint64_t> executeTime{0}; 43 uint64_t maxWaitTime{0}; 44 uint64_t maxRunDuration{0}; 45 } ffrt_record_task_time_t; 46 47 class FFRTTraceRecord { 48 public: 49 static const int TASK_TYPE_NUM = ffrt_queue_task + 1; 50 static bool ffrt_be_used_; 51 static bool stat_enable_; 52 static int g_recordMaxWorkerNumber_[QoS::MaxNum()]; 53 static ffrt_record_task_counter_t g_recordTaskCounter_[TASK_TYPE_NUM][QoS::MaxNum()]; 54 static ffrt_record_task_time_t g_recordTaskTime_[TASK_TYPE_NUM][QoS::MaxNum()]; 55 56 public: 57 FFRTTraceRecord() = default; 58 ~FFRTTraceRecord() = default; TimeStamp(void)59 static inline uint64_t TimeStamp(void) 60 { 61 #if defined(__aarch64__) 62 uint64_t tsc = 1; 63 asm volatile("mrs %0, cntvct_el0" : "=r" (tsc)); 64 return tsc; 65 #else 66 return static_cast<uint64_t>(std::chrono::time_point_cast<std::chrono::microseconds>( 67 std::chrono::steady_clock::now()).time_since_epoch().count()); 68 #endif 69 } 70 FfrtBeUsed()71 static inline bool FfrtBeUsed() 72 { 73 return ffrt_be_used_; 74 } 75 StatEnable(char * buf,uint32_t len)76 static int StatEnable(char *buf, uint32_t len) 77 { 78 FFRT_LOGW("StatEnable, buffer addr = 0x%pK, size = %u", buf, len); 79 if (len < TASK_STAT_LENGTH) { 80 FFRT_LOGE("Buffer size is not enough, len = %u", len); 81 return -1; 82 } 83 if (stat_enable_) { 84 FFRT_LOGW("Statistics are already enabled."); 85 return -1; 86 } 87 if (ringBuffer_ != nullptr) { 88 FFRT_LOGW( 89 "Buffer has been set, do not set again. " 90 "Previous buffer start addr = %p, size = %u", 91 ringBuffer_->GetBuffer(), ringBuffer_->GetBufferSize()); 92 return -1; 93 } 94 ringBuffer_ = std::make_unique<FFRTRingBuffer>(buf, len); 95 stat_enable_ = true; 96 return 0; 97 } 98 StatsDisable(char * buf)99 static int StatsDisable(char *buf) 100 { 101 FFRT_LOGW("StatsDisable"); 102 if (ringBuffer_ == nullptr) { 103 FFRT_LOGW("StatsDisable: ringBuffer_ is already nullptr"); 104 return -1; 105 } 106 107 if (buf != ringBuffer_->GetBuffer()) { 108 FFRT_LOGW( 109 "Buffer addr invalid " 110 "Previous buffer addr = %p, now is = %p", 111 ringBuffer_->GetBuffer(), buf); 112 return -1; 113 } 114 115 stat_enable_ = false; 116 ringBuffer_.reset(); 117 return 0; 118 } 119 UseFfrt()120 static inline void UseFfrt() 121 { 122 if (unlikely(!ffrt_be_used_)) { 123 ffrt_be_used_ = true; 124 } 125 } 126 127 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos)128 static inline void TaskSubmit(int qos) 129 { 130 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 131 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 132 #endif 133 } 134 TaskSubmit(uint64_t * createTime,int32_t * fromTid)135 static inline void TaskSubmit(uint64_t* createTime, int32_t* fromTid) 136 { 137 *createTime = TimeStamp(); 138 *fromTid = ExecuteCtx::Cur()->tid; 139 } 140 141 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos,uint64_t * createTime,int32_t * fromTid)142 static inline void TaskSubmit(int qos, uint64_t* createTime, int32_t* fromTid) 143 { 144 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 145 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 146 #endif 147 *createTime = TimeStamp(); 148 *fromTid = ExecuteCtx::Cur()->tid; 149 } 150 TaskExecute(uint64_t * executeTime)151 static inline void TaskExecute(uint64_t* executeTime) 152 { 153 *executeTime = TimeStamp(); 154 } 155 156 template<ffrt_executor_task_type_t taskType> TaskExecute(int qos)157 static inline void TaskExecute(int qos) 158 { 159 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 160 g_recordTaskCounter_[taskType][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 161 #endif 162 } 163 164 template<ffrt_executor_task_type_t taskType> TaskDone(int qos)165 static inline void TaskDone(int qos) 166 { 167 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 168 g_recordTaskCounter_[taskType][qos].doneCounter.fetch_add(1, std::memory_order_relaxed); 169 #endif 170 } 171 172 template<ffrt_executor_task_type_t taskType> TaskDone(int qos,TaskBase * task)173 static void TaskDone(int qos, TaskBase* task) 174 { 175 if (stat_enable_) { 176 uint64_t endTime = TimeStamp(); 177 ffrt_stat stat; 178 errno_t ret; 179 if (taskType == ffrt_normal_task) { 180 auto baseTask = reinterpret_cast<CPUEUTask*>(task); 181 auto f = reinterpret_cast<ffrt_function_header_t*>(baseTask->func_storage); 182 baseTask->label.resize(MAX_TASK_NAME_LENGTH - 1, ' '); 183 ret = strcpy_s(stat.taskName, MAX_TASK_NAME_LENGTH, baseTask->label.c_str()); 184 stat.funcPtr = reinterpret_cast<uint64_t>(f->exec); 185 } 186 if (taskType == ffrt_queue_task) { 187 auto baseTask = reinterpret_cast<QueueTask*>(task); 188 auto f = reinterpret_cast<ffrt_function_header_t*>(baseTask->func_storage); 189 baseTask->label.resize(MAX_TASK_NAME_LENGTH - 1, ' '); 190 ret = strcpy_s(stat.taskName, MAX_TASK_NAME_LENGTH, baseTask->label.c_str()); 191 stat.funcPtr = reinterpret_cast<uint64_t>(f->exec); 192 } 193 if (ret != EOK) { 194 FFRT_LOGE("strcpy_s failed"); 195 return; 196 } 197 stat.startTime = task->createTime; 198 stat.endTime = endTime; 199 ringBuffer_->Write(stat); 200 } 201 202 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 203 auto runDuration = TimeStamp() - task->executeTime; 204 g_recordTaskTime_[taskType][qos].runDuration += runDuration; 205 206 if (g_recordTaskTime_[taskType][qos].maxRunDuration < runDuration) { 207 g_recordTaskTime_[taskType][qos].maxRunDuration = runDuration; 208 } 209 210 auto waitTime = task->executeTime - task->createTime; 211 g_recordTaskTime_[taskType][qos].waitTime += waitTime; 212 if (g_recordTaskTime_[taskType][qos].maxWaitTime < waitTime) { 213 g_recordTaskTime_[taskType][qos].maxWaitTime = waitTime; 214 } 215 #endif 216 } 217 218 template<ffrt_executor_task_type_t taskType> TaskEnqueue(int qos)219 static inline void TaskEnqueue(int qos) 220 { 221 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 222 g_recordTaskCounter_[taskType][qos].enqueueCounter.fetch_add(1, std::memory_order_relaxed); 223 #endif 224 } 225 226 template<ffrt_executor_task_type_t taskType> TaskCancel(int qos)227 static inline void TaskCancel(int qos) 228 { 229 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 230 g_recordTaskCounter_[taskType][qos].cancelCounter.fetch_add(1, std::memory_order_relaxed); 231 #endif 232 } 233 TaskRun(int qos,TaskBase * task)234 static inline void TaskRun(int qos, TaskBase* task) 235 { 236 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 237 g_recordTaskCounter_[task->type][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 238 #endif 239 } 240 TaskCoSwitchOut(TaskBase * task)241 static inline void TaskCoSwitchOut(TaskBase* task) 242 { 243 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 244 g_recordTaskCounter_[task->type][task->GetQos()].coSwitchCounter.fetch_add(1, std::memory_order_relaxed); 245 #endif 246 } 247 WorkRecord(int qos,int workerNum)248 static inline void WorkRecord(int qos, int workerNum) 249 { 250 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 251 if (g_recordMaxWorkerNumber_[qos] < workerNum) { 252 g_recordMaxWorkerNumber_[qos] = workerNum; 253 } 254 #endif 255 } 256 257 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 258 static int StatisticInfoDump(char* buf, uint32_t len); 259 static void DumpNormalTaskStatisticInfo(std::ostringstream& oss); 260 static void DumpQueueTaskStatisticInfo(std::ostringstream& oss); 261 static void DumpUVTaskStatisticInfo(std::ostringstream& oss); 262 263 static unsigned int GetSubmitCount(); 264 static unsigned int GetEnqueueCount(); 265 static unsigned int GetRunCount(); 266 static unsigned int GetDoneCount(); 267 static unsigned int GetCoSwitchCount(); 268 static unsigned int GetFinishCount(); 269 #endif 270 271 private: 272 static std::unique_ptr<FFRTRingBuffer> ringBuffer_; 273 }; 274 } 275 #endif // FFRT_TRACE_RECORD_H 276