1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.8.1
3 * Copyright 2023 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The implementation for the event buffer.
9 */
10
11 #include <trcRecorder.h>
12
13 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
14
15 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
16
xTraceEventBufferInitialize(TraceEventBuffer_t * pxTraceEventBuffer,uint32_t uiOptions,uint8_t * puiBuffer,uint32_t uiSize)17 traceResult xTraceEventBufferInitialize(TraceEventBuffer_t* pxTraceEventBuffer, uint32_t uiOptions,
18 uint8_t* puiBuffer, uint32_t uiSize)
19 {
20 /* This should never fail */
21 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
22
23 /* This should never fail */
24 TRC_ASSERT(puiBuffer != (void*)0);
25
26 /* This should never fail */
27 TRC_ASSERT(uiSize != 0u);
28
29 pxTraceEventBuffer->uiOptions = uiOptions;
30 pxTraceEventBuffer->uiHead = 0u;
31 pxTraceEventBuffer->uiTail = 0u;
32 pxTraceEventBuffer->uiSize = uiSize;
33 pxTraceEventBuffer->uiFree = uiSize;
34 pxTraceEventBuffer->puiBuffer = puiBuffer;
35 pxTraceEventBuffer->uiSlack = 0u;
36 pxTraceEventBuffer->uiNextHead = 0u;
37 pxTraceEventBuffer->uiTimerWraparounds = 0u;
38
39 xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_EVENT_BUFFER);
40
41 return TRC_SUCCESS;
42 }
43
44 /**
45 * @brief Pops the oldest event from the Event Buffer.
46 *
47 * @param[in] pxTraceEventBuffer Pointer to initialized trace event buffer.
48 *
49 * @retval TRC_FAIL Failure
50 * @retval TRC_SUCCESS Success
51 */
prvTraceEventBufferPop(TraceEventBuffer_t * pxTraceEventBuffer)52 static traceResult prvTraceEventBufferPop(TraceEventBuffer_t *pxTraceEventBuffer)
53 {
54 uint32_t uiFreeSize = 0u;
55
56 /* Get size of event we are freeing */
57 /* This should never fail */
58 TRC_ASSERT_ALWAYS_EVALUATE(xTraceEventGetSize(((void*)&(pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiTail])), &uiFreeSize) == TRC_SUCCESS); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
59
60 pxTraceEventBuffer->uiFree += uiFreeSize;
61
62 /* Update tail to point to the new last event */
63 pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
64
65 return TRC_SUCCESS;
66 }
67
prvTraceEventBufferAllocPop(TraceEventBuffer_t * pxTraceEventBuffer)68 static traceResult prvTraceEventBufferAllocPop(TraceEventBuffer_t *pxTraceEventBuffer)
69 {
70 uint32_t uiFreeSize = 0u;
71
72 /* Check if tail is in, or at the start of the slack area. We do not want to call
73 * a free when in the slack area since it would read garbage data and free would
74 * become undefined.
75 */
76 if (pxTraceEventBuffer->uiTail >= (pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiSlack))
77 {
78 /* Tail was in the slack area, wrap back to the start of the buffer. */
79 pxTraceEventBuffer->uiTail = 0u;
80 }
81 else
82 {
83 /* Get size of event we are freeing (this should never fail) */
84 TRC_ASSERT_ALWAYS_EVALUATE(xTraceEventGetSize(((void*)&(pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiTail])), &uiFreeSize) == TRC_SUCCESS); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
85
86 /* Update tail to point to the new last event */
87 pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
88 }
89
90 return TRC_SUCCESS;
91 }
92
xTraceEventBufferAlloc(TraceEventBuffer_t * pxTraceEventBuffer,uint32_t uiSize,void ** ppvData)93 traceResult xTraceEventBufferAlloc(TraceEventBuffer_t *pxTraceEventBuffer, uint32_t uiSize, void **ppvData)
94 {
95 uint32_t uiFreeSpace;
96 uint32_t uiHead;
97 uint32_t uiTail;
98 uint32_t uiBufferSize;
99
100 /* This should never fail */
101 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
102
103 /* This should never fail */
104 TRC_ASSERT(ppvData != (void*)0);
105
106 uiBufferSize = pxTraceEventBuffer->uiSize;
107
108 TRC_ASSERT(uiBufferSize != 0u);
109
110 /* Check if the data size is larger than the buffer */
111 /* This should never fail */
112 TRC_ASSERT(uiSize <= uiBufferSize);
113
114 /* Handle overwrite buffer allocation, since this kind of allocation modifies
115 * both head and tail it should only be used for internal buffers without any
116 * flushing calls (Streaming Ringbuffer)
117 */
118 if (pxTraceEventBuffer->uiOptions == TRC_EVENT_BUFFER_OPTION_OVERWRITE)
119 {
120 if (pxTraceEventBuffer->uiHead >= pxTraceEventBuffer->uiTail)
121 {
122 /* Do we have enough space to directly allocate from the buffer? */
123 if ((uiBufferSize - pxTraceEventBuffer->uiHead) > uiSize)
124 {
125 *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
126 pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize) % uiBufferSize;
127 }
128 /* There wasn't enough space for a direct alloc, handle freeing up
129 * space and wrapping. */
130 else
131 {
132 /* Free space until there is enough space for a contiguous
133 * allocation */
134 do
135 {
136 (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
137 uiFreeSpace = pxTraceEventBuffer->uiTail - sizeof(uint32_t);
138 } while (uiFreeSpace < uiSize);
139
140 /* Calculate slack from the wrapping */
141 pxTraceEventBuffer->uiSlack = uiBufferSize - pxTraceEventBuffer->uiHead;
142
143 /* Wrap head */
144 pxTraceEventBuffer->uiHead = 0u;
145
146 /* Allocate data */
147 *ppvData = pxTraceEventBuffer->puiBuffer;
148
149 pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize) % uiBufferSize;
150 }
151 }
152 else
153 {
154 uiFreeSpace = pxTraceEventBuffer->uiTail - pxTraceEventBuffer->uiHead - sizeof(uint32_t);
155
156 /* Check if we have to free space */
157 if (uiFreeSpace < uiSize)
158 {
159 /* Check if this is a wrapping alloc */
160 if ((pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiHead) < uiSize)
161 {
162 /* To avoid uiHead and uiTail from becoming the same we want to
163 * pop any events that would make uiTail equal uiHead before
164 * wrapping the head. */
165 do
166 {
167 (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
168 } while (pxTraceEventBuffer->uiTail == 0u);
169
170 pxTraceEventBuffer->uiSlack = pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiHead;
171 pxTraceEventBuffer->uiHead = 0u;
172 }
173
174 do
175 {
176 (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
177 uiFreeSpace = pxTraceEventBuffer->uiTail - pxTraceEventBuffer->uiHead - sizeof(uint32_t);
178 } while (uiFreeSpace < uiSize);
179
180 if (pxTraceEventBuffer->uiTail == 0u)
181 {
182 *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
183 }
184 }
185
186 /* Alloc data */
187 *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
188
189 pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize);
190 }
191 }
192 else
193 {
194 /* Since a consumer could potentially update tail (free) during the procedure
195 * we have to save it here to avoid problems with it changing during this call.
196 */
197 uiHead = pxTraceEventBuffer->uiHead;
198 uiTail = pxTraceEventBuffer->uiTail;
199
200 if (uiHead >= uiTail)
201 {
202 uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
203
204 if (uiFreeSpace < uiSize)
205 {
206 *ppvData = 0;
207
208 return TRC_FAIL;
209 }
210
211 /* Copy data */
212 if ((uiBufferSize - uiHead) > uiSize)
213 {
214 *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
215
216 pxTraceEventBuffer->uiNextHead = (uiHead + uiSize) % uiBufferSize;
217 }
218 else
219 {
220 uiFreeSpace = uiTail;
221
222 if (uiFreeSpace < uiSize)
223 {
224 *ppvData = 0;
225
226 return TRC_FAIL;
227 }
228
229 /* Calculate slack */
230 pxTraceEventBuffer->uiSlack = uiBufferSize - uiHead;
231
232 *ppvData = pxTraceEventBuffer->puiBuffer;
233
234 pxTraceEventBuffer->uiNextHead = (uiHead + pxTraceEventBuffer->uiSlack + uiSize) % uiBufferSize;
235 }
236 }
237 else
238 {
239 uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
240
241 if (uiFreeSpace < uiSize)
242 {
243 *ppvData = 0;
244
245 return TRC_FAIL;
246 }
247
248 /* Alloc data */
249 *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
250
251 pxTraceEventBuffer->uiNextHead = (uiHead + uiSize);
252 }
253 }
254
255 return TRC_SUCCESS;
256 }
257
xTraceEventBufferAllocCommit(TraceEventBuffer_t * pxTraceEventBuffer,const void * pvData,uint32_t uiSize,int32_t * piBytesWritten)258 traceResult xTraceEventBufferAllocCommit(TraceEventBuffer_t *pxTraceEventBuffer, const void *pvData, uint32_t uiSize, int32_t *piBytesWritten)
259 {
260 (void)pvData;
261
262 /* This should never fail */
263 TRC_ASSERT_ALWAYS_EVALUATE(xTraceTimestampGetWraparounds(&pxTraceEventBuffer->uiTimerWraparounds) == TRC_SUCCESS);
264
265 /* Advance head location */
266 pxTraceEventBuffer->uiHead = pxTraceEventBuffer->uiNextHead;
267
268 /* Update bytes written */
269 *piBytesWritten = (int32_t)uiSize;
270
271 return TRC_SUCCESS;
272 }
273
xTraceEventBufferPush(TraceEventBuffer_t * pxTraceEventBuffer,void * pvData,uint32_t uiSize,int32_t * piBytesWritten)274 traceResult xTraceEventBufferPush(TraceEventBuffer_t *pxTraceEventBuffer, void *pvData, uint32_t uiSize, int32_t *piBytesWritten)
275 {
276 uint32_t uiBufferSize;
277 uint32_t uiHead;
278 uint32_t uiTail;
279 uint32_t uiFreeSpace;
280
281 /* This should never fail */
282 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
283
284 /* This should never fail */
285 TRC_ASSERT(pvData != (void*)0);
286
287 uiBufferSize = pxTraceEventBuffer->uiSize;
288
289 TRC_ASSERT(uiBufferSize != 0u);
290
291 /* Check if the data size is larger than the buffer */
292 /* This should never fail */
293 TRC_ASSERT(uiSize <= uiBufferSize);
294
295 /* Check byte alignment */
296 /* This should never fail */
297 TRC_ASSERT((uiSize % 4u) == 0u);
298
299 /* Ensure bytes written start at 0 */
300 /* This should never fail */
301 TRC_ASSERT(piBytesWritten != (void*)0);
302
303 *piBytesWritten = 0;
304
305 /* This should never fail */
306 TRC_ASSERT_ALWAYS_EVALUATE(xTraceTimestampGetWraparounds(&pxTraceEventBuffer->uiTimerWraparounds) == TRC_SUCCESS);
307
308 /* In ring buffer mode we cannot provide lock free access since the producer modified
309 * the head and tail variables in the same call. This option is only safe when used
310 * with an internal buffer (streaming snapshot) which no consumer accesses.
311 */
312 switch (pxTraceEventBuffer->uiOptions)
313 {
314 case TRC_EVENT_BUFFER_OPTION_OVERWRITE:
315 uiHead = pxTraceEventBuffer->uiHead;
316
317 /* If there isn't enough space in the buffer pop events until there is */
318 while (pxTraceEventBuffer->uiFree < uiSize)
319 {
320 (void)prvTraceEventBufferPop(pxTraceEventBuffer);
321 }
322
323 /* Copy data */
324 if ((uiBufferSize - uiHead) > uiSize)
325 {
326 TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
327 }
328 else
329 {
330 TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, (uiBufferSize - uiHead)); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
331 TRC_MEMCPY(pxTraceEventBuffer->puiBuffer, (void*)(&((uint8_t*)pvData)[(uiBufferSize - uiHead)]), (uiSize - (uiBufferSize - uiHead))); /*cstat !MISRAC2012-Rule-11.5 Suppress pointer checks*/ /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
332 }
333
334 pxTraceEventBuffer->uiFree -= uiSize;
335
336 pxTraceEventBuffer->uiHead = (uiHead + uiSize) % uiBufferSize;
337
338 *piBytesWritten = (int32_t)uiSize;
339 break;
340 case TRC_EVENT_BUFFER_OPTION_SKIP:
341 /* Since a consumer could potentially update tail (free) during the procedure
342 * we have to save it here to avoid problems with the push algorithm.
343 */
344 uiHead = pxTraceEventBuffer->uiHead;
345 uiTail = pxTraceEventBuffer->uiTail;
346
347 if (uiHead >= uiTail)
348 {
349 uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
350
351 if (uiFreeSpace < uiSize)
352 {
353 *piBytesWritten = 0;
354
355 return TRC_SUCCESS;
356 }
357
358 /* Copy data */
359 if ((uiBufferSize - uiHead) > uiSize)
360 {
361 TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
362 }
363 else
364 {
365 TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, (uiBufferSize - uiHead)); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
366 TRC_MEMCPY(pxTraceEventBuffer->puiBuffer, (void*)(&((uint8_t*)pvData)[(uiBufferSize - uiHead)]), (uiSize - (uiBufferSize - uiHead))); /*cstat !MISRAC2012-Rule-11.5 Suppress pointer checks*/ /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
367 }
368
369 pxTraceEventBuffer->uiHead = (uiHead + uiSize) % uiBufferSize;
370 }
371 else
372 {
373 uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
374
375 if (uiFreeSpace < uiSize)
376 {
377 *piBytesWritten = 0;
378
379 return TRC_SUCCESS;
380 }
381
382 /* Copy data */
383 TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
384
385 pxTraceEventBuffer->uiHead = (uiHead + uiSize);
386 }
387
388 *piBytesWritten = (int32_t)uiSize;
389 break;
390 default:
391 return TRC_FAIL;
392 break;
393 }
394
395 return TRC_SUCCESS;
396 }
397
xTraceEventBufferTransferAll(TraceEventBuffer_t * pxTraceEventBuffer,int32_t * piBytesWritten)398 traceResult xTraceEventBufferTransferAll(TraceEventBuffer_t* pxTraceEventBuffer, int32_t* piBytesWritten)
399 {
400 int32_t iBytesWritten = 0;
401 int32_t iSumBytesWritten = 0;
402 uint32_t uiHead;
403 uint32_t uiTail;
404 uint32_t uiSlack;
405
406 /* This should never fail */
407 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
408
409 /* This should never fail */
410 TRC_ASSERT(piBytesWritten != (void*)0);
411
412 uiHead = pxTraceEventBuffer->uiHead;
413 uiTail = pxTraceEventBuffer->uiTail;
414 uiSlack = pxTraceEventBuffer->uiSlack;
415
416 /* Check if core event buffer is empty */
417 if (uiHead == uiTail)
418 {
419 /* Make sure this value is set in case it was passed uninitialized. */
420 *piBytesWritten = 0;
421
422 return TRC_SUCCESS;
423 }
424
425 /* Check if we can do a direct write or if we have to handle wrapping */
426 if (uiHead > uiTail)
427 {
428 /* No wrapping */
429 xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (uiHead - uiTail), &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
430 }
431 else
432 {
433 /* Wrapping */
434
435 /* Try to write: tail -> end of buffer */
436 xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (pxTraceEventBuffer->uiSize - uiTail - uiSlack), &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
437
438 /* Did we manage to write all bytes? */
439 if ((uint32_t)iBytesWritten == (pxTraceEventBuffer->uiSize - uiTail - uiSlack))
440 {
441 /* uiTail is moved to start of buffer */
442 pxTraceEventBuffer->uiTail = 0u;
443
444 iSumBytesWritten = iBytesWritten;
445
446 /* We zero this here in case it does not get zeroed by the streamport. This isn't really a problem with our
447 * streamports, but there has been cases with custom streamport forgetting to set this to 0 if there is no
448 * data to write. */
449 iBytesWritten = 0;
450
451 /* Try to write: start of buffer -> head */
452 xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[0], uiHead, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
453 }
454 }
455
456 /* Move tail */
457 pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
458
459 iSumBytesWritten += iBytesWritten;
460
461 *piBytesWritten = iSumBytesWritten;
462
463 return TRC_SUCCESS;
464 }
465
xTraceEventBufferTransferChunk(TraceEventBuffer_t * pxTraceEventBuffer,uint32_t uiChunkSize,int32_t * piBytesWritten)466 traceResult xTraceEventBufferTransferChunk(TraceEventBuffer_t* pxTraceEventBuffer, uint32_t uiChunkSize, int32_t* piBytesWritten)
467 {
468 int32_t iBytesWritten = 0;
469 uint32_t uiHead;
470 uint32_t uiTail;
471 uint32_t uiSlack;
472 uint32_t uiBytesToWrite;
473
474 /* This should never fail */
475 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
476
477 /* This should never fail */
478 TRC_ASSERT(piBytesWritten != (void*)0);
479
480 uiHead = pxTraceEventBuffer->uiHead;
481 uiTail = pxTraceEventBuffer->uiTail;
482 uiSlack = pxTraceEventBuffer->uiSlack;
483
484 /* Check if core event buffer is empty */
485 if (uiHead == uiTail)
486 {
487 /* Make sure this value is set in case it was passed uninitialized. */
488 *piBytesWritten = 0;
489
490 return TRC_SUCCESS;
491 }
492
493 /* Check if we can do a direct write or if we have to handle wrapping */
494 if (uiHead > uiTail)
495 {
496 uiBytesToWrite = uiHead - uiTail;
497 if (uiBytesToWrite > uiChunkSize)
498 {
499 uiBytesToWrite = uiChunkSize;
500 }
501
502 (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], uiBytesToWrite, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
503
504 pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
505 }
506 else
507 {
508 uiBytesToWrite = pxTraceEventBuffer->uiSize - uiTail - uiSlack;
509 if (uiBytesToWrite > uiChunkSize)
510 {
511 uiBytesToWrite = uiChunkSize;
512 }
513
514 (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], uiBytesToWrite, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
515
516 /* Check if we managed to write until the end or not, if we didn't we
517 * add the number of bytes written. If we managed to write the last
518 * segment, reset tail to 0. */
519 if ((uiTail + (uint32_t)iBytesWritten) == (pxTraceEventBuffer->uiSize - uiSlack))
520 {
521 pxTraceEventBuffer->uiTail = 0u;
522 }
523 else
524 {
525 pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
526 }
527 }
528
529 *piBytesWritten = iBytesWritten;
530
531 return TRC_SUCCESS;
532 }
533
xTraceEventBufferClear(TraceEventBuffer_t * pxTraceEventBuffer)534 traceResult xTraceEventBufferClear(TraceEventBuffer_t* pxTraceEventBuffer)
535 {
536 /* This should never fail */
537 TRC_ASSERT(pxTraceEventBuffer != (void*)0);
538
539 pxTraceEventBuffer->uiHead = 0u;
540 pxTraceEventBuffer->uiTail = 0u;
541 pxTraceEventBuffer->uiFree = pxTraceEventBuffer->uiSize;
542 pxTraceEventBuffer->uiSlack = 0u;
543 pxTraceEventBuffer->uiNextHead = 0u;
544
545 return TRC_SUCCESS;
546 }
547
548 #endif
549
550 #endif
551