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