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