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 std::atomic<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; 59 FfrtBeUsed()60 static inline bool FfrtBeUsed() 61 { 62 return ffrt_be_used_; 63 } 64 StatEnable(char * buf,uint32_t len)65 static int StatEnable(char *buf, uint32_t len) 66 { 67 if (len < TASK_STAT_LENGTH) { 68 FFRT_LOGE("Buffer size is not enough, len = %u", len); 69 return -1; 70 } 71 if (stat_enable_) { 72 FFRT_LOGW("Statistics are already enabled."); 73 return -1; 74 } 75 if (ringBuffer_ != nullptr) { 76 FFRT_LOGW( 77 "Buffer has been set, do not set again. " 78 "Previous buffer start addr = %p, size = %u", 79 ringBuffer_->GetBuffer(), ringBuffer_->GetBufferSize()); 80 return -1; 81 } 82 ringBuffer_ = std::make_unique<FFRTRingBuffer>(buf, len); 83 stat_enable_ = true; 84 return 0; 85 } 86 StatsDisable(char * buf)87 static int StatsDisable(char *buf) 88 { 89 FFRT_LOGW("StatsDisable"); 90 if (ringBuffer_ == nullptr) { 91 FFRT_LOGW("StatsDisable: ringBuffer_ is already nullptr"); 92 return -1; 93 } 94 95 if (buf != ringBuffer_->GetBuffer()) { 96 FFRT_LOGW( 97 "Buffer addr invalid " 98 "Previous buffer addr = %p, now is = %p", 99 ringBuffer_->GetBuffer(), buf); 100 return -1; 101 } 102 103 stat_enable_ = false; 104 ringBuffer_.reset(); 105 return 0; 106 } 107 UseFfrt()108 static inline void UseFfrt() 109 { 110 if (unlikely(!ffrt_be_used_)) { 111 ffrt_be_used_ = true; 112 } 113 } 114 115 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos)116 static inline void TaskSubmit(int qos) 117 { 118 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 119 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 120 #endif 121 } 122 TaskSubmit(uint64_t * createTime,int32_t * fromTid)123 static inline void TaskSubmit(uint64_t* createTime, int32_t* fromTid) 124 { 125 *createTime = TimeStamp(); 126 *fromTid = ExecuteCtx::Cur()->tid; 127 } 128 129 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos,uint64_t * createTime,int32_t * fromTid)130 static inline void TaskSubmit(int qos, uint64_t* createTime, int32_t* fromTid) 131 { 132 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 133 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 134 #endif 135 *createTime = TimeStamp(); 136 *fromTid = ExecuteCtx::Cur()->tid; 137 } 138 TaskExecute(uint64_t * executeTime)139 static inline void TaskExecute(uint64_t* executeTime) 140 { 141 *executeTime = TimeStamp(); 142 } 143 144 template<ffrt_executor_task_type_t taskType> TaskExecute(int qos)145 static inline void TaskExecute(int qos) 146 { 147 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 148 g_recordTaskCounter_[taskType][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 149 #endif 150 } 151 152 template<ffrt_executor_task_type_t taskType> TaskDone(int qos)153 static inline void TaskDone(int qos) 154 { 155 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 156 g_recordTaskCounter_[taskType][qos].doneCounter.fetch_add(1, std::memory_order_relaxed); 157 #endif 158 } 159 160 template<ffrt_executor_task_type_t taskType> TaskDone(int qos,TaskBase * task)161 static void TaskDone(int qos, TaskBase* task) 162 { 163 if (stat_enable_) { 164 uint64_t endTime = TimeStamp(); 165 ffrt_stat stat; 166 errno_t ret; 167 if (taskType == ffrt_normal_task) { 168 auto baseTask = reinterpret_cast<CPUEUTask*>(task); 169 auto f = reinterpret_cast<ffrt_function_header_t*>(baseTask->func_storage); 170 baseTask->label.resize(MAX_TASK_NAME_LENGTH - 1, ' '); 171 ret = strcpy_s(stat.taskName, MAX_TASK_NAME_LENGTH, baseTask->GetLabel().c_str()); 172 stat.funcPtr = reinterpret_cast<uint64_t>(f->exec); 173 } 174 if (taskType == ffrt_queue_task) { 175 auto baseTask = reinterpret_cast<QueueTask*>(task); 176 auto f = reinterpret_cast<ffrt_function_header_t*>(baseTask->func_storage); 177 baseTask->label.resize(MAX_TASK_NAME_LENGTH - 1, ' '); 178 ret = strcpy_s(stat.taskName, MAX_TASK_NAME_LENGTH, baseTask->GetLabel().c_str()); 179 stat.funcPtr = reinterpret_cast<uint64_t>(f->exec); 180 } 181 if (ret != EOK) { 182 FFRT_LOGE("strcpy_s failed"); 183 return; 184 } 185 stat.startTime = task->createTime; 186 stat.endTime = endTime; 187 ringBuffer_->Write(stat); 188 } 189 190 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 191 auto runDuration = TimeStamp() - task->executeTime; 192 g_recordTaskTime_[taskType][qos].runDuration += runDuration; 193 194 if (g_recordTaskTime_[taskType][qos].maxRunDuration < runDuration) { 195 g_recordTaskTime_[taskType][qos].maxRunDuration = runDuration; 196 } 197 198 auto waitTime = task->executeTime - task->createTime; 199 g_recordTaskTime_[taskType][qos].waitTime += waitTime; 200 if (g_recordTaskTime_[taskType][qos].maxWaitTime < waitTime) { 201 g_recordTaskTime_[taskType][qos].maxWaitTime = waitTime; 202 } 203 #endif 204 } 205 206 template<ffrt_executor_task_type_t taskType> TaskEnqueue(int qos)207 static inline void TaskEnqueue(int qos) 208 { 209 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 210 g_recordTaskCounter_[taskType][qos].enqueueCounter.fetch_add(1, std::memory_order_relaxed); 211 #endif 212 } 213 214 template<ffrt_executor_task_type_t taskType> TaskCancel(int qos)215 static inline void TaskCancel(int qos) 216 { 217 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 218 g_recordTaskCounter_[taskType][qos].cancelCounter.fetch_add(1, std::memory_order_relaxed); 219 #endif 220 } 221 TaskRun(int qos,TaskBase * task)222 static inline void TaskRun(int qos, TaskBase* task) 223 { 224 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 225 g_recordTaskCounter_[task->type][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 226 #endif 227 } 228 TaskCoSwitchOut(TaskBase * task)229 static inline void TaskCoSwitchOut(TaskBase* task) 230 { 231 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 232 g_recordTaskCounter_[task->type][task->GetQos()].coSwitchCounter.fetch_add(1, std::memory_order_relaxed); 233 #endif 234 } 235 WorkRecord(int qos,int workerNum)236 static inline void WorkRecord(int qos, int workerNum) 237 { 238 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 239 if (g_recordMaxWorkerNumber_[qos] < workerNum) { 240 g_recordMaxWorkerNumber_[qos] = workerNum; 241 } 242 #endif 243 } 244 245 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 246 static int StatisticInfoDump(char* buf, uint32_t len); 247 static void DumpNormalTaskStatisticInfo(std::ostringstream& oss); 248 static void DumpQueueTaskStatisticInfo(std::ostringstream& oss); 249 static void DumpUVTaskStatisticInfo(std::ostringstream& oss); 250 251 static unsigned int GetSubmitCount(); 252 static unsigned int GetEnqueueCount(); 253 static unsigned int GetRunCount(); 254 static unsigned int GetDoneCount(); 255 static unsigned int GetCoSwitchCount(); 256 static unsigned int GetFinishCount(); 257 #endif 258 259 private: 260 static std::unique_ptr<FFRTRingBuffer> ringBuffer_; 261 }; 262 } 263 #endif // FFRT_TRACE_RECORD_H 264