You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FreeRTOS/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcEventBuffer.c

257 lines
6.9 KiB
C

/*
* Percepio Trace Recorder for Tracealyzer v4.6.0
* Copyright 2021 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)
#if (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 != 0);
/* This should never fail */
TRC_ASSERT(puiBuffer != 0);
pxTraceEventBuffer->uiOptions = uiOptions;
pxTraceEventBuffer->uiHead = 0;
pxTraceEventBuffer->uiTail = 0;
pxTraceEventBuffer->uiSize = uiSize;
pxTraceEventBuffer->uiFree = uiSize;
pxTraceEventBuffer->puiBuffer = puiBuffer;
pxTraceEventBuffer->uiTimerWraparounds = 0;
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 = 0;
/* Get size of event we are freeing */
/* This should never fail */
TRC_ASSERT_ALWAYS_EVALUATE(xTraceEventGetSize(((void*)&(pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiTail])), &uiFreeSize) == TRC_SUCCESS);
pxTraceEventBuffer->uiFree += uiFreeSize;
/* Update tail to point to the new last event */
pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
return TRC_SUCCESS;
}
traceResult xTraceEventBufferPush(TraceEventBuffer_t *pxTraceEventBuffer, void *pxData, uint32_t uiDataSize, int32_t *piBytesWritten)
{
uint32_t uiBufferSize;
/* This should never fail */
TRC_ASSERT(pxTraceEventBuffer != 0);
/* This should never fail */
TRC_ASSERT(pxData != 0);
uiBufferSize = pxTraceEventBuffer->uiSize;
/* Check if the data size is larger than the buffer */
/* This should never fail */
TRC_ASSERT(uiDataSize <= uiBufferSize);
/* Check byte alignment */
/* This should never fail */
TRC_ASSERT((uiDataSize % 4) == 0);
/* Ensure bytes written start at 0 */
/* This should never fail */
TRC_ASSERT(piBytesWritten != 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:
{
uint32_t uiHead = pxTraceEventBuffer->uiHead;
/* If there isn't enough space in the buffer pop events until there is */
while (pxTraceEventBuffer->uiFree < uiDataSize)
{
prvTraceEventBufferPop(pxTraceEventBuffer);
}
/* Copy data */
if ((uiBufferSize - uiHead) > uiDataSize)
{
TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiDataSize);
}
else
{
TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiBufferSize - uiHead);
TRC_MEMCPY(pxTraceEventBuffer->puiBuffer,
(void*)(&((uint8_t*)pxData)[(uiBufferSize - uiHead)]),
uiDataSize - (uiBufferSize - uiHead));
}
pxTraceEventBuffer->uiFree -= uiDataSize;
pxTraceEventBuffer->uiHead = (uiHead + uiDataSize) % uiBufferSize;
*piBytesWritten = uiDataSize;
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.
*/
uint32_t uiHead = pxTraceEventBuffer->uiHead;
uint32_t uiTail = pxTraceEventBuffer->uiTail;
if (uiHead >= uiTail)
{
uint32_t uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
if (uiFreeSpace < uiDataSize)
{
*piBytesWritten = 0;
return TRC_SUCCESS;
}
/* Copy data */
if ((uiBufferSize - uiHead) > uiDataSize)
{
TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pxData, uiDataSize);
}
else
{
TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiBufferSize - uiHead);
TRC_MEMCPY(pxTraceEventBuffer->puiBuffer,
(void*)(&((uint8_t*)pxData)[(uiBufferSize - uiHead)]),
uiDataSize - (uiBufferSize - uiHead));
}
pxTraceEventBuffer->uiHead = (uiHead + uiDataSize) % uiBufferSize;
}
else
{
uint32_t uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
if (uiFreeSpace < uiDataSize)
{
*piBytesWritten = 0;
return TRC_SUCCESS;
}
/* Copy data */
TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pxData, uiDataSize);
pxTraceEventBuffer->uiHead = (uiHead + uiDataSize);
}
*piBytesWritten = uiDataSize;
break;
}
default:
{
return TRC_FAIL;
}
}
return TRC_SUCCESS;
}
traceResult xTraceEventBufferTransfer(TraceEventBuffer_t* pxTraceEventBuffer, int32_t* piBytesWritten)
{
int32_t iBytesWritten = 0;
int32_t iSumBytesWritten = 0;
uint32_t uiHead;
uint32_t uiTail;
/* This should never fail */
TRC_ASSERT(pxTraceEventBuffer != 0);
/* This should never fail */
TRC_ASSERT(piBytesWritten != 0);
uiHead = pxTraceEventBuffer->uiHead;
uiTail = pxTraceEventBuffer->uiTail;
/* Check if core event buffer is empty */
if (uiHead == uiTail)
{
return TRC_SUCCESS;
}
/* Check if we can do a direct write or if we have to handle wrapping */
if (uiHead > uiTail)
{
xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (uiHead - uiTail), &iBytesWritten);
pxTraceEventBuffer->uiTail = uiHead;
}
else
{
xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (pxTraceEventBuffer->uiSize - uiTail), &iBytesWritten);
iSumBytesWritten += iBytesWritten;
xTraceStreamPortWriteData(pxTraceEventBuffer->puiBuffer, uiHead, &iBytesWritten);
pxTraceEventBuffer->uiTail = uiHead;
}
iSumBytesWritten += iBytesWritten;
*piBytesWritten = iSumBytesWritten;
return TRC_SUCCESS;
}
traceResult xTraceEventBufferClear(TraceEventBuffer_t* pxTraceEventBuffer)
{
/* This should never fail */
TRC_ASSERT(pxTraceEventBuffer != 0);
pxTraceEventBuffer->uiHead = 0;
pxTraceEventBuffer->uiTail = 0;
pxTraceEventBuffer->uiFree = pxTraceEventBuffer->uiSize;
return TRC_SUCCESS;
}
#endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
#endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */