• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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