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