• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 #include "hitrace/hitracechainc.h"
17 
18 #include <sched.h>
19 #include <stdatomic.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/time.h>
24 
25 #include "hilog/log.h"
26 #include "hilog_trace.h"
27 #include "hitracechain_inner.h"
28 #include "hitrace_meter_wrapper.h"
29 #include "hitrace_meter_c.h"
30 #include "securec.h"
31 
32 #ifdef LOG_DOMAIN
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN 0xD002D33
35 #endif
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #define LOG_TAG "HiTraceC"
39 #endif
40 
41 static const int BUFF_ZERO_NUMBER = 0;
42 static const int BUFF_ONE_NUMBER = 1;
43 static const int BUFF_TWO_NUMBER = 2;
44 
45 typedef struct HiTraceChainIdStruct {
46     union {
47 #if __BYTE_ORDER == __LITTLE_ENDIAN
48         struct {
49             uint64_t reserved : 4;
50             uint64_t usecond : 20;
51             uint64_t second : 16;
52             uint64_t cpuId : 4;
53             uint64_t deviceId : 20;
54         };
55         struct {
56             uint64_t padding : 4;
57             uint64_t chainId : 60;
58         };
59 #elif __BYTE_ORDER == __BIG_ENDIAN
60         struct {
61             uint64_t deviceId : 20;
62             uint64_t cpuId : 4;
63             uint64_t second : 16;
64             uint64_t usecond : 20;
65             uint64_t reserved : 4;
66         };
67         struct {
68             uint64_t chainId : 60;
69             uint64_t padding : 4;
70         };
71 #else
72 #error "ERROR: No BIG_LITTLE_ENDIAN defines."
73 #endif
74     };
75 } HiTraceChainIdStruct;
76 
77 typedef struct HiTraceIdStructExtra {
78     uint32_t setTls : 1;
79     uint32_t reserved : 31;
80 } HiTraceIdStructExtra;
81 
82 typedef struct HiTraceIdStructInner {
83     HiTraceIdStruct id;
84     HiTraceIdStructExtra extra;
85 } HiTraceIdStructInner;
86 
87 static __thread HiTraceIdStructInner g_hiTraceId = {{0, 0, 0, 0, 0, 0}, {0, 0}};
88 
GetThreadIdInner(void)89 static inline HiTraceIdStructInner* GetThreadIdInner(void)
90 {
91     return &g_hiTraceId;
92 }
93 
HiTraceChainGetId(void)94 HiTraceIdStruct HiTraceChainGetId(void)
95 {
96     HiTraceIdStructInner* pThreadId = GetThreadIdInner();
97     return pThreadId->id;
98 }
99 
HiTraceChainSetId(const HiTraceIdStruct * pId)100 void HiTraceChainSetId(const HiTraceIdStruct* pId)
101 {
102     if (!HiTraceChainIsValid(pId)) {
103         return;
104     }
105 
106     HiTraceIdStructInner* pThreadId = GetThreadIdInner();
107     pThreadId->id = *pId;
108     return;
109 }
110 
HiTraceChainClearId(void)111 void HiTraceChainClearId(void)
112 {
113     HiTraceIdStructInner* pThreadId = GetThreadIdInner();
114     HiTraceChainInitId(&(pThreadId->id));
115     return;
116 }
117 
HiTraceChainGetDeviceId(void)118 static inline int HiTraceChainGetDeviceId(void)
119 {
120     // save device id and use it later
121     static atomic_int deviceId = 0;
122 
123     if (deviceId == 0) {
124         struct timeval tv;
125         gettimeofday(&tv, NULL);
126         srand(tv.tv_sec);
127         deviceId = random();
128     }
129     return deviceId;
130 }
131 
HiTraceChainGetCpuId(void)132 static inline unsigned int HiTraceChainGetCpuId(void)
133 {
134     // Using vdso call will make get_cpu_id faster: sched_getcpu()
135     static atomic_uint cpuId = 0;
136     cpuId++;
137 
138     return cpuId;
139 }
140 
HiTraceChainCreateChainId(void)141 static inline uint64_t HiTraceChainCreateChainId(void)
142 {
143     // get timestamp. Using vdso call(no system call)
144     struct timeval tv;
145     gettimeofday(&tv, NULL);
146     HiTraceChainIdStruct chainId = {
147         .padding = 0,
148         .chainId = 0
149     };
150     chainId.deviceId = (uint64_t)(HiTraceChainGetDeviceId());
151     chainId.cpuId = HiTraceChainGetCpuId();
152     chainId.second = (uint64_t)(tv.tv_sec);
153     chainId.usecond = (uint64_t)(tv.tv_usec);
154     return chainId.chainId;
155 }
156 
HiTraceChainBegin(const char * name,int flags)157 HiTraceIdStruct HiTraceChainBegin(const char* name, int flags)
158 {
159     HiTraceIdStruct id;
160     HiTraceChainInitId(&id);
161 
162     if ((flags < HITRACE_FLAG_MIN) || (flags > HITRACE_FLAG_MAX)) {
163         return id;
164     }
165 
166     HiTraceIdStructInner* pThreadId = GetThreadIdInner();
167     if (HiTraceChainIsValid(&(pThreadId->id))) {
168         return id;
169     }
170 
171     id.valid = HITRACE_ID_VALID;
172     id.ver = HITRACE_VER_1;
173     id.chainId = HiTraceChainCreateChainId();
174     id.flags = (uint64_t)flags;
175     id.spanId = 0;
176     id.parentSpanId = 0;
177 
178     pThreadId->id = id;
179 
180     if (!HiTraceChainIsFlagEnabled(&id, HITRACE_FLAG_NO_BE_INFO)) {
181         HILOG_INFO(LOG_CORE, "HiTraceBegin name:%{public}s flags:0x%{public}.2x.", name ? name : "", (int)id.flags);
182     }
183     return id;
184 }
185 
HiTraceChainEnd(const HiTraceIdStruct * pId)186 void HiTraceChainEnd(const HiTraceIdStruct* pId)
187 {
188     if (!HiTraceChainIsValid(pId)) {
189         HILOG_ERROR(LOG_CORE, "HiTraceEnd error: invalid end id.");
190         return;
191     }
192 
193     HiTraceIdStructInner* pThreadId = GetThreadIdInner();
194     if (!HiTraceChainIsValid(&(pThreadId->id))) {
195         HILOG_ERROR(LOG_CORE, "HiTraceEnd error: invalid thread id.");
196         return;
197     }
198 
199     if (HiTraceChainGetChainId(pId) != HiTraceChainGetChainId(&(pThreadId->id))) {
200         HILOG_ERROR(LOG_CORE, "HiTraceEnd error: end id(%{public}llx) != thread id(%{public}llx).",
201                     (unsigned long long)pId->chainId, (unsigned long long)pThreadId->id.chainId);
202         return;
203     }
204 
205     if (!HiTraceChainIsFlagEnabled(&(pThreadId->id), HITRACE_FLAG_NO_BE_INFO)) {
206         HILOG_INFO(LOG_CORE, "HiTraceEnd.");
207     }
208 
209     HiTraceChainInitId(&(pThreadId->id));
210     return;
211 }
212 
213 // BKDRHash
HashFunc(const void * pData,uint32_t dataLen)214 static uint32_t HashFunc(const void* pData, uint32_t dataLen)
215 {
216     const uint32_t seed = 131;
217 
218     if ((!pData) || dataLen == 0) {
219         return 0;
220     }
221 
222     uint32_t hash = 0;
223     uint32_t len = dataLen;
224     char* p = (char*)pData;
225 
226     for (; len > 0; --len) {
227         hash = (hash * seed) + (*p++);
228     }
229 
230     return hash;
231 }
232 
HiTraceChainCreateSpan(void)233 HiTraceIdStruct HiTraceChainCreateSpan(void)
234 {
235     static const uint32_t hashDataNum = 5;
236 
237     HiTraceIdStruct id = HiTraceChainGetId();
238     if (!HiTraceChainIsValid(&id)) {
239         return id;
240     }
241 
242     if (HiTraceChainIsFlagEnabled(&id, HITRACE_FLAG_DONOT_CREATE_SPAN)) {
243         return id;
244     }
245 
246     // create child span id
247     struct timeval tv;
248     gettimeofday(&tv, NULL);
249 
250     uint32_t hashData[hashDataNum];
251     hashData[0] = (uint32_t)(HiTraceChainGetDeviceId());  // 0: device id
252     hashData[1] = id.parentSpanId;                   // 1: parent span id
253     hashData[2] = id.spanId;                         // 2: span id
254     hashData[3] = (uint32_t)(tv.tv_sec);             // 3: second
255     hashData[4] = (uint32_t)(tv.tv_usec);            // 4: usecond
256 
257     uint32_t hash = HashFunc(hashData, hashDataNum * sizeof(uint32_t));
258 
259     id.parentSpanId = id.spanId;
260     id.spanId = hash;
261     return id;
262 }
263 
HiTraceChainTracepointInner(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)264 void HiTraceChainTracepointInner(HiTraceCommunicationMode mode, HiTraceTracepointType type,
265     const HiTraceIdStruct* pId, const char* fmt, va_list args)
266 {
267     static const int tpBufferSize = 1024;
268     static const char* hiTraceTypeStr[] = { "CS", "CR", "SS", "SR", "GENERAL", };
269     static const char* hiTraceModeStr[] = { "DEFAULT", "THREAD", "PROCESS", "DEVICE", };
270     static const int hitraceMask = 3;
271 
272     if ((mode < HITRACE_CM_MIN) || (mode > HITRACE_CM_MAX)) {
273         return;
274     }
275     if ((type < HITRACE_TP_MIN) || (type > HITRACE_TP_MAX)) {
276         return;
277     }
278 
279     if (!HiTraceChainIsValid(pId)) {
280         return;
281     }
282 
283     char buff[tpBufferSize];
284     if (type == HITRACE_TP_CS || type == HITRACE_TP_CR) {
285         buff[BUFF_ZERO_NUMBER] = 'C';
286     }
287 
288     if (type == HITRACE_TP_SR || type == HITRACE_TP_SS) {
289         buff[BUFF_ZERO_NUMBER] = 'S';
290     }
291     buff[BUFF_ONE_NUMBER] = '#';
292     buff[BUFF_TWO_NUMBER] = '#';
293 
294 #pragma clang diagnostic push
295 #pragma clang diagnostic ignored "-Wformat-nonliteral"
296     // if using privacy parameter: vsnprintf => hilog_vsnprintf
297     int ret = vsnprintf_s(buff + hitraceMask, tpBufferSize - hitraceMask, tpBufferSize - 1 - hitraceMask, fmt, args);
298 #pragma clang diagnostic pop
299     if (ret == -1) { // -1: vsnprintf_s copy string fail
300         return;
301     }
302     if (type == HITRACE_TP_CS || type == HITRACE_TP_SR) {
303         StartTraceChainPoint(pId, buff);
304     }
305 
306     if (type == HITRACE_TP_CR || type == HITRACE_TP_SS) {
307         HiTraceFinishTrace(HITRACE_TAG_OHOS);
308     }
309 
310     if (!HiTraceChainIsFlagEnabled(pId, HITRACE_FLAG_TP_INFO) &&
311         !HiTraceChainIsFlagEnabled(pId, HITRACE_FLAG_D2D_TP_INFO)) {
312         // Both tp and d2d-tp flags are disabled.
313         return;
314     } else if (!HiTraceChainIsFlagEnabled(pId, HITRACE_FLAG_TP_INFO) && (mode != HITRACE_CM_DEVICE)) {
315         // Only d2d-tp flag is enabled. But the communication mode is not device-to-device.
316         return;
317     }
318     HILOG_INFO(LOG_CORE, "<%{public}s,%{public}s,[%{public}llx,%{public}llx,%{public}llx]> %{public}s",
319                hiTraceModeStr[mode], hiTraceTypeStr[type], (unsigned long long)pId->chainId,
320                (unsigned long long)pId->spanId, (unsigned long long)pId->parentSpanId, buff + hitraceMask);
321     return;
322 }
323 
HiTraceChainTracepointWithArgs(HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)324 void HiTraceChainTracepointWithArgs(HiTraceTracepointType type, const HiTraceIdStruct* pId, const char* fmt,
325     va_list args)
326 {
327     HiTraceChainTracepointInner(HITRACE_CM_DEFAULT, type, pId, fmt, args);
328 }
329 
HiTraceChainTracepointExWithArgs(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)330 void HiTraceChainTracepointExWithArgs(HiTraceCommunicationMode mode, HiTraceTracepointType type,
331     const HiTraceIdStruct* pId, const char* fmt, va_list args)
332 {
333     HiTraceChainTracepointInner(mode, type, pId, fmt, args);
334 }
335 
HiTraceChainTracepoint(HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,...)336 void HiTraceChainTracepoint(HiTraceTracepointType type, const HiTraceIdStruct* pId, const char* fmt, ...)
337 {
338     va_list args;
339     va_start(args, fmt);
340     HiTraceChainTracepointInner(HITRACE_CM_DEFAULT, type, pId, fmt, args);
341     va_end(args);
342     return;
343 }
344 
HiTraceChainTracepointEx(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,...)345 void HiTraceChainTracepointEx(HiTraceCommunicationMode mode, HiTraceTracepointType type, const HiTraceIdStruct* pId,
346     const char* fmt, ...)
347 {
348     va_list args;
349     va_start(args, fmt);
350     HiTraceChainTracepointInner(mode, type, pId, fmt, args);
351     va_end(args);
352     return;
353 }
354 
HiTraceChainGetInfo(uint64_t * chainId,uint32_t * flags,uint64_t * spanId,uint64_t * parentSpanId)355 int HiTraceChainGetInfo(uint64_t* chainId, uint32_t* flags, uint64_t* spanId, uint64_t* parentSpanId)
356 {
357     if (!chainId || !flags || !spanId || !parentSpanId) {
358         return HITRACE_INFO_FAIL;
359     }
360 
361     HiTraceIdStruct id = HiTraceChainGetId();
362     if (!HiTraceChainIsValid(&id)) {
363         return HITRACE_INFO_FAIL;
364     }
365 
366     if (HiTraceChainIsFlagEnabled(&id, HITRACE_FLAG_DONOT_ENABLE_LOG)) {
367         return HITRACE_INFO_FAIL;
368     }
369 
370     *chainId = HiTraceChainGetChainId(&id);
371     *flags = HiTraceChainGetFlags(&id);
372 
373     if (HiTraceChainIsFlagEnabled(&id, HITRACE_FLAG_DONOT_CREATE_SPAN)) {
374         *spanId = 0;
375         *parentSpanId = 0;
376         return HITRACE_INFO_ALL_VALID_EXCEPT_SPAN;
377     }
378 
379     *spanId = HiTraceChainGetSpanId(&id);
380     *parentSpanId = HiTraceChainGetParentSpanId(&id);
381     return HITRACE_INFO_ALL_VALID;
382 }
383 
HiTraceChainSaveAndSetId(const HiTraceIdStruct * pId)384 HiTraceIdStruct HiTraceChainSaveAndSetId(const HiTraceIdStruct* pId)
385 {
386     HiTraceIdStruct oldId = g_hiTraceId.id;
387     if (pId != NULL && pId->valid == HITRACE_ID_VALID) {
388         g_hiTraceId.id = *pId;
389     }
390     return oldId;
391 }
392 
HiTraceChainRestoreId(const HiTraceIdStruct * pId)393 void HiTraceChainRestoreId(const HiTraceIdStruct* pId)
394 {
395     if (pId != NULL) {
396         g_hiTraceId.id = *pId;
397     }
398 }
399 
HiTraceChainInit(void)400 static void __attribute__((constructor)) HiTraceChainInit(void)
401 {
402     // Call HiLog Register Interface
403     HiLogRegisterGetIdFun(HiTraceChainGetInfo);
404 }
405 
HiTraceChainFini(void)406 static void __attribute__((destructor)) HiTraceChainFini(void)
407 {
408     HiLogUnregisterGetIdFun(HiTraceChainGetInfo);
409 }
410