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