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