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 "internal_inc/osal.h" 19 #include "tm/task_base.h" 20 21 #define FFRT_TRACE_RECORD_LEVEL_1 (1) 22 #define FFRT_TRACE_RECORD_LEVEL_2 (2) 23 #define FFRT_TRACE_RECORD_LEVEL_3 (3) 24 25 namespace ffrt { 26 typedef struct ffrt_record_task_counter { alignasffrt_record_task_counter27 alignas(cacheline_size) std::atomic<unsigned int> submitCounter{0}; alignasffrt_record_task_counter28 alignas(cacheline_size) std::atomic<unsigned int> enqueueCounter{0}; alignasffrt_record_task_counter29 alignas(cacheline_size) std::atomic<unsigned int> coSwitchCounter{0}; alignasffrt_record_task_counter30 alignas(cacheline_size) std::atomic<unsigned int> runCounter{0}; alignasffrt_record_task_counter31 alignas(cacheline_size) std::atomic<unsigned int> doneCounter{0}; alignasffrt_record_task_counter32 alignas(cacheline_size) std::atomic<unsigned int> cancelCounter{0}; 33 } ffrt_record_task_counter_t; 34 35 typedef struct ffrt_record_task_time { 36 std::atomic<uint64_t> waitTime{0}; 37 std::atomic<uint64_t> runDuration{0}; 38 std::atomic<uint64_t> executeTime{0}; 39 uint64_t maxWaitTime{0}; 40 uint64_t maxRunDuration{0}; 41 } ffrt_record_task_time_t; 42 43 class FFRTTraceRecord { 44 public: 45 static const int TASK_TYPE_NUM = ffrt_queue_task + 1; 46 static bool ffrt_be_used_; 47 static int g_recordMaxWorkerNumber_[QoS::MaxNum()]; 48 static ffrt_record_task_counter_t g_recordTaskCounter_[TASK_TYPE_NUM][QoS::MaxNum()]; 49 static ffrt_record_task_time_t g_recordTaskTime_[TASK_TYPE_NUM][QoS::MaxNum()]; 50 51 public: 52 FFRTTraceRecord() = default; 53 ~FFRTTraceRecord() = default; TimeStamp(void)54 static inline uint64_t TimeStamp(void) 55 { 56 #if defined(__aarch64__) 57 uint64_t tsc = 1; 58 asm volatile("mrs %0, cntvct_el0" : "=r" (tsc)); 59 return tsc; 60 #else 61 return static_cast<uint64_t>(std::chrono::time_point_cast<std::chrono::microseconds>( 62 std::chrono::steady_clock::now()).time_since_epoch().count()); 63 #endif 64 } 65 FfrtBeUsed()66 static inline bool FfrtBeUsed() 67 { 68 return ffrt_be_used_; 69 } 70 UseFfrt()71 static inline void UseFfrt() 72 { 73 if (unlikely(!ffrt_be_used_)) { 74 ffrt_be_used_ = true; 75 } 76 } 77 78 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos)79 static inline void TaskSubmit(int qos) 80 { 81 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 82 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 83 #endif 84 } 85 TaskSubmit(uint64_t * createTime,int32_t * fromTid)86 static inline void TaskSubmit(uint64_t* createTime, int32_t* fromTid) 87 { 88 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1) 89 *createTime = TimeStamp(); 90 *fromTid = ExecuteCtx::Cur()->tid; 91 #endif 92 } 93 94 template<ffrt_executor_task_type_t taskType> TaskSubmit(int qos,uint64_t * createTime,int32_t * fromTid)95 static inline void TaskSubmit(int qos, uint64_t* createTime, int32_t* fromTid) 96 { 97 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 98 g_recordTaskCounter_[taskType][qos].submitCounter.fetch_add(1, std::memory_order_relaxed); 99 #endif 100 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1) 101 *createTime = TimeStamp(); 102 *fromTid = ExecuteCtx::Cur()->tid; 103 #endif 104 } 105 TaskExecute(uint64_t * executeTime)106 static inline void TaskExecute(uint64_t* executeTime) 107 { 108 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_1) 109 *executeTime = TimeStamp(); 110 #endif 111 } 112 113 template<ffrt_executor_task_type_t taskType> TaskExecute(int qos)114 static inline void TaskExecute(int qos) 115 { 116 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 117 g_recordTaskCounter_[taskType][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 118 #endif 119 } 120 121 template<ffrt_executor_task_type_t taskType> TaskDone(int qos)122 static inline void TaskDone(int qos) 123 { 124 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 125 g_recordTaskCounter_[taskType][qos].doneCounter.fetch_add(1, std::memory_order_relaxed); 126 #endif 127 } 128 129 template<ffrt_executor_task_type_t taskType> TaskDone(int qos,TaskBase * task)130 static inline void TaskDone(int qos, TaskBase* task) 131 { 132 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 133 auto runDuration = TimeStamp() - task->executeTime; 134 g_recordTaskTime_[taskType][qos].runDuration += runDuration; 135 136 if (g_recordTaskTime_[taskType][qos].maxRunDuration < runDuration) { 137 g_recordTaskTime_[taskType][qos].maxRunDuration = runDuration; 138 } 139 140 auto waitTime = task->executeTime - task->createTime; 141 g_recordTaskTime_[taskType][qos].waitTime += waitTime; 142 if (g_recordTaskTime_[taskType][qos].maxWaitTime < waitTime) { 143 g_recordTaskTime_[taskType][qos].maxWaitTime = waitTime; 144 } 145 #endif 146 } 147 148 template<ffrt_executor_task_type_t taskType> TaskEnqueue(int qos)149 static inline void TaskEnqueue(int qos) 150 { 151 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 152 g_recordTaskCounter_[taskType][qos].enqueueCounter.fetch_add(1, std::memory_order_relaxed); 153 #endif 154 } 155 156 template<ffrt_executor_task_type_t taskType> TaskCancel(int qos)157 static inline void TaskCancel(int qos) 158 { 159 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 160 g_recordTaskCounter_[taskType][qos].cancelCounter.fetch_add(1, std::memory_order_relaxed); 161 #endif 162 } 163 TaskRun(int qos,TaskBase * task)164 static inline void TaskRun(int qos, TaskBase* task) 165 { 166 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 167 g_recordTaskCounter_[task->type][qos].runCounter.fetch_add(1, std::memory_order_relaxed); 168 #endif 169 } 170 TaskCoSwitchOut(TaskBase * task)171 static inline void TaskCoSwitchOut(TaskBase* task) 172 { 173 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 174 g_recordTaskCounter_[task->type][task->GetQos()].coSwitchCounter.fetch_add(1, std::memory_order_relaxed); 175 #endif 176 } 177 WorkRecord(int qos,int workerNum)178 static inline void WorkRecord(int qos, int workerNum) 179 { 180 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_3) 181 if (g_recordMaxWorkerNumber_[qos] < workerNum) { 182 g_recordMaxWorkerNumber_[qos] = workerNum; 183 } 184 #endif 185 } 186 187 #if (FFRT_TRACE_RECORD_LEVEL >= FFRT_TRACE_RECORD_LEVEL_2) 188 static int StatisticInfoDump(char* buf, uint32_t len); 189 static void DumpNormalTaskStatisticInfo(std::ostringstream& oss); 190 static void DumpQueueTaskStatisticInfo(std::ostringstream& oss); 191 static void DumpUVTaskStatisticInfo(std::ostringstream& oss); 192 193 static unsigned int GetSubmitCount(); 194 static unsigned int GetEnqueueCount(); 195 static unsigned int GetRunCount(); 196 static unsigned int GetDoneCount(); 197 static unsigned int GetCoSwitchCount(); 198 static unsigned int GetFinishCount(); 199 #endif 200 }; 201 } 202 #endif // FFRT_TRACE_RECORD_H 203