1 /*
2 * Copyright (c) 2021 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/hitracec.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 "hitrace_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()76 static inline HiTraceIdStructInner* GetThreadIdInner()
77 {
78 return &g_hiTraceId;
79 }
80
HiTraceGetId()81 HiTraceIdStruct HiTraceGetId()
82 {
83 HiTraceIdStructInner* pThreadId = GetThreadIdInner();
84 return pThreadId->id;
85 }
86
HiTraceSetId(const HiTraceIdStruct * pId)87 void HiTraceSetId(const HiTraceIdStruct* pId)
88 {
89 if (!HiTraceIsValid(pId)) {
90 return;
91 }
92
93 HiTraceIdStructInner* pThreadId = GetThreadIdInner();
94 pThreadId->id = *pId;
95 return;
96 }
97
HiTraceClearId()98 void HiTraceClearId()
99 {
100 HiTraceIdStructInner* pThreadId = GetThreadIdInner();
101 HiTraceInitId(&(pThreadId->id));
102 return;
103 }
104
HiTraceGetDeviceId()105 static inline int HiTraceGetDeviceId()
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
HiTraceGetCpuId()119 static inline unsigned int HiTraceGetCpuId()
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
HiTraceCreateChainId()128 static inline uint64_t HiTraceCreateChainId()
129 {
130 // get timestamp. Using vdso call(no system call)
131 struct timeval tv;
132 gettimeofday(&tv, NULL);
133
134 HiTraceChainIdStruct chainId = {
135 .padding = 0,
136 .chainId = 0
137 };
138 chainId.deviceId = (uint64_t)(HiTraceGetDeviceId());
139 chainId.cpuId = HiTraceGetCpuId();
140 chainId.second = (uint64_t)(tv.tv_sec);
141 chainId.usecond = (uint64_t)(tv.tv_usec);
142
143 return chainId.chainId;
144 }
145
HiTraceBegin(const char * name,int flags)146 HiTraceIdStruct HiTraceBegin(const char* name, int flags)
147 {
148 HiTraceIdStruct id;
149 HiTraceInitId(&id);
150
151 if ((flags < HITRACE_FLAG_MIN) || (flags > HITRACE_FLAG_MAX)) {
152 return id;
153 }
154
155 HiTraceIdStructInner* pThreadId = GetThreadIdInner();
156 if (HiTraceIsValid(&(pThreadId->id))) {
157 return id;
158 }
159
160 id.valid = HITRACE_ID_VALID;
161 id.ver = HITRACE_VER_1;
162 id.chainId = HiTraceCreateChainId();
163 id.flags = (uint64_t)flags;
164 id.spanId = 0;
165 id.parentSpanId = 0;
166
167 pThreadId->id = id;
168
169 if (!HiTraceIsFlagEnabled(&id, HITRACE_FLAG_NO_BE_INFO)) {
170 HILOG_INFO(LOG_CORE, "HiTraceBegin name:%{public}s flags:0x%{public}.2x.", name ? name : "", (int)id.flags);
171 }
172 return id;
173 }
174
HiTraceEnd(const HiTraceIdStruct * pId)175 void HiTraceEnd(const HiTraceIdStruct* pId)
176 {
177 if (!HiTraceIsValid(pId)) {
178 HILOG_ERROR(LOG_CORE, "HiTraceEnd error: invalid end id.");
179 return;
180 }
181
182 HiTraceIdStructInner* pThreadId = GetThreadIdInner();
183 if (!HiTraceIsValid(&(pThreadId->id))) {
184 HILOG_ERROR(LOG_CORE, "HiTraceEnd error: invalid thread id.");
185 return;
186 }
187
188 if (HiTraceGetChainId(pId) != HiTraceGetChainId(&(pThreadId->id))) {
189 HILOG_ERROR(LOG_CORE, "HiTraceEnd error: end id(%{public}llx) != thread id(%{public}llx).",
190 (unsigned long long)pId->chainId, (unsigned long long)pThreadId->id.chainId);
191 return;
192 }
193
194 if (!HiTraceIsFlagEnabled(&(pThreadId->id), HITRACE_FLAG_NO_BE_INFO)) {
195 HILOG_INFO(LOG_CORE, "HiTraceEnd.");
196 }
197
198 HiTraceInitId(&(pThreadId->id));
199 return;
200 }
201
202 // BKDRHash
HashFunc(const void * pData,uint32_t dataLen)203 static uint32_t HashFunc(const void* pData, uint32_t dataLen)
204 {
205 const uint32_t seed = 131;
206
207 if ((!pData) || dataLen == 0) {
208 return 0;
209 }
210
211 uint32_t hash = 0;
212 uint32_t len = dataLen;
213 char* p = (char*)pData;
214
215 for (; len > 0; --len) {
216 hash = (hash * seed) + (*p++);
217 }
218
219 return hash;
220 }
221
HiTraceCreateSpan()222 HiTraceIdStruct HiTraceCreateSpan()
223 {
224 static const uint32_t hashDataNum = 5;
225
226 HiTraceIdStruct id = HiTraceGetId();
227 if (!HiTraceIsValid(&id)) {
228 return id;
229 }
230
231 if (HiTraceIsFlagEnabled(&id, HITRACE_FLAG_DONOT_CREATE_SPAN)) {
232 return id;
233 }
234
235 // create child span id
236 struct timeval tv;
237 gettimeofday(&tv, NULL);
238
239 uint32_t hashData[hashDataNum];
240 hashData[0] = (uint32_t)(HiTraceGetDeviceId()); // 0: device id
241 hashData[1] = id.parentSpanId; // 1: parent span id
242 hashData[2] = id.spanId; // 2: span id
243 hashData[3] = (uint32_t)(tv.tv_sec); // 3: second
244 hashData[4] = (uint32_t)(tv.tv_usec); // 4: usecond
245
246 uint32_t hash = HashFunc(hashData, hashDataNum * sizeof(uint32_t));
247
248 id.parentSpanId = id.spanId;
249 id.spanId = hash;
250 return id;
251 }
252
HiTraceTracepointInner(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)253 void HiTraceTracepointInner(HiTraceCommunicationMode mode, HiTraceTracepointType type, const HiTraceIdStruct* pId,
254 const char* fmt, va_list args)
255 {
256 static const int tpBufferSize = 1024;
257 static const char* hiTraceTypeStr[] = { "CS", "CR", "SS", "SR", "GENERAL", };
258 static const char* hiTraceModeStr[] = { "DEFAULT", "THREAD", "PROCESS", "DEVICE", };
259
260 if ((mode < HITRACE_CM_MIN) || (mode > HITRACE_CM_MAX)) {
261 return;
262 }
263 if ((type < HITRACE_TP_MIN) || (type > HITRACE_TP_MAX)) {
264 return;
265 }
266
267 if (!HiTraceIsValid(pId)) {
268 return;
269 }
270
271 if (!HiTraceIsFlagEnabled(pId, HITRACE_FLAG_TP_INFO) && !HiTraceIsFlagEnabled(pId, HITRACE_FLAG_D2D_TP_INFO)) {
272 // Both tp and d2d-tp flags are disabled.
273 return;
274 } else if (!HiTraceIsFlagEnabled(pId, HITRACE_FLAG_TP_INFO) && (mode != HITRACE_CM_DEVICE)) {
275 // Only d2d-tp flag is enabled. But the communication mode is not device-to-device.
276 return;
277 }
278
279 char buff[tpBufferSize];
280 #pragma clang diagnostic push
281 #pragma clang diagnostic ignored "-Wformat-nonliteral"
282 // if using privacy parameter: vsnprintf => hilog_vsnprintf
283 int ret = vsnprintf_s(buff, tpBufferSize, tpBufferSize - 1, fmt, args);
284 #pragma clang diagnostic pop
285 if (ret == -1) { // -1: vsnprintf_s copy string fail
286 return;
287 }
288
289 HILOG_INFO(LOG_CORE, "<%{public}s,%{public}s,[%{public}llx,%{public}llx,%{public}llx]> %{public}s",
290 hiTraceModeStr[mode], hiTraceTypeStr[type], (unsigned long long)pId->chainId,
291 (unsigned long long)pId->spanId, (unsigned long long)pId->parentSpanId, buff);
292 return;
293 }
294
HiTraceTracepointWithArgs(HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)295 void HiTraceTracepointWithArgs(HiTraceTracepointType type, const HiTraceIdStruct* pId, const char* fmt, va_list args)
296 {
297 HiTraceTracepointInner(HITRACE_CM_DEFAULT, type, pId, fmt, args);
298 }
299
HiTraceTracepointExWithArgs(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,va_list args)300 void HiTraceTracepointExWithArgs(HiTraceCommunicationMode mode, HiTraceTracepointType type, const HiTraceIdStruct* pId,
301 const char* fmt, va_list args)
302 {
303 HiTraceTracepointInner(mode, type, pId, fmt, args);
304 }
305
HiTraceTracepoint(HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,...)306 void HiTraceTracepoint(HiTraceTracepointType type, const HiTraceIdStruct* pId, const char* fmt, ...)
307 {
308 va_list args;
309 va_start(args, fmt);
310 HiTraceTracepointInner(HITRACE_CM_DEFAULT, type, pId, fmt, args);
311 va_end(args);
312 return;
313 }
314
HiTraceTracepointEx(HiTraceCommunicationMode mode,HiTraceTracepointType type,const HiTraceIdStruct * pId,const char * fmt,...)315 void HiTraceTracepointEx(HiTraceCommunicationMode mode, HiTraceTracepointType type, const HiTraceIdStruct* pId,
316 const char* fmt, ...)
317 {
318 va_list args;
319 va_start(args, fmt);
320 HiTraceTracepointInner(mode, type, pId, fmt, args);
321 va_end(args);
322 return;
323 }
324
HiTraceGetInfo(uint64_t * chainId,uint32_t * flags,uint64_t * spanId,uint64_t * parentSpanId)325 int HiTraceGetInfo(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 = HiTraceGetId();
332 if (!HiTraceIsValid(&id)) {
333 return HITRACE_INFO_FAIL;
334 }
335
336 if (HiTraceIsFlagEnabled(&id, HITRACE_FLAG_DONOT_ENABLE_LOG)) {
337 return HITRACE_INFO_FAIL;
338 }
339
340 *chainId = HiTraceGetChainId(&id);
341 *flags = HiTraceGetFlags(&id);
342
343 if (HiTraceIsFlagEnabled(&id, HITRACE_FLAG_DONOT_CREATE_SPAN)) {
344 *spanId = 0;
345 *parentSpanId = 0;
346 return HITRACE_INFO_ALL_VALID_EXCEPT_SPAN;
347 }
348
349 *spanId = HiTraceGetSpanId(&id);
350 *parentSpanId = HiTraceGetParentSpanId(&id);
351 return HITRACE_INFO_ALL_VALID;
352 }
353
HiTraceInit()354 static void __attribute__((constructor)) HiTraceInit()
355 {
356 // Call HiLog Register Interface
357 HiLogRegisterGetIdFun(HiTraceGetInfo);
358 }
359
HiTraceFini()360 static void __attribute__((destructor)) HiTraceFini()
361 {
362 HiLogUnregisterGetIdFun(HiTraceGetInfo);
363 }
364