| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- /*
- * Percepio Trace Recorder for Tracealyzer v4.9.2
- * Copyright 2023 Percepio AB
- * www.percepio.com
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * The implementation for the event buffer.
- */
- #include <trcRecorder.h>
- #if (TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
- traceResult xTraceEventBufferInitialize(TraceEventBuffer_t* pxTraceEventBuffer, uint32_t uiOptions,
- uint8_t* puiBuffer, uint32_t uiSize)
- {
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
- /* This should never fail */
- TRC_ASSERT(puiBuffer != (void*)0);
- /* This should never fail */
- TRC_ASSERT(uiSize != 0u);
- pxTraceEventBuffer->uiOptions = uiOptions;
- pxTraceEventBuffer->uiHead = 0u;
- pxTraceEventBuffer->uiTail = 0u;
- pxTraceEventBuffer->uiSize = uiSize;
- pxTraceEventBuffer->uiFree = uiSize;
- pxTraceEventBuffer->puiBuffer = puiBuffer;
- pxTraceEventBuffer->uiSlack = 0u;
- pxTraceEventBuffer->uiNextHead = 0u;
- pxTraceEventBuffer->uiTimerWraparounds = 0u;
- (void)xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_EVENT_BUFFER);
- return TRC_SUCCESS;
- }
- /**
- * @brief Pops the oldest event from the Event Buffer.
- *
- * @param[in] pxTraceEventBuffer Pointer to initialized trace event buffer.
- *
- * @retval TRC_FAIL Failure
- * @retval TRC_SUCCESS Success
- */
- static traceResult prvTraceEventBufferPop(TraceEventBuffer_t *pxTraceEventBuffer)
- {
- uint32_t uiFreeSize = 0u;
- /* Get size of event we are freeing */
- /* This should never fail */
- 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*/
- pxTraceEventBuffer->uiFree += uiFreeSize;
- /* Update tail to point to the new last event */
- pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
- return TRC_SUCCESS;
- }
- static traceResult prvTraceEventBufferAllocPop(TraceEventBuffer_t *pxTraceEventBuffer)
- {
- uint32_t uiFreeSize = 0u;
- /* Check if tail is in, or at the start of the slack area. We do not want to call
- * a free when in the slack area since it would read garbage data and free would
- * become undefined.
- */
- if (pxTraceEventBuffer->uiTail >= (pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiSlack))
- {
- /* Tail was in the slack area, wrap back to the start of the buffer. */
- pxTraceEventBuffer->uiTail = 0u;
- }
- else
- {
- /* Get size of event we are freeing (this should never fail) */
- 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*/
- /* Update tail to point to the new last event */
- pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
- }
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferAlloc(TraceEventBuffer_t *pxTraceEventBuffer, uint32_t uiSize, void **ppvData)
- {
- uint32_t uiFreeSpace;
- uint32_t uiHead;
- uint32_t uiTail;
- uint32_t uiBufferSize;
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
-
- /* This should never fail */
- TRC_ASSERT(ppvData != (void*)0);
- uiBufferSize = pxTraceEventBuffer->uiSize;
-
- TRC_ASSERT(uiBufferSize != 0u);
- /* Check if the data size is larger than the buffer */
- /* This should never fail */
- TRC_ASSERT(uiSize <= uiBufferSize);
- /* Handle overwrite buffer allocation, since this kind of allocation modifies
- * both head and tail it should only be used for internal buffers without any
- * flushing calls (Streaming Ringbuffer)
- */
- if (pxTraceEventBuffer->uiOptions == TRC_EVENT_BUFFER_OPTION_OVERWRITE)
- {
- if (pxTraceEventBuffer->uiHead >= pxTraceEventBuffer->uiTail)
- {
- /* Do we have enough space to directly allocate from the buffer? */
- if ((uiBufferSize - pxTraceEventBuffer->uiHead) > uiSize)
- {
- *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize) % uiBufferSize;
- }
- /* There wasn't enough space for a direct alloc, handle freeing up
- * space and wrapping. */
- else
- {
- /* Free space until there is enough space for a contiguous
- * allocation */
- do
- {
- (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
- uiFreeSpace = pxTraceEventBuffer->uiTail - sizeof(uint32_t);
- } while (uiFreeSpace < uiSize);
- /* Calculate slack from the wrapping */
- pxTraceEventBuffer->uiSlack = uiBufferSize - pxTraceEventBuffer->uiHead;
- /* Wrap head */
- pxTraceEventBuffer->uiHead = 0u;
- /* Allocate data */
- *ppvData = pxTraceEventBuffer->puiBuffer;
- pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize) % uiBufferSize;
- }
- }
- else
- {
- uiFreeSpace = pxTraceEventBuffer->uiTail - pxTraceEventBuffer->uiHead - sizeof(uint32_t);
- /* Check if we have to free space */
- if (uiFreeSpace < uiSize)
- {
- /* Check if this is a wrapping alloc */
- if ((pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiHead) < uiSize)
- {
- /* To avoid uiHead and uiTail from becoming the same we want to
- * pop any events that would make uiTail equal uiHead before
- * wrapping the head. */
- do
- {
- (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
- } while (pxTraceEventBuffer->uiTail == 0u);
- pxTraceEventBuffer->uiSlack = pxTraceEventBuffer->uiSize - pxTraceEventBuffer->uiHead;
- pxTraceEventBuffer->uiHead = 0u;
- }
-
- do
- {
- (void)prvTraceEventBufferAllocPop(pxTraceEventBuffer);
- uiFreeSpace = pxTraceEventBuffer->uiTail - pxTraceEventBuffer->uiHead - sizeof(uint32_t);
- } while (uiFreeSpace < uiSize);
- if (pxTraceEventBuffer->uiTail == 0u)
- {
- *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- }
- }
- /* Alloc data */
- *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiNextHead = (pxTraceEventBuffer->uiHead + uiSize);
- }
- }
- else
- {
- /* Since a consumer could potentially update tail (free) during the procedure
- * we have to save it here to avoid problems with it changing during this call.
- */
- uiHead = pxTraceEventBuffer->uiHead;
- uiTail = pxTraceEventBuffer->uiTail;
- if (uiHead >= uiTail)
- {
- uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
- if (uiFreeSpace < uiSize)
- {
- *ppvData = 0;
- return TRC_FAIL;
- }
- /* Copy data */
- if ((uiBufferSize - uiHead) > uiSize)
- {
- *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiNextHead = (uiHead + uiSize) % uiBufferSize;
- }
- else
- {
- uiFreeSpace = uiTail;
- if (uiFreeSpace < uiSize)
- {
- *ppvData = 0;
- return TRC_FAIL;
- }
- /* Calculate slack */
- pxTraceEventBuffer->uiSlack = uiBufferSize - uiHead;
- *ppvData = pxTraceEventBuffer->puiBuffer;
- pxTraceEventBuffer->uiNextHead = (uiHead + pxTraceEventBuffer->uiSlack + uiSize) % uiBufferSize;
- }
- }
- else
- {
- uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
- if (uiFreeSpace < uiSize)
- {
- *ppvData = 0;
- return TRC_FAIL;
- }
- /* Alloc data */
- *ppvData = &pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead]; /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiNextHead = (uiHead + uiSize);
- }
- }
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferAllocCommit(TraceEventBuffer_t *pxTraceEventBuffer, const void *pvData, uint32_t uiSize, int32_t *piBytesWritten)
- {
- (void)pvData;
- /* This should never fail */
- TRC_ASSERT_ALWAYS_EVALUATE(xTraceTimestampGetWraparounds(&pxTraceEventBuffer->uiTimerWraparounds) == TRC_SUCCESS);
- /* Advance head location */
- pxTraceEventBuffer->uiHead = pxTraceEventBuffer->uiNextHead;
- /* Update bytes written */
- *piBytesWritten = (int32_t)uiSize;
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferPush(TraceEventBuffer_t *pxTraceEventBuffer, void *pvData, uint32_t uiSize, int32_t *piBytesWritten)
- {
- uint32_t uiBufferSize;
- uint32_t uiHead;
- uint32_t uiTail;
- uint32_t uiFreeSpace;
-
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
-
- /* This should never fail */
- TRC_ASSERT(pvData != (void*)0);
-
- uiBufferSize = pxTraceEventBuffer->uiSize;
-
- TRC_ASSERT(uiBufferSize != 0u);
- /* Check if the data size is larger than the buffer */
- /* This should never fail */
- TRC_ASSERT(uiSize <= uiBufferSize);
- /* Check byte alignment */
- /* This should never fail */
- TRC_ASSERT((uiSize % 4u) == 0u);
- /* Ensure bytes written start at 0 */
- /* This should never fail */
- TRC_ASSERT(piBytesWritten != (void*)0);
- *piBytesWritten = 0;
- /* This should never fail */
- TRC_ASSERT_ALWAYS_EVALUATE(xTraceTimestampGetWraparounds(&pxTraceEventBuffer->uiTimerWraparounds) == TRC_SUCCESS);
- /* In ring buffer mode we cannot provide lock free access since the producer modified
- * the head and tail variables in the same call. This option is only safe when used
- * with an internal buffer (streaming snapshot) which no consumer accesses.
- */
- switch (pxTraceEventBuffer->uiOptions)
- {
- case TRC_EVENT_BUFFER_OPTION_OVERWRITE:
- uiHead = pxTraceEventBuffer->uiHead;
- /* If there isn't enough space in the buffer pop events until there is */
- while (pxTraceEventBuffer->uiFree < uiSize)
- {
- (void)prvTraceEventBufferPop(pxTraceEventBuffer);
- }
- /* Copy data */
- if ((uiBufferSize - uiHead) > uiSize)
- {
- TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- }
- else
- {
- TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, (uiBufferSize - uiHead)); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- 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*/
- }
- pxTraceEventBuffer->uiFree -= uiSize;
- pxTraceEventBuffer->uiHead = (uiHead + uiSize) % uiBufferSize;
- *piBytesWritten = (int32_t)uiSize;
- break;
- case TRC_EVENT_BUFFER_OPTION_SKIP:
- /* Since a consumer could potentially update tail (free) during the procedure
- * we have to save it here to avoid problems with the push algorithm.
- */
- uiHead = pxTraceEventBuffer->uiHead;
- uiTail = pxTraceEventBuffer->uiTail;
- if (uiHead >= uiTail)
- {
- uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
- if (uiFreeSpace < uiSize)
- {
- *piBytesWritten = 0;
- return TRC_SUCCESS;
- }
- /* Copy data */
- if ((uiBufferSize - uiHead) > uiSize)
- {
- TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- }
- else
- {
- TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pvData, (uiBufferSize - uiHead)); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- 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*/
- }
- pxTraceEventBuffer->uiHead = (uiHead + uiSize) % uiBufferSize;
- }
- else
- {
- uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
- if (uiFreeSpace < uiSize)
- {
- *piBytesWritten = 0;
- return TRC_SUCCESS;
- }
- /* Copy data */
- TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pvData, uiSize); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiHead = (uiHead + uiSize);
- }
- *piBytesWritten = (int32_t)uiSize;
- break;
- default:
- return TRC_FAIL;
- }
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferTransferAll(TraceEventBuffer_t* pxTraceEventBuffer, int32_t* piBytesWritten)
- {
- int32_t iBytesWritten = 0;
- int32_t iSumBytesWritten = 0;
- uint32_t uiHead;
- uint32_t uiTail;
- uint32_t uiSlack;
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
- /* This should never fail */
- TRC_ASSERT(piBytesWritten != (void*)0);
- uiHead = pxTraceEventBuffer->uiHead;
- uiTail = pxTraceEventBuffer->uiTail;
- uiSlack = pxTraceEventBuffer->uiSlack;
- /* Check if core event buffer is empty */
- if (uiHead == uiTail)
- {
- /* Make sure this value is set in case it was passed uninitialized. */
- *piBytesWritten = 0;
- return TRC_SUCCESS;
- }
- /* Check if we can do a direct write or if we have to handle wrapping */
- if (uiHead > uiTail)
- {
- /* No wrapping */
- (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (uiHead - uiTail), &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- }
- else
- {
- /* Wrapping */
- /* Try to write: tail -> end of buffer */
- (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*/
- /* Did we manage to write all bytes? */
- if ((uint32_t)iBytesWritten == (pxTraceEventBuffer->uiSize - uiTail - uiSlack))
- {
- /* uiTail is moved to start of buffer */
- pxTraceEventBuffer->uiTail = 0u;
- iSumBytesWritten = iBytesWritten;
- /* We zero this here in case it does not get zeroed by the streamport. This isn't really a problem with our
- * streamports, but there has been cases with custom streamport forgetting to set this to 0 if there is no
- * data to write. */
- iBytesWritten = 0;
- /* Try to write: start of buffer -> head */
- (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[0], uiHead, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- }
- }
-
- /* Move tail */
- pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
-
- iSumBytesWritten += iBytesWritten;
- *piBytesWritten = iSumBytesWritten;
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferTransferChunk(TraceEventBuffer_t* pxTraceEventBuffer, uint32_t uiChunkSize, int32_t* piBytesWritten)
- {
- int32_t iBytesWritten = 0;
- uint32_t uiHead;
- uint32_t uiTail;
- uint32_t uiSlack;
- uint32_t uiBytesToWrite;
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
- /* This should never fail */
- TRC_ASSERT(piBytesWritten != (void*)0);
- uiHead = pxTraceEventBuffer->uiHead;
- uiTail = pxTraceEventBuffer->uiTail;
- uiSlack = pxTraceEventBuffer->uiSlack;
- /* Check if core event buffer is empty */
- if (uiHead == uiTail)
- {
- /* Make sure this value is set in case it was passed uninitialized. */
- *piBytesWritten = 0;
- return TRC_SUCCESS;
- }
- /* Check if we can do a direct write or if we have to handle wrapping */
- if (uiHead > uiTail)
- {
- uiBytesToWrite = uiHead - uiTail;
- if (uiBytesToWrite > uiChunkSize)
- {
- uiBytesToWrite = uiChunkSize;
- }
- (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], uiBytesToWrite, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
- }
- else
- {
- uiBytesToWrite = pxTraceEventBuffer->uiSize - uiTail - uiSlack;
- if (uiBytesToWrite > uiChunkSize)
- {
- uiBytesToWrite = uiChunkSize;
- }
- (void)xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], uiBytesToWrite, &iBytesWritten); /*cstat !MISRAC2004-17.4_b We need to access a specific part of the buffer*/
- /* Check if we managed to write until the end or not, if we didn't we
- * add the number of bytes written. If we managed to write the last
- * segment, reset tail to 0. */
- if ((uiTail + (uint32_t)iBytesWritten) == (pxTraceEventBuffer->uiSize - uiSlack))
- {
- pxTraceEventBuffer->uiTail = 0u;
- }
- else
- {
- pxTraceEventBuffer->uiTail += (uint32_t)iBytesWritten;
- }
- }
- *piBytesWritten = iBytesWritten;
- return TRC_SUCCESS;
- }
- traceResult xTraceEventBufferClear(TraceEventBuffer_t* pxTraceEventBuffer)
- {
- /* This should never fail */
- TRC_ASSERT(pxTraceEventBuffer != (void*)0);
- pxTraceEventBuffer->uiHead = 0u;
- pxTraceEventBuffer->uiTail = 0u;
- pxTraceEventBuffer->uiFree = pxTraceEventBuffer->uiSize;
- pxTraceEventBuffer->uiSlack = 0u;
- pxTraceEventBuffer->uiNextHead = 0u;
- return TRC_SUCCESS;
- }
- #endif
|