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.
257 lines
6.9 KiB
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) */
|