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