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