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 
16 #ifndef __FFRT_TRACE_H__
17 #define __FFRT_TRACE_H__
18 
19 #include <atomic>
20 #include <chrono>
21 #include "internal_inc/osal.h"
22 #include "dfx/log/ffrt_log_api.h"
23 
24 #ifdef FFRT_OH_TRACE_ENABLE
25 #include <dlfcn.h>
26 #endif
27 
28 namespace ffrt {
29 enum TraceLevel {
30     TRACE_LEVEL0 = 0,
31     TRACE_LEVEL1,
32     TRACE_LEVEL2,
33     TRACE_LEVEL3, // lowest level, trace all
34     TRACE_LEVEL_MAX,
35 };
36 
37 class TraceLevelManager {
38 public:
39     TraceLevelManager();
40     ~TraceLevelManager() = default;
41 
GetTraceLevel()42     uint64_t GetTraceLevel() const
43     {
44         return traceLevel_;
45     }
46 
Instance()47     static inline TraceLevelManager* Instance()
48     {
49         static TraceLevelManager ins;
50         return &ins;
51     }
52 
53 private:
54     uint8_t traceLevel_;
55 };
56 
57 class ScopedTrace {
58 public:
59     ScopedTrace(uint64_t level, const char* name);
60     ~ScopedTrace();
61 
62 private:
63     std::atomic<bool> isTraceEnable_;
64 };
65 } // namespace ffrt
66 
67 #ifdef FFRT_OH_TRACE_ENABLE
68 constexpr uint64_t HITRACE_TAG_FFRT = (1ULL << 13); // ffrt tasks.
69 bool IsTagEnabled(uint64_t tag);
70 void StartTrace(uint64_t label, const std::string& value, float limit = -1);
71 void FinishTrace(uint64_t label);
72 void StartAsyncTrace(uint64_t label, const std::string& value, int32_t taskId, float limit = -1);
73 void FinishAsyncTrace(uint64_t label, const std::string& value, int32_t taskId);
74 void CountTrace(uint64_t label, const std::string& name, int64_t count);
75 #ifdef APP_USE_ARM
76 static const std::string TRACE_LIB_PATH = "/system/lib/chipset-pub-sdk/libhitrace_meter.so";
77 #else
78 static const std::string TRACE_LIB_PATH = "/system/lib64/chipset-pub-sdk/libhitrace_meter.so";
79 #endif
80 class TraceAdapter {
81 public:
TraceAdapter()82     TraceAdapter()
83     {
84         Load();
85     }
86 
~TraceAdapter()87     ~TraceAdapter()
88     {
89         UnLoad();
90     }
91 
Instance()92     static TraceAdapter* Instance()
93     {
94         static TraceAdapter instance;
95         return &instance;
96     }
97 
98 #define REG_FUNC(func) using func##Type = decltype(func)*; func##Type func = nullptr
99     REG_FUNC(IsTagEnabled);
100     REG_FUNC(StartTrace);
101     REG_FUNC(FinishTrace);
102     REG_FUNC(StartAsyncTrace);
103     REG_FUNC(FinishAsyncTrace);
104     REG_FUNC(CountTrace);
105 #undef REG_FUNC
106 
107 private:
Load()108     bool Load()
109     {
110         if (handle != nullptr) {
111             FFRT_LOGD("handle exits");
112             return true;
113         }
114 
115         handle = dlopen(TRACE_LIB_PATH.c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
116         if (handle == nullptr) {
117             FFRT_LOGE("load so[%s] fail", TRACE_LIB_PATH.c_str());
118             return false;
119         }
120 
121 #define LOAD_FUNC(x) x = reinterpret_cast<x##Type>(dlsym(handle, #x));                        \
122         if (x == nullptr)                                                                     \
123         {                                                                                     \
124             FFRT_LOGE("load func %s from %s failed", #x, TRACE_LIB_PATH.c_str());             \
125             return false;                                                                     \
126         }
127             LOAD_FUNC(IsTagEnabled);
128             LOAD_FUNC(StartTrace);
129             LOAD_FUNC(FinishTrace);
130             LOAD_FUNC(StartAsyncTrace);
131             LOAD_FUNC(FinishAsyncTrace);
132             LOAD_FUNC(CountTrace);
133 #undef LOAD_FUNC
134         return true;
135     }
136 
UnLoad()137     bool UnLoad()
138     {
139         if (handle != nullptr) {
140             if (dlclose(handle) != 0) {
141                 return false;
142             }
143             handle = nullptr;
144             return true;
145         }
146         return true;
147     }
148 
149     void* handle = nullptr;
150 };
151 
152 #define GET_TRACE_FUNC(x) (TraceAdapter::Instance()->x)
153 
_IsTagEnabled(uint64_t label)154 static bool _IsTagEnabled(uint64_t label)
155 {
156     auto func = GET_TRACE_FUNC(IsTagEnabled);
157     if (func != nullptr) {
158         return func(label);
159     }
160     return false;
161 }
162 #define _StartTrace(label, tag, limit) \
163     do { \
164         auto func = GET_TRACE_FUNC(StartTrace); \
165         if (func != nullptr) { \
166             func(label, tag, limit); \
167         } \
168     } while (0)
169 #define _FinishTrace(label) \
170     do { \
171         auto func = GET_TRACE_FUNC(FinishTrace); \
172         if (func != nullptr) { \
173             func(label); \
174         } \
175     } while (0)
176 #define _StartAsyncTrace(label, tag, tid, limit) \
177     do { \
178         auto func = GET_TRACE_FUNC(StartAsyncTrace); \
179         if (func != nullptr) { \
180             func(label, tag, tid, limit); \
181         } \
182     } while (0)
183 #define _FinishAsyncTrace(label, tag, tid) \
184     do { \
185         auto func = GET_TRACE_FUNC(FinishAsyncTrace); \
186         if (func != nullptr) { \
187             func(label, tag, tid); \
188         } \
189     } while (0)
190 #define _TraceCount(label, tag, value) \
191     do { \
192         auto func = GET_TRACE_FUNC(CountTrace); \
193         if (func != nullptr) { \
194             func(label, tag, value); \
195         } \
196     } while (0)
197 
198 #define FFRT_TRACE_BEGIN(tag) \
199     do { \
200         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
201             _StartTrace(HITRACE_TAG_FFRT, tag, -1); \
202     } while (false)
203 #define FFRT_TRACE_END() \
204     do { \
205         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
206             _FinishTrace(HITRACE_TAG_FFRT); \
207     } while (false)
208 #define FFRT_TRACE_ASYNC_BEGIN(tag, tid) \
209     do { \
210         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
211             _StartAsyncTrace(HITRACE_TAG_FFRT, tag, tid, -1); \
212     } while (false)
213 #define FFRT_TRACE_ASYNC_END(tag, tid) \
214     do { \
215         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
216             _FinishAsyncTrace(HITRACE_TAG_FFRT, tag, tid); \
217     } while (false)
218 #define FFRT_TRACE_COUNT(tag, value) \
219     do { \
220         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
221             _TraceCount(HITRACE_TAG_FFRT, tag, value); \
222     } while (false)
223 #define FFRT_TASK_BEGIN(tag, gid) \
224     do { \
225         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
226             _StartTrace(HITRACE_TAG_FFRT, ("FFRT" + (tag) + "|" + std::to_string(gid)).c_str(), -1); \
227     } while (false)
228 #define FFRT_BLOCK_TRACER(gid, tag) \
229     do { \
230         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
231             _StartTrace(HITRACE_TAG_FFRT, ("FFBK" #tag "|" + std::to_string(gid)).c_str(), -1); \
232         FFRT_TRACE_END(); \
233     } while (false)
234 #define FFRT_WAKE_TRACER(gid) \
235     do { \
236         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
237             _StartTrace(HITRACE_TAG_FFRT, ("FFWK|" + std::to_string(gid)).c_str(), -1); \
238         FFRT_TRACE_END(); \
239     } while (false)
240 #define FFRT_EXECUTOR_TASK_BEGIN(ptr) \
241     do { \
242         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
243             _StartTrace(HITRACE_TAG_FFRT, ("FFRTex_task|" + \
244                 std::to_string(((reinterpret_cast<uintptr_t>(ptr)) & 0x11111111))).c_str(), -1); \
245     } while (false)
246 #define FFRT_SERIAL_QUEUE_TASK_SUBMIT_MARKER(qid, gid) \
247     do { \
248         if (__builtin_expect(!!(_IsTagEnabled(HITRACE_TAG_FFRT)), 0)) \
249             _StartTrace(HITRACE_TAG_FFRT, ("P[sq_" + \
250                 std::to_string(qid) + "]|" + std::to_string(gid)).c_str(), -1); \
251         FFRT_TRACE_END(); \
252     } while (false)
253 #define FFRT_TRACE_SCOPE(level, tag) ffrt::ScopedTrace ___tracer##tag(level, #tag)
254 #else
255 #define FFRT_TRACE_BEGIN(tag)
256 #define FFRT_TRACE_END()
257 #define FFRT_TRACE_ASYNC_BEGIN(tag, tid)
258 #define FFRT_TRACE_ASYNC_END(tag, tid)
259 #define FFRT_TRACE_COUNT(tag, value)
260 #define FFRT_TRACE_SCOPE(level, tag)
261 #define FFRT_TASK_BEGIN(tag, gid)
262 #define FFRT_BLOCK_TRACER(gid, tag)
263 #define FFRT_WAKE_TRACER(gid)
264 #define FFRT_EXECUTOR_TASK_BEGIN(ptr)
265 #define FFRT_SERIAL_QUEUE_TASK_SUBMIT_MARKER(qid, gid)
266 #endif
267 
268 // DFX Trace for FFRT Normal Task
269 #define FFRT_WORKER_IDLE_BEGIN_MARKER()
270 #define FFRT_WORKER_IDLE_END_MARKER()
271 #define FFRT_SUBMIT_MARKER(tag, gid) \
272     { \
273         FFRT_TRACE_ASYNC_END("P", gid); \
274     }
275 #define FFRT_READY_MARKER(gid) \
276     { \
277         FFRT_TRACE_ASYNC_END("R", gid); \
278     }
279 #define FFRT_BLOCK_MARKER(gid) \
280     { \
281         FFRT_TRACE_ASYNC_END("B", gid); \
282     }
283 #define FFRT_TASKDONE_MARKER(gid) \
284     { \
285         FFRT_TRACE_ASYNC_END("F", gid); \
286     }
287 #define FFRT_FAKE_TRACE_MARKER(gid) \
288     { \
289         FFRT_TRACE_ASYNC_END("Co", gid); \
290     }
291 #define FFRT_TASK_END() \
292     { \
293         FFRT_TRACE_END(); \
294     }
295 
296 // DFX Trace for FFRT Executor Task
297 #define FFRT_EXECUTOR_TASK_SUBMIT_MARKER(ptr) \
298     { \
299         FFRT_TRACE_ASYNC_END("P", ((reinterpret_cast<uintptr_t>(ptr)) & 0x11111111)); \
300     }
301 #define FFRT_EXECUTOR_TASK_READY_MARKER(ptr) \
302     { \
303         FFRT_TRACE_ASYNC_END("R", ((reinterpret_cast<uintptr_t>(ptr)) & 0x11111111)); \
304     }
305 #define FFRT_EXECUTOR_TASK_BLOCK_MARKER(ptr) \
306     { \
307         FFRT_TRACE_ASYNC_END("B", ((reinterpret_cast<uintptr_t>(ptr)) & 0x11111111)); \
308     }
309 #define FFRT_EXECUTOR_TASK_FINISH_MARKER(ptr) \
310     { \
311         FFRT_TRACE_ASYNC_END("F", ((reinterpret_cast<uintptr_t>(ptr)) & 0x11111111)); \
312     }
313 
314 #define FFRT_EXECUTOR_TASK_END() \
315     { \
316         FFRT_TRACE_END(); \
317     }
318 
319 // DFX Trace for FFRT Serial Queue Task
320 #define FFRT_SERIAL_QUEUE_TASK_EXECUTE_MARKER(gid) \
321     { \
322         FFRT_TRACE_ASYNC_END("E", gid); \
323     }
324 #define FFRT_SERIAL_QUEUE_TASK_FINISH_MARKER(gid) \
325     { \
326         FFRT_TRACE_ASYNC_END("D", gid); \
327     }
328 #endif