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