Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "trace_rb_log.h"
12 : #include "trace_system_api.h"
13 : #include "adiag_print.h"
14 : #include "adiag_utils.h"
15 : #include "trace_attr.h"
16 : #include "securec.h"
17 : #include "trace_types.h"
18 : #include "adiag_list.h"
19 :
20 : #define AVERAGE(a, b) (((a) + (b)) >> 1)
21 : #define MIN(a, b) ((a) > (b) ? (b) : (a))
22 : #define AO_F_ADD(ptr, value) ((__typeof__(*(ptr)))__sync_fetch_and_add((ptr), (value)))
23 : #define AO_SUB_F(ptr, value) ((__typeof__(*(ptr)))__sync_sub_and_fetch((ptr), (value)))
24 : #define AO_SET(ptr, value) ((void)__sync_lock_test_and_set((ptr), (value)))
25 : #define AO_CASB(ptr, comp, value) (__sync_bool_compare_and_swap((ptr), (comp), (value)))
26 : #define MAX_RING_BUFFER_SIZE 1024U
27 : #define MIN_RING_BUFFER_SIZE 1U
28 : #define MAX_MSG_SIZE 1024U
29 : #define MIN_MSG_SIZE 64U
30 : #define MAX_RING_BUFFER_SPACE 131072U // 128M
31 :
32 1876 : STATIC INLINE void TraceRbLogInitTime(struct RbLogCtrl *head)
33 : {
34 1876 : uint64_t realTime1 = GetRealTime();
35 1876 : uint64_t monotonicTime1 = GetCpuCycleCounter();
36 1876 : uint64_t monotonicTime2 = GetCpuCycleCounter();
37 1876 : uint64_t realTime2 = GetRealTime();
38 1876 : head->realTime = AVERAGE(realTime1, realTime2);
39 1876 : head->monotonicTime = AVERAGE(monotonicTime1, monotonicTime2);
40 1876 : if (TraceGetTimeOffset(&head->minutesWest) != TRACE_SUCCESS) {
41 20 : ADIAG_WAR("can not get time offset.");
42 : }
43 1876 : head->cpuFreq = GetCpuFrequency();
44 1876 : ADIAG_INF("init ring buffer time finished, realTime %llu, monotonicTime %llu, freq %llu kHz, minutesWest %d minutes",
45 : head->realTime, head->monotonicTime, head->cpuFreq, head->minutesWest);
46 1876 : }
47 :
48 2120 : STATIC bool TraceRbLogCheckParam(const char *name, const TraceAttr *attr)
49 : {
50 2120 : ADIAG_CHK_NULL_PTR(name, return false);
51 2120 : ADIAG_CHK_NULL_PTR(attr, return false);
52 2120 : if ((attr->msgNum != 0) && (attr->msgNum > MAX_RING_BUFFER_SIZE || attr->msgNum < MIN_RING_BUFFER_SIZE)) {
53 40 : ADIAG_ERR("[%s] msg num %u out of range [%u, %u]",
54 : name, attr->msgNum, MIN_RING_BUFFER_SIZE, MAX_RING_BUFFER_SIZE);
55 40 : return false;
56 : }
57 2080 : if ((attr->msgSize != 0) && (attr->msgSize > MAX_MSG_SIZE || attr->msgSize < MIN_MSG_SIZE)) {
58 40 : ADIAG_ERR("[%s] msg size %u out of range [%u, %u] bytes", name, attr->msgSize, MIN_MSG_SIZE, MAX_MSG_SIZE);
59 40 : return false;
60 : }
61 2040 : return true;
62 : }
63 :
64 1876 : STATIC INLINE TraStatus TraceRbLogInitDataStruct(struct RbLog *rb, const TraceAttr *attr)
65 : {
66 20636 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
67 18760 : if (attr->handle[i] == NULL) {
68 18568 : continue;
69 : }
70 192 : if (attr->handle[i]->list == NULL) {
71 0 : ADIAG_ERR("[%s] struct list is invalid.", attr->handle[i]->name);
72 0 : return TRACE_FAILURE;
73 : }
74 192 : errno_t ret = strcpy_s(rb->entry[i].name, TRACE_NAME_LENGTH, attr->handle[i]->name);
75 192 : if (ret != EOK) {
76 0 : ADIAG_ERR("[%s] strncpy_s data struct name failed.", attr->handle[i]->name);
77 0 : return TRACE_FAILURE;
78 : }
79 192 : rb->entry[i].list = attr->handle[i]->list;
80 192 : attr->handle[i]->list = NULL;
81 : }
82 1876 : return TRACE_SUCCESS;
83 : }
84 :
85 : /**
86 : * @brief create log ringbuffer
87 : * @param [in] name: ringbuffer name
88 : * @param [in] bufSize: ringbuffer size
89 : * @return ring buffer ptr
90 : */
91 2120 : struct RbLog *TraceRbLogCreate(const char *name, const TraceAttr *attr)
92 : {
93 2120 : if (!TraceRbLogCheckParam(name, attr)) {
94 80 : return NULL;
95 : }
96 2040 : uint32_t bufferSize = (attr->msgNum == 0) ? DEFAULT_ATRACE_MSG_NUM : attr->msgNum;
97 2040 : uint32_t msgTxtSize = (attr->msgSize == 0) ? DEFAULT_ATRACE_MSG_SIZE : attr->msgSize;
98 :
99 2040 : if ((bufferSize & (bufferSize - 1U)) != 0) { // bufSize if not power of 2
100 40 : bufferSize = GetNearestPowerOfTwo(bufferSize);
101 40 : ADIAG_WAR("[%s] buffer size if not power of 2, resize to %u bytes", name, bufferSize);
102 : }
103 2040 : uint32_t msgSize = msgTxtSize + (uint32_t)sizeof(RbMsgHead);
104 2040 : size_t totalSize = (size_t)msgSize * bufferSize;
105 2040 : if (msgSize * bufferSize > MAX_RING_BUFFER_SPACE) {
106 40 : ADIAG_ERR("[%s] buffer space %zu bytes exceed max buffer space %u bytes", name, totalSize, MAX_RING_BUFFER_SPACE);
107 40 : return NULL;
108 : }
109 2000 : totalSize += sizeof(RbLog);
110 2000 : struct RbLog *rb = AdiagMalloc(totalSize);
111 2000 : if (rb == NULL) {
112 42 : ADIAG_ERR("[%s] malloc ring buffer failed.", name);
113 42 : return NULL;
114 : }
115 1958 : struct RbLogCtrl *head = &rb->head;
116 1958 : errno_t ret = strcpy_s(head->name, sizeof(head->name), name);
117 1958 : if (ret != EOK) {
118 82 : ADIAG_ERR("[%s] strcpy_s ring buffer name failed, ret : %d.", name, ret);
119 82 : ADIAG_SAFE_FREE(rb);
120 82 : return NULL;
121 : }
122 1876 : if (TraceRbLogInitDataStruct(rb, attr) != TRACE_SUCCESS) {
123 0 : ADIAG_ERR("[%s] init data struct failed.", name);
124 0 : ADIAG_SAFE_FREE(rb);
125 0 : return NULL;
126 : }
127 1876 : head->readIdx = 0;
128 1876 : head->writeIdx = 0;
129 1876 : head->bufSize = bufferSize;
130 1876 : head->msgSize = msgSize;
131 1876 : head->msgTxtSize = msgTxtSize;
132 1876 : head->mask = bufferSize - 1U;
133 1876 : head->errCount = 0;
134 1876 : TraceRbLogInitTime(head);
135 1876 : ADIAG_INF("[%s] create ring buffer successfully, "
136 : "msgSize %u bytes, msgTxtSize %u bytes, bufferSize %u bytes, msg space %u bytes, total space %zu bytes",
137 : name, msgSize, msgTxtSize, bufferSize, msgSize, totalSize);
138 1876 : return rb;
139 : }
140 :
141 : /**
142 : * @brief destroy log ringbuffer
143 : * @param [in] rb: ringbuffer ptr
144 : * @return NA
145 : */
146 2113 : void TraceRbLogDestroy(struct RbLog *rb)
147 : {
148 2113 : if (rb != NULL) {
149 20581 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
150 18710 : if (rb->entry[i].list != NULL) {
151 190 : (void)AdiagListDestroy((struct AdiagList *)rb->entry[i].list);
152 190 : ADIAG_SAFE_FREE(rb->entry[i].list);
153 : }
154 : }
155 1871 : ADIAG_SAFE_FREE(rb);
156 : }
157 2113 : }
158 :
159 6414118 : STATIC INLINE RbLogMsg *TraceRbLogGetMsgByIndex(struct RbLog *rb, uint32_t msgIndex)
160 : {
161 6414118 : return (RbLogMsg *)(rb->msg + rb->head.msgSize * msgIndex);
162 : }
163 :
164 : /**
165 : * @brief write log msg to ringbuffer
166 : * @param [in] rb: ringbuffer ptr, caller guarantees not be NULL
167 : * @param [in] buffer: data buffer
168 : * @param [in] bufSize: data buffer size
169 : * @return TraStatus
170 : */
171 2483308 : TraStatus TraceRbLogWriteRbMsg(struct RbLog *rb, uint8_t bufferType, const char *buffer, uint32_t bufSize)
172 : {
173 2483308 : ADIAG_CHK_NULL_PTR(buffer, return TRACE_INVALID_PARAM);
174 2483287 : ADIAG_CHK_EXPR_ACTION(bufSize == 0, return TRACE_INVALID_PARAM, "invalid bufSize 0");
175 2483267 : uint32_t txtSize = bufSize;
176 2483267 : if (txtSize > rb->head.msgTxtSize) {
177 81941 : ADIAG_WAR("[%s] msg size %u bytes exceeded ringbuffer msg size %u bytes, truncated.",
178 : rb->head.name, txtSize, rb->head.msgTxtSize);
179 81941 : txtSize = rb->head.msgTxtSize;
180 : }
181 2483267 : uint64_t monotonicTime = GetCpuCycleCounter();
182 2401067 : uint64_t originalWriteIdx = AO_F_ADD(&rb->head.writeIdx, 1);
183 2401067 : uint32_t writeIdx = (uint32_t)(originalWriteIdx & rb->head.mask);
184 2401067 : RbLogMsg *msg = TraceRbLogGetMsgByIndex(rb, writeIdx);
185 3035507 : if (!AO_CASB(&msg->head.busy, false, true)) {
186 0 : uint32_t errCount = AO_F_ADD(&rb->head.errCount, 1);
187 0 : if ((errCount & rb->head.mask) == 0) {
188 0 : ADIAG_WAR("[%s] can not write msg [%s] to index %u, buffer is busy", rb->head.name, buffer, writeIdx);
189 : }
190 0 : return TRACE_FAILURE;
191 : }
192 3035507 : int32_t ret = memcpy_s(msg->txt, rb->head.msgTxtSize, buffer, txtSize);
193 2747267 : if (ret != EOK) {
194 1 : ADIAG_ERR("[%s] memcpy_s ringbuffer msg failed.", rb->head.name);
195 21 : return TRACE_FAILURE;
196 : }
197 2999646 : msg->head.cycle = monotonicTime - rb->head.monotonicTime;
198 2999646 : msg->head.txtSize = txtSize;
199 2999646 : msg->head.bufferType = bufferType;
200 2999646 : AO_SET(&msg->head.busy, false);
201 2999646 : return TRACE_SUCCESS;
202 : }
203 :
204 24 : TraStatus TraceRbLogWriteRbMsgNoLock(struct RbLog *rb, uint8_t bufferType, const char *buffer, uint32_t bufSize)
205 : {
206 24 : if ((buffer == NULL) || (bufSize == 0)) {
207 1 : return TRACE_INVALID_PARAM;
208 : }
209 23 : struct RbLogCtrl *head = &rb->head;
210 23 : RbLogMsg *msg = (RbLogMsg *)(rb->msg + head->msgSize * (uint32_t)((++head->writeIdx) & head->mask));
211 23 : uint32_t txtSize = MIN(bufSize, head->msgTxtSize);
212 :
213 23 : int32_t ret = memcpy_s(msg->txt, head->msgTxtSize, buffer, txtSize);
214 23 : if (ret != EOK) {
215 1 : return TRACE_FAILURE;
216 : }
217 22 : msg->head.cycle = GetCpuCycleCounter() - head->monotonicTime;
218 22 : msg->head.txtSize = txtSize;
219 22 : msg->head.bufferType = bufferType;
220 22 : return TRACE_SUCCESS;
221 : }
222 :
223 5889406 : STATIC INLINE int RbLogMsgCmp(const void *a, const void *b)
224 : {
225 5889406 : const RbLogMsg *msgA = (const RbLogMsg *)a;
226 5889406 : const RbLogMsg *msgB = (const RbLogMsg *)b;
227 5889406 : if (msgA->head.busy != msgB->head.busy) {
228 620 : return msgA->head.busy ? 1 : 0; // msgA->head.busy > msgB->head.busy
229 : }
230 5888786 : return msgA->head.cycle > msgB->head.cycle;
231 : }
232 :
233 1090600 : STATIC TraStatus TraceRbLogCopyMsg(struct RbLog *newRb, struct RbLog *rb, uint32_t msgIndex)
234 : {
235 1090600 : uint32_t msgTxtSize = rb->head.msgTxtSize;
236 1090600 : RbLogMsg *msg = TraceRbLogGetMsgByIndex(rb, msgIndex);
237 1090600 : RbLogMsg *newMsg = TraceRbLogGetMsgByIndex(newRb, msgIndex);
238 :
239 1090600 : uint64_t cycle = msg->head.cycle;
240 1090600 : int32_t ret = memcpy_s(&newMsg->txt, msgTxtSize, &msg->txt, msgTxtSize);
241 1090600 : if (ret != EOK) {
242 20 : ADIAG_ERR("[%s] memcpy_s msg txt failed.", rb->head.name);
243 20 : return TRACE_FAILURE;
244 : }
245 1090580 : ret = memcpy_s(&newMsg->head, sizeof(RbMsgHead), &msg->head, sizeof(RbMsgHead));
246 1090580 : if (ret != EOK) {
247 20 : ADIAG_ERR("[%s] memcpy_s msg head failed.", rb->head.name);
248 20 : return TRACE_FAILURE;
249 : }
250 : // cycle has changed before memcpy finished, set busy to true to drop data.
251 1090560 : if (newMsg->head.cycle != cycle) {
252 60 : newMsg->head.busy = true;
253 : }
254 1090560 : return TRACE_SUCCESS;
255 : }
256 :
257 1145 : STATIC void TraceRbLogSort(struct RbLog *rb)
258 : {
259 1145 : qsort(rb->msg, rb->head.bufSize, rb->head.msgSize, RbLogMsgCmp);
260 1145 : }
261 :
262 : /**
263 : * @brief get struct entry list
264 : * @param [in/out] newRb: new ringbuffer
265 : * @param [in] traList: trace list of ring buffer
266 : * @return TRACE_SUCCESS success; TRACE_FAILURE failure
267 : */
268 128 : STATIC TraStatus TraceRbLogGetStructEntryList(struct AdiagList **newRbList, const struct AdiagList *traList)
269 : {
270 128 : struct AdiagList *newList = (struct AdiagList *)AdiagMalloc(sizeof(struct AdiagList));
271 128 : if (newList == NULL) {
272 20 : ADIAG_ERR("malloc new ringbuffer list failed.");
273 20 : return TRACE_FAILURE;
274 : }
275 108 : if (AdiagListInit(newList) != TRACE_SUCCESS) {
276 20 : ADIAG_ERR("init new ringbuffer list failed.");
277 20 : ADIAG_SAFE_FREE(newList);
278 20 : return TRACE_FAILURE;
279 : }
280 88 : struct ListHead *pos = NULL;
281 88 : struct AdiagListNode *node = NULL;
282 400 : LIST_FOR_EACH(pos, &traList->list) {
283 352 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
284 352 : if (node == NULL) {
285 0 : (void)AdiagListDestroy(newList);
286 0 : ADIAG_SAFE_FREE(newList);
287 0 : return TRACE_FAILURE;
288 : }
289 352 : TraceStructField *data = (TraceStructField *)AdiagMalloc(sizeof(TraceStructField));
290 352 : if (data == NULL) {
291 20 : ADIAG_ERR("malloc struct field failed.");
292 20 : (void)AdiagListDestroy(newList);
293 20 : ADIAG_SAFE_FREE(newList);
294 20 : return TRACE_FAILURE;
295 : }
296 332 : errno_t ret = memcpy_s(data, sizeof(TraceStructField), node->data, sizeof(TraceStructField));
297 332 : if (ret != EOK) {
298 0 : ADIAG_ERR("memcpy_s struct field failed.");
299 0 : ADIAG_SAFE_FREE(data);
300 0 : (void)AdiagListDestroy(newList);
301 0 : ADIAG_SAFE_FREE(newList);
302 0 : return TRACE_FAILURE;
303 : }
304 332 : if (AdiagListInsert(newList, data) != ADIAG_SUCCESS) {
305 20 : ADIAG_ERR("insert struct list failed.");
306 20 : ADIAG_SAFE_FREE(data);
307 20 : (void)AdiagListDestroy(newList);
308 20 : ADIAG_SAFE_FREE(newList);
309 20 : return TRACE_FAILURE;
310 : }
311 : }
312 48 : *newRbList = newList;
313 48 : return TRACE_SUCCESS;
314 : }
315 :
316 : /**
317 : * @brief copy ringbuffer to new buffer and sort valid msg by cycle
318 : * @param [out] newRb: new ringbuffer
319 : * @param [in] rb: original ringbuffer
320 : * @return TraStatus
321 : */
322 1229 : TraStatus TraceRbLogGetCopyOfRingBuffer(struct RbLog **newRb, struct RbLog *rb)
323 : {
324 1229 : size_t totalSize = sizeof(RbLog) + (size_t)rb->head.bufSize * rb->head.msgSize;
325 1229 : *newRb = AdiagMalloc(totalSize);
326 1229 : if (*newRb == NULL) {
327 22 : ADIAG_ERR("[%s] malloc new ringbuffer failed, size : %zu bytes.", rb->head.name, totalSize);
328 22 : return TRACE_FAILURE;
329 : }
330 1207 : errno_t ret = memcpy_s(*newRb, sizeof(RbLog), rb, sizeof(RbLog));
331 1207 : if (ret != EOK) {
332 22 : ADIAG_SAFE_FREE(*newRb);
333 22 : ADIAG_ERR("[%s] memcpy_s ringbuffer failed.", rb->head.name);
334 22 : return TRACE_FAILURE;
335 : }
336 1091745 : for (uint32_t i = 0; i < rb->head.bufSize; i++) {
337 1090600 : if (TraceRbLogCopyMsg(*newRb, rb, i) != TRACE_SUCCESS) {
338 40 : ADIAG_SAFE_FREE(*newRb);
339 40 : return TRACE_FAILURE;
340 : }
341 : }
342 1145 : TraceRbLogSort(*newRb);
343 : // if trace struct not defined, return success
344 1145 : struct AdiagList *traList = NULL;
345 11795 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
346 10730 : traList = (struct AdiagList *)(rb->entry[i].list);
347 10730 : if ((rb->entry[i].list == NULL) || (ListEmpty(&traList->list))) {
348 10602 : continue;
349 : }
350 128 : if (TraceRbLogGetStructEntryList((struct AdiagList **)&(*newRb)->entry[i].list, traList) != TRACE_SUCCESS) {
351 80 : ADIAG_SAFE_FREE(*newRb);
352 80 : return TRACE_FAILURE;
353 : }
354 : }
355 1065 : return TRACE_SUCCESS;
356 : }
357 :
358 : /**
359 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
360 : * @param [in] rb: ringbuffer
361 : * @param [out] timeStr: timestamp str
362 : * @param [out] buffer: ptr of msg txt in ringbuffer
363 : * @return TraStatus
364 : */
365 364624 : TraStatus TraceRbLogReadRbMsg(struct RbLog *rb, char *timeStr, uint32_t timeStrSize, char **buffer)
366 : {
367 364624 : RbLogMsg *msg = NULL;
368 960503 : for (;rb->head.readIdx != rb->head.bufSize; rb->head.readIdx++) {
369 959508 : msg = TraceRbLogGetMsgByIndex(rb, rb->head.readIdx);
370 959508 : if (msg->head.busy) { // msg has not been written done
371 60 : continue;
372 : }
373 959448 : if (msg->head.txtSize == 0) {
374 595819 : continue;
375 : }
376 363629 : rb->head.readIdx++;
377 363629 : double costTime = (double)msg->head.cycle / (double)rb->head.cpuFreq * (double)FREQ_GHZ_TO_KHZ;
378 363629 : uint64_t timestamp = (uint64_t)costTime + rb->head.realTime;
379 363629 : TraStatus ret = TimestampToStr(timestamp, timeStr, timeStrSize);
380 363629 : if (ret != TRACE_SUCCESS) {
381 0 : return ret;
382 : }
383 363629 : uint32_t lastIndex = MIN(msg->head.txtSize, rb->head.msgTxtSize - 1U);
384 363629 : msg->txt[lastIndex] = '\0'; // ensure msg must have a string terminator
385 363629 : *buffer = msg->txt;
386 363629 : return TRACE_SUCCESS;
387 : }
388 995 : *buffer = NULL;
389 995 : return TRACE_RING_BUFFER_EMPTY;
390 : }
391 :
392 : /**
393 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
394 : * @param [in] rb: ringbuffer
395 : * @param [out] buffer: ptr of msg in ringbuffer
396 : * @param [out] bufLen: length of msg in ringbuffer
397 : * @return TraStatus
398 : */
399 149 : TraStatus TraceRbLogReadOriRbMsg(struct RbLog *rb, char **buffer, uint32_t *bufLen)
400 : {
401 149 : RbLogMsg *msg = NULL;
402 49199 : for (;rb->head.readIdx != rb->head.bufSize; rb->head.readIdx++) {
403 49151 : msg = TraceRbLogGetMsgByIndex(rb, rb->head.readIdx);
404 49151 : if (msg->head.txtSize == 0) {
405 49050 : continue;
406 : }
407 101 : rb->head.readIdx++;
408 101 : *buffer = (char *)msg;
409 101 : *bufLen = rb->head.msgSize;
410 101 : return TRACE_SUCCESS;
411 : }
412 48 : *buffer = NULL;
413 48 : *bufLen = 0;
414 48 : return TRACE_RING_BUFFER_EMPTY;
415 : }
416 :
417 82 : void TraceRbLogPrepareForRead(struct RbLog *rb)
418 : {
419 82 : rb->head.readIdx = 0;
420 82 : }
421 :
422 223 : STATIC RbLogMsg *TraceRbLogGetOldestMsg(struct RbLog *rb, uint64_t *cycle, bool filterBusy)
423 : {
424 223 : RbLogMsg *oldestMsg = NULL;
425 223 : RbLogMsg *msg = NULL;
426 228575 : for (uint32_t i = 0; i < rb->head.bufSize; i++) {
427 228352 : msg = TraceRbLogGetMsgByIndex(rb, i);
428 228352 : if (msg->head.txtSize == 0) {
429 228190 : continue;
430 : }
431 162 : if ((filterBusy) && (msg->head.busy)) {
432 0 : continue;
433 : }
434 162 : if (msg->head.cycle <= *cycle) {
435 21 : continue;
436 : }
437 141 : if ((oldestMsg == NULL) || (msg->head.cycle < oldestMsg->head.cycle)) {
438 141 : oldestMsg = msg;
439 : }
440 : }
441 223 : if (oldestMsg != NULL) {
442 141 : *cycle = oldestMsg->head.cycle;
443 : }
444 223 : return oldestMsg;
445 : }
446 :
447 : /**
448 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
449 : * @param [in] rb: ringbuffer
450 : * @param [out] timeStr: timestamp str
451 : * @param [out] buffer: ptr of msg txt in ringbuffer
452 : * @return TraStatus
453 : */
454 161 : TraStatus TraceRbLogReadRbMsgSafe(struct RbLog *rb, char *timeStr, uint32_t timeStrSize, char **buffer)
455 : {
456 161 : if (rb->head.readIdx == rb->head.bufSize) {
457 0 : return TRACE_RING_BUFFER_EMPTY;
458 : }
459 161 : uint64_t cycle = 0;
460 161 : RbLogMsg *msg = TraceRbLogGetOldestMsg(rb, &cycle, true);
461 161 : if (msg == NULL) {
462 61 : return TRACE_RING_BUFFER_EMPTY;
463 : }
464 100 : double costTime = (double)msg->head.cycle / (double)rb->head.cpuFreq * (double)FREQ_GHZ_TO_KHZ;
465 100 : uint64_t timestamp = (uint64_t)costTime + rb->head.realTime;
466 100 : TraStatus ret = TimestampToStr(timestamp, timeStr, timeStrSize);
467 100 : if (ret != TRACE_SUCCESS) {
468 0 : return ret;
469 : }
470 100 : uint32_t lastIndex = MIN(msg->head.txtSize, rb->head.msgTxtSize - 1U);
471 100 : msg->txt[lastIndex] = '\0'; // ensure msg must have a string terminator
472 100 : *buffer = msg->txt;
473 100 : msg->head.txtSize = 0;
474 100 : rb->head.readIdx++;
475 100 : return TRACE_SUCCESS;
476 : }
477 :
478 : /**
479 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
480 : * @param [in] rb: ringbuffer
481 : * @param [out] buffer: ptr of msg in ringbuffer
482 : * @param [out] bufLen: length of msg in ringbuffer
483 : * @return TraStatus
484 : */
485 62 : TraStatus TraceRbLogReadOriRbMsgSafe(struct RbLog *rb, char **buffer, uint32_t *bufLen, uint64_t *cycle)
486 : {
487 62 : if (rb->head.readIdx == rb->head.bufSize) {
488 0 : return TRACE_RING_BUFFER_EMPTY;
489 : }
490 62 : RbLogMsg *msg = TraceRbLogGetOldestMsg(rb, cycle, false);
491 62 : if (msg == NULL) {
492 21 : return TRACE_RING_BUFFER_EMPTY;
493 : }
494 41 : *buffer = (char *)msg;
495 41 : *bufLen = rb->head.msgSize;
496 41 : rb->head.readIdx++;
497 41 : return TRACE_SUCCESS;
498 : }
499 :
500 98 : uint32_t TracerRbLogGetMsgNum(const RbLog *rb)
501 : {
502 98 : return (rb->head.writeIdx > (uint64_t)rb->head.bufSize) ? rb->head.bufSize : (uint32_t)rb->head.writeIdx;
503 : }
|