• 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 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