• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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