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 2060 : STATIC INLINE void TraceRbLogInitTime(struct RbLogCtrl* head)
33 : {
34 2060 : uint64_t realTime1 = GetRealTime();
35 2060 : uint64_t monotonicTime1 = GetCpuCycleCounter();
36 2060 : uint64_t monotonicTime2 = GetCpuCycleCounter();
37 2060 : uint64_t realTime2 = GetRealTime();
38 2060 : head->realTime = AVERAGE(realTime1, realTime2);
39 2060 : head->monotonicTime = AVERAGE(monotonicTime1, monotonicTime2);
40 2060 : if (TraceGetTimeOffset(&head->minutesWest) != TRACE_SUCCESS) {
41 22 : ADIAG_WAR("can not get time offset.");
42 : }
43 2060 : head->cpuFreq = GetCpuFrequency();
44 2060 : ADIAG_INF(
45 : "init ring buffer time finished, realTime %llu, monotonicTime %llu, freq %llu kHz, minutesWest %d minutes",
46 : head->realTime, head->monotonicTime, head->cpuFreq, head->minutesWest);
47 2060 : }
48 :
49 2328 : STATIC bool TraceRbLogCheckParam(const char* name, const TraceAttr* attr)
50 : {
51 2328 : ADIAG_CHK_NULL_PTR(name, return false);
52 2328 : ADIAG_CHK_NULL_PTR(attr, return false);
53 2328 : if ((attr->msgNum != 0) && (attr->msgNum > MAX_RING_BUFFER_SIZE || attr->msgNum < MIN_RING_BUFFER_SIZE)) {
54 44 : ADIAG_ERR(
55 : "[%s] msg num %u out of range [%u, %u]", name, attr->msgNum, MIN_RING_BUFFER_SIZE, MAX_RING_BUFFER_SIZE);
56 44 : return false;
57 : }
58 2284 : if ((attr->msgSize != 0) && (attr->msgSize > MAX_MSG_SIZE || attr->msgSize < MIN_MSG_SIZE)) {
59 44 : ADIAG_ERR("[%s] msg size %u out of range [%u, %u] bytes", name, attr->msgSize, MIN_MSG_SIZE, MAX_MSG_SIZE);
60 44 : return false;
61 : }
62 2240 : return true;
63 : }
64 :
65 2060 : STATIC INLINE TraStatus TraceRbLogInitDataStruct(struct RbLog* rb, const TraceAttr* attr)
66 : {
67 22660 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
68 20600 : if (attr->handle[i] == NULL) {
69 20390 : continue;
70 : }
71 210 : if (attr->handle[i]->list == NULL) {
72 0 : ADIAG_ERR("[%s] struct list is invalid.", attr->handle[i]->name);
73 0 : return TRACE_FAILURE;
74 : }
75 210 : errno_t ret = strcpy_s(rb->entry[i].name, TRACE_NAME_LENGTH, attr->handle[i]->name);
76 210 : if (ret != EOK) {
77 0 : ADIAG_ERR("[%s] strncpy_s data struct name failed.", attr->handle[i]->name);
78 0 : return TRACE_FAILURE;
79 : }
80 210 : rb->entry[i].list = attr->handle[i]->list;
81 210 : attr->handle[i]->list = NULL;
82 : }
83 2060 : return TRACE_SUCCESS;
84 : }
85 :
86 : /**
87 : * @brief create log ringbuffer
88 : * @param [in] name: ringbuffer name
89 : * @param [in] bufSize: ringbuffer size
90 : * @return ring buffer ptr
91 : */
92 2328 : struct RbLog* TraceRbLogCreate(const char* name, const TraceAttr* attr)
93 : {
94 2328 : if (!TraceRbLogCheckParam(name, attr)) {
95 88 : return NULL;
96 : }
97 2240 : uint32_t bufferSize = (attr->msgNum == 0) ? DEFAULT_ATRACE_MSG_NUM : attr->msgNum;
98 2240 : uint32_t msgTxtSize = (attr->msgSize == 0) ? DEFAULT_ATRACE_MSG_SIZE : attr->msgSize;
99 :
100 2240 : if ((bufferSize & (bufferSize - 1U)) != 0) { // bufSize if not power of 2
101 44 : bufferSize = GetNearestPowerOfTwo(bufferSize);
102 44 : ADIAG_WAR("[%s] buffer size if not power of 2, resize to %u bytes", name, bufferSize);
103 : }
104 2240 : uint32_t msgSize = msgTxtSize + (uint32_t)sizeof(RbMsgHead);
105 2240 : size_t totalSize = (size_t)msgSize * bufferSize;
106 2240 : if (msgSize * bufferSize > MAX_RING_BUFFER_SPACE) {
107 44 : ADIAG_ERR(
108 : "[%s] buffer space %zu bytes exceed max buffer space %u bytes", name, totalSize, MAX_RING_BUFFER_SPACE);
109 44 : return NULL;
110 : }
111 2196 : totalSize += sizeof(RbLog);
112 2196 : struct RbLog* rb = AdiagMalloc(totalSize);
113 2196 : if (rb == NULL) {
114 46 : ADIAG_ERR("[%s] malloc ring buffer failed.", name);
115 46 : return NULL;
116 : }
117 2150 : struct RbLogCtrl* head = &rb->head;
118 2150 : errno_t ret = strcpy_s(head->name, sizeof(head->name), name);
119 2150 : if (ret != EOK) {
120 90 : ADIAG_ERR("[%s] strcpy_s ring buffer name failed, ret : %d.", name, ret);
121 90 : ADIAG_SAFE_FREE(rb);
122 90 : return NULL;
123 : }
124 2060 : if (TraceRbLogInitDataStruct(rb, attr) != TRACE_SUCCESS) {
125 0 : ADIAG_ERR("[%s] init data struct failed.", name);
126 0 : ADIAG_SAFE_FREE(rb);
127 0 : return NULL;
128 : }
129 2060 : head->readIdx = 0;
130 2060 : head->writeIdx = 0;
131 2060 : head->bufSize = bufferSize;
132 2060 : head->msgSize = msgSize;
133 2060 : head->msgTxtSize = msgTxtSize;
134 2060 : head->mask = bufferSize - 1U;
135 2060 : head->errCount = 0;
136 2060 : TraceRbLogInitTime(head);
137 2060 : ADIAG_INF(
138 : "[%s] create ring buffer successfully, "
139 : "msgSize %u bytes, msgTxtSize %u bytes, bufferSize %u bytes, msg space %u bytes, total space %zu bytes",
140 : name, msgSize, msgTxtSize, bufferSize, msgSize, totalSize);
141 2060 : return rb;
142 : }
143 :
144 : /**
145 : * @brief destroy log ringbuffer
146 : * @param [in] rb: ringbuffer ptr
147 : * @return NA
148 : */
149 2319 : void TraceRbLogDestroy(struct RbLog* rb)
150 : {
151 2319 : if (rb != NULL) {
152 22605 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
153 20550 : if (rb->entry[i].list != NULL) {
154 208 : (void)AdiagListDestroy((struct AdiagList*)rb->entry[i].list);
155 208 : ADIAG_SAFE_FREE(rb->entry[i].list);
156 : }
157 : }
158 2055 : ADIAG_SAFE_FREE(rb);
159 : }
160 2319 : }
161 :
162 7215812 : STATIC INLINE RbLogMsg* TraceRbLogGetMsgByIndex(struct RbLog* rb, uint32_t msgIndex)
163 : {
164 7215812 : return (RbLogMsg*)(rb->msg + rb->head.msgSize * msgIndex);
165 : }
166 :
167 : /**
168 : * @brief write log msg to ringbuffer
169 : * @param [in] rb: ringbuffer ptr, caller guarantees not be NULL
170 : * @param [in] buffer: data buffer
171 : * @param [in] bufSize: data buffer size
172 : * @return TraStatus
173 : */
174 3166856 : TraStatus TraceRbLogWriteRbMsg(struct RbLog* rb, uint8_t bufferType, const char* buffer, uint32_t bufSize)
175 : {
176 3166856 : ADIAG_CHK_NULL_PTR(buffer, return TRACE_INVALID_PARAM);
177 3166833 : ADIAG_CHK_EXPR_ACTION(bufSize == 0, return TRACE_INVALID_PARAM, "invalid bufSize 0");
178 3166811 : uint32_t txtSize = bufSize;
179 3166811 : if (txtSize > rb->head.msgTxtSize) {
180 90135 : ADIAG_WAR(
181 : "[%s] msg size %u bytes exceeded ringbuffer msg size %u bytes, truncated.", rb->head.name, txtSize,
182 : rb->head.msgTxtSize);
183 90135 : txtSize = rb->head.msgTxtSize;
184 : }
185 3166811 : uint64_t monotonicTime = GetCpuCycleCounter();
186 3164655 : uint64_t originalWriteIdx = AO_F_ADD(&rb->head.writeIdx, 1);
187 3164655 : uint32_t writeIdx = (uint32_t)(originalWriteIdx & rb->head.mask);
188 3164655 : RbLogMsg* msg = TraceRbLogGetMsgByIndex(rb, writeIdx);
189 3491069 : if (!AO_CASB(&msg->head.busy, false, true)) {
190 0 : uint32_t errCount = AO_F_ADD(&rb->head.errCount, 1);
191 0 : if ((errCount & rb->head.mask) == 0) {
192 0 : ADIAG_WAR("[%s] can not write msg [%s] to index %u, buffer is busy", rb->head.name, buffer, writeIdx);
193 : }
194 0 : return TRACE_FAILURE;
195 : }
196 3491069 : int32_t ret = memcpy_s(msg->txt, rb->head.msgTxtSize, buffer, txtSize);
197 3449643 : if (ret != EOK) {
198 1 : ADIAG_ERR("[%s] memcpy_s ringbuffer msg failed.", rb->head.name);
199 23 : return TRACE_FAILURE;
200 : }
201 3503432 : msg->head.cycle = monotonicTime - rb->head.monotonicTime;
202 3503432 : msg->head.txtSize = txtSize;
203 3503432 : msg->head.bufferType = bufferType;
204 3503432 : AO_SET(&msg->head.busy, false);
205 3503432 : return TRACE_SUCCESS;
206 : }
207 :
208 26 : TraStatus TraceRbLogWriteRbMsgNoLock(struct RbLog* rb, uint8_t bufferType, const char* buffer, uint32_t bufSize)
209 : {
210 26 : if ((buffer == NULL) || (bufSize == 0)) {
211 1 : return TRACE_INVALID_PARAM;
212 : }
213 25 : struct RbLogCtrl* head = &rb->head;
214 25 : RbLogMsg* msg = (RbLogMsg*)(rb->msg + head->msgSize * (uint32_t)((++head->writeIdx) & head->mask));
215 25 : uint32_t txtSize = MIN(bufSize, head->msgTxtSize);
216 :
217 25 : int32_t ret = memcpy_s(msg->txt, head->msgTxtSize, buffer, txtSize);
218 25 : if (ret != EOK) {
219 1 : return TRACE_FAILURE;
220 : }
221 24 : msg->head.cycle = GetCpuCycleCounter() - head->monotonicTime;
222 24 : msg->head.txtSize = txtSize;
223 24 : msg->head.bufferType = bufferType;
224 24 : return TRACE_SUCCESS;
225 : }
226 :
227 6527298 : STATIC INLINE int RbLogMsgCmp(const void* a, const void* b)
228 : {
229 6527298 : const RbLogMsg* msgA = (const RbLogMsg*)a;
230 6527298 : const RbLogMsg* msgB = (const RbLogMsg*)b;
231 6527298 : if (msgA->head.busy != msgB->head.busy) {
232 0 : return msgA->head.busy ? 1 : 0; // msgA->head.busy > msgB->head.busy
233 : }
234 6527298 : return msgA->head.cycle > msgB->head.cycle;
235 : }
236 :
237 1197100 : STATIC TraStatus TraceRbLogCopyMsg(struct RbLog* newRb, struct RbLog* rb, uint32_t msgIndex)
238 : {
239 1197100 : uint32_t msgTxtSize = rb->head.msgTxtSize;
240 1197100 : RbLogMsg* msg = TraceRbLogGetMsgByIndex(rb, msgIndex);
241 1197100 : RbLogMsg* newMsg = TraceRbLogGetMsgByIndex(newRb, msgIndex);
242 :
243 1197100 : uint64_t cycle = msg->head.cycle;
244 1197100 : int32_t ret = memcpy_s(&newMsg->txt, msgTxtSize, &msg->txt, msgTxtSize);
245 1197100 : if (ret != EOK) {
246 22 : ADIAG_ERR("[%s] memcpy_s msg txt failed.", rb->head.name);
247 22 : return TRACE_FAILURE;
248 : }
249 1197078 : ret = memcpy_s(&newMsg->head, sizeof(RbMsgHead), &msg->head, sizeof(RbMsgHead));
250 1197078 : if (ret != EOK) {
251 22 : ADIAG_ERR("[%s] memcpy_s msg head failed.", rb->head.name);
252 22 : return TRACE_FAILURE;
253 : }
254 : // cycle has changed before memcpy finished, set busy to true to drop data.
255 1197056 : if (newMsg->head.cycle != cycle) {
256 0 : newMsg->head.busy = true;
257 : }
258 1197056 : return TRACE_SUCCESS;
259 : }
260 :
261 1257 : STATIC void TraceRbLogSort(struct RbLog* rb) { qsort(rb->msg, rb->head.bufSize, rb->head.msgSize, RbLogMsgCmp); }
262 :
263 : /**
264 : * @brief get struct entry list
265 : * @param [in/out] newRb: new ringbuffer
266 : * @param [in] traList: trace list of ring buffer
267 : * @return TRACE_SUCCESS success; TRACE_FAILURE failure
268 : */
269 140 : STATIC TraStatus TraceRbLogGetStructEntryList(struct AdiagList** newRbList, const struct AdiagList* traList)
270 : {
271 140 : struct AdiagList* newList = (struct AdiagList*)AdiagMalloc(sizeof(struct AdiagList));
272 140 : if (newList == NULL) {
273 22 : ADIAG_ERR("malloc new ringbuffer list failed.");
274 22 : return TRACE_FAILURE;
275 : }
276 118 : if (AdiagListInit(newList) != TRACE_SUCCESS) {
277 22 : ADIAG_ERR("init new ringbuffer list failed.");
278 22 : ADIAG_SAFE_FREE(newList);
279 22 : return TRACE_FAILURE;
280 : }
281 96 : struct ListHead* pos = NULL;
282 96 : struct AdiagListNode* node = NULL;
283 432 : LIST_FOR_EACH(pos, &traList->list)
284 : {
285 380 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
286 380 : if (node == NULL) {
287 0 : (void)AdiagListDestroy(newList);
288 0 : ADIAG_SAFE_FREE(newList);
289 0 : return TRACE_FAILURE;
290 : }
291 380 : TraceStructField* data = (TraceStructField*)AdiagMalloc(sizeof(TraceStructField));
292 380 : if (data == NULL) {
293 22 : ADIAG_ERR("malloc struct field failed.");
294 22 : (void)AdiagListDestroy(newList);
295 22 : ADIAG_SAFE_FREE(newList);
296 22 : return TRACE_FAILURE;
297 : }
298 358 : errno_t ret = memcpy_s(data, sizeof(TraceStructField), node->data, sizeof(TraceStructField));
299 358 : if (ret != EOK) {
300 0 : ADIAG_ERR("memcpy_s struct field failed.");
301 0 : ADIAG_SAFE_FREE(data);
302 0 : (void)AdiagListDestroy(newList);
303 0 : ADIAG_SAFE_FREE(newList);
304 0 : return TRACE_FAILURE;
305 : }
306 358 : if (AdiagListInsert(newList, data) != ADIAG_SUCCESS) {
307 22 : ADIAG_ERR("insert struct list failed.");
308 22 : ADIAG_SAFE_FREE(data);
309 22 : (void)AdiagListDestroy(newList);
310 22 : ADIAG_SAFE_FREE(newList);
311 22 : return TRACE_FAILURE;
312 : }
313 : }
314 52 : *newRbList = newList;
315 52 : return TRACE_SUCCESS;
316 : }
317 :
318 : /**
319 : * @brief copy ringbuffer to new buffer and sort valid msg by cycle
320 : * @param [out] newRb: new ringbuffer
321 : * @param [in] rb: original ringbuffer
322 : * @return TraStatus
323 : */
324 1349 : TraStatus TraceRbLogGetCopyOfRingBuffer(struct RbLog** newRb, struct RbLog* rb)
325 : {
326 1349 : size_t totalSize = sizeof(RbLog) + (size_t)rb->head.bufSize * rb->head.msgSize;
327 1349 : *newRb = AdiagMalloc(totalSize);
328 1349 : if (*newRb == NULL) {
329 24 : ADIAG_ERR("[%s] malloc new ringbuffer failed, size : %zu bytes.", rb->head.name, totalSize);
330 24 : return TRACE_FAILURE;
331 : }
332 1325 : errno_t ret = memcpy_s(*newRb, sizeof(RbLog), rb, sizeof(RbLog));
333 1325 : if (ret != EOK) {
334 24 : ADIAG_SAFE_FREE(*newRb);
335 24 : ADIAG_ERR("[%s] memcpy_s ringbuffer failed.", rb->head.name);
336 24 : return TRACE_FAILURE;
337 : }
338 1198357 : for (uint32_t i = 0; i < rb->head.bufSize; i++) {
339 1197100 : if (TraceRbLogCopyMsg(*newRb, rb, i) != TRACE_SUCCESS) {
340 44 : ADIAG_SAFE_FREE(*newRb);
341 44 : return TRACE_FAILURE;
342 : }
343 : }
344 1257 : TraceRbLogSort(*newRb);
345 : // if trace struct not defined, return success
346 1257 : struct AdiagList* traList = NULL;
347 12947 : for (uint32_t i = 0; i < TRACE_STRUCT_ENTRY_MAX_NUM; i++) {
348 11778 : traList = (struct AdiagList*)(rb->entry[i].list);
349 11778 : if ((rb->entry[i].list == NULL) || (ListEmpty(&traList->list))) {
350 11638 : continue;
351 : }
352 140 : if (TraceRbLogGetStructEntryList((struct AdiagList**)&(*newRb)->entry[i].list, traList) != TRACE_SUCCESS) {
353 88 : ADIAG_SAFE_FREE(*newRb);
354 88 : return TRACE_FAILURE;
355 : }
356 : }
357 1169 : return TRACE_SUCCESS;
358 : }
359 :
360 : /**
361 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
362 : * @param [in] rb: ringbuffer
363 : * @param [out] timeStr: timestamp str
364 : * @param [out] buffer: ptr of msg txt in ringbuffer
365 : * @return TraStatus
366 : */
367 348680 : TraStatus TraceRbLogReadRbMsg(struct RbLog* rb, char* timeStr, uint32_t timeStrSize, char** buffer)
368 : {
369 348680 : RbLogMsg* msg = NULL;
370 1054811 : for (; rb->head.readIdx != rb->head.bufSize; rb->head.readIdx++) {
371 1053718 : msg = TraceRbLogGetMsgByIndex(rb, rb->head.readIdx);
372 1053718 : if (msg->head.busy) { // msg has not been written done
373 0 : continue;
374 : }
375 1053718 : if (msg->head.txtSize == 0) {
376 706131 : continue;
377 : }
378 347587 : rb->head.readIdx++;
379 347587 : double costTime = (double)msg->head.cycle / (double)rb->head.cpuFreq * (double)FREQ_GHZ_TO_KHZ;
380 347587 : uint64_t timestamp = (uint64_t)costTime + rb->head.realTime;
381 347587 : TraStatus ret = TimestampToStr(timestamp, timeStr, timeStrSize);
382 347587 : if (ret != TRACE_SUCCESS) {
383 0 : return ret;
384 : }
385 347587 : uint32_t lastIndex = MIN(msg->head.txtSize, rb->head.msgTxtSize - 1U);
386 347587 : msg->txt[lastIndex] = '\0'; // ensure msg must have a string terminator
387 347587 : *buffer = msg->txt;
388 347587 : return TRACE_SUCCESS;
389 : }
390 1093 : *buffer = NULL;
391 1093 : return TRACE_RING_BUFFER_EMPTY;
392 : }
393 :
394 : /**
395 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
396 : * @param [in] rb: ringbuffer
397 : * @param [out] buffer: ptr of msg in ringbuffer
398 : * @param [out] bufLen: length of msg in ringbuffer
399 : * @return TraStatus
400 : */
401 157 : TraStatus TraceRbLogReadOriRbMsg(struct RbLog* rb, char** buffer, uint32_t* bufLen)
402 : {
403 157 : RbLogMsg* msg = NULL;
404 53299 : for (; rb->head.readIdx != rb->head.bufSize; rb->head.readIdx++) {
405 53247 : msg = TraceRbLogGetMsgByIndex(rb, rb->head.readIdx);
406 53247 : if (msg->head.txtSize == 0) {
407 53142 : continue;
408 : }
409 105 : rb->head.readIdx++;
410 105 : *buffer = (char*)msg;
411 105 : *bufLen = rb->head.msgSize;
412 105 : return TRACE_SUCCESS;
413 : }
414 52 : *buffer = NULL;
415 52 : *bufLen = 0;
416 52 : return TRACE_RING_BUFFER_EMPTY;
417 : }
418 :
419 90 : void TraceRbLogPrepareForRead(struct RbLog* rb) { rb->head.readIdx = 0; }
420 :
421 245 : STATIC RbLogMsg* TraceRbLogGetOldestMsg(struct RbLog* rb, uint64_t* cycle, bool filterBusy)
422 : {
423 245 : RbLogMsg* oldestMsg = NULL;
424 245 : RbLogMsg* msg = NULL;
425 251125 : for (uint32_t i = 0; i < rb->head.bufSize; i++) {
426 250880 : msg = TraceRbLogGetMsgByIndex(rb, i);
427 250880 : if (msg->head.txtSize == 0) {
428 250702 : continue;
429 : }
430 178 : if ((filterBusy) && (msg->head.busy)) {
431 0 : continue;
432 : }
433 178 : if (msg->head.cycle <= *cycle) {
434 23 : continue;
435 : }
436 155 : if ((oldestMsg == NULL) || (msg->head.cycle < oldestMsg->head.cycle)) {
437 155 : oldestMsg = msg;
438 : }
439 : }
440 245 : if (oldestMsg != NULL) {
441 155 : *cycle = oldestMsg->head.cycle;
442 : }
443 245 : return oldestMsg;
444 : }
445 :
446 : /**
447 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
448 : * @param [in] rb: ringbuffer
449 : * @param [out] timeStr: timestamp str
450 : * @param [out] buffer: ptr of msg txt in ringbuffer
451 : * @return TraStatus
452 : */
453 177 : TraStatus TraceRbLogReadRbMsgSafe(struct RbLog* rb, char* timeStr, uint32_t timeStrSize, char** buffer)
454 : {
455 177 : if (rb->head.readIdx == rb->head.bufSize) {
456 0 : return TRACE_RING_BUFFER_EMPTY;
457 : }
458 177 : uint64_t cycle = 0;
459 177 : RbLogMsg* msg = TraceRbLogGetOldestMsg(rb, &cycle, true);
460 177 : if (msg == NULL) {
461 67 : return TRACE_RING_BUFFER_EMPTY;
462 : }
463 110 : double costTime = (double)msg->head.cycle / (double)rb->head.cpuFreq * (double)FREQ_GHZ_TO_KHZ;
464 110 : uint64_t timestamp = (uint64_t)costTime + rb->head.realTime;
465 110 : TraStatus ret = TimestampToStr(timestamp, timeStr, timeStrSize);
466 110 : if (ret != TRACE_SUCCESS) {
467 0 : return ret;
468 : }
469 110 : uint32_t lastIndex = MIN(msg->head.txtSize, rb->head.msgTxtSize - 1U);
470 110 : msg->txt[lastIndex] = '\0'; // ensure msg must have a string terminator
471 110 : *buffer = msg->txt;
472 110 : msg->head.txtSize = 0;
473 110 : rb->head.readIdx++;
474 110 : return TRACE_SUCCESS;
475 : }
476 :
477 : /**
478 : * @brief read msg from ringbuffer, must be reentrant, cannot print msg
479 : * @param [in] rb: ringbuffer
480 : * @param [out] buffer: ptr of msg in ringbuffer
481 : * @param [out] bufLen: length of msg in ringbuffer
482 : * @return TraStatus
483 : */
484 68 : TraStatus TraceRbLogReadOriRbMsgSafe(struct RbLog* rb, char** buffer, uint32_t* bufLen, uint64_t* cycle)
485 : {
486 68 : if (rb->head.readIdx == rb->head.bufSize) {
487 0 : return TRACE_RING_BUFFER_EMPTY;
488 : }
489 68 : RbLogMsg* msg = TraceRbLogGetOldestMsg(rb, cycle, false);
490 68 : if (msg == NULL) {
491 23 : return TRACE_RING_BUFFER_EMPTY;
492 : }
493 45 : *buffer = (char*)msg;
494 45 : *bufLen = rb->head.msgSize;
495 45 : rb->head.readIdx++;
496 45 : return TRACE_SUCCESS;
497 : }
498 :
499 106 : uint32_t TracerRbLogGetMsgNum(const RbLog* rb)
500 : {
501 106 : return (rb->head.writeIdx > (uint64_t)rb->head.bufSize) ? rb->head.bufSize : (uint32_t)rb->head.writeIdx;
502 : }
|