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