1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.6.6
3 * Copyright 2021 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 != 0);
22 
23 	/* This should never fail */
24 	TRC_ASSERT(puiBuffer != 0);
25 
26 	pxTraceEventBuffer->uiOptions = uiOptions;
27 	pxTraceEventBuffer->uiHead = 0;
28 	pxTraceEventBuffer->uiTail = 0;
29 	pxTraceEventBuffer->uiSize = uiSize;
30 	pxTraceEventBuffer->uiFree = uiSize;
31 	pxTraceEventBuffer->puiBuffer = puiBuffer;
32 	pxTraceEventBuffer->uiTimerWraparounds = 0;
33 
34 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_EVENT_BUFFER);
35 
36 	return TRC_SUCCESS;
37 }
38 
39 /**
40  * @brief Pops the oldest event from the Event Buffer.
41  *
42  * @param[in] pxTraceEventBuffer Pointer to initialized trace event buffer.
43  *
44  * @retval TRC_FAIL Failure
45  * @retval TRC_SUCCESS Success
46  */
prvTraceEventBufferPop(TraceEventBuffer_t * pxTraceEventBuffer)47 static traceResult prvTraceEventBufferPop(TraceEventBuffer_t *pxTraceEventBuffer)
48 {
49 	uint32_t uiFreeSize = 0;
50 
51 	/* Get size of event we are freeing */
52 	/* This should never fail */
53 	TRC_ASSERT_ALWAYS_EVALUATE(xTraceEventGetSize(((void*)&(pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiTail])), &uiFreeSize) == TRC_SUCCESS);
54 
55 	pxTraceEventBuffer->uiFree += uiFreeSize;
56 
57 	/* Update tail to point to the new last event */
58 	pxTraceEventBuffer->uiTail = (pxTraceEventBuffer->uiTail + uiFreeSize) % pxTraceEventBuffer->uiSize;
59 
60 	return TRC_SUCCESS;
61 }
62 
xTraceEventBufferPush(TraceEventBuffer_t * pxTraceEventBuffer,void * pxData,uint32_t uiDataSize,int32_t * piBytesWritten)63 traceResult xTraceEventBufferPush(TraceEventBuffer_t *pxTraceEventBuffer, void *pxData, uint32_t uiDataSize, int32_t *piBytesWritten)
64 {
65 	uint32_t uiBufferSize;
66 
67 	/* This should never fail */
68 	TRC_ASSERT(pxTraceEventBuffer != 0);
69 
70 	/* This should never fail */
71 	TRC_ASSERT(pxData != 0);
72 
73 	uiBufferSize = pxTraceEventBuffer->uiSize;
74 
75 	/* Check if the data size is larger than the buffer */
76 	/* This should never fail */
77 	TRC_ASSERT(uiDataSize <= uiBufferSize);
78 
79 	/* Check byte alignment */
80 	/* This should never fail */
81 	TRC_ASSERT((uiDataSize % 4) == 0);
82 
83 	/* Ensure bytes written start at 0 */
84 	/* This should never fail */
85 	TRC_ASSERT(piBytesWritten != 0);
86 
87 	*piBytesWritten = 0;
88 
89 	/* This should never fail */
90 	TRC_ASSERT_ALWAYS_EVALUATE(xTraceTimestampGetWraparounds(&pxTraceEventBuffer->uiTimerWraparounds) == TRC_SUCCESS);
91 
92 	/* In ring buffer mode we cannot provide lock free access since the producer modified
93 	 * the head and tail variables in the same call. This option is only safe when used
94 	 * with an internal buffer (streaming snapshot) which no consumer accesses.
95 	 */
96 	switch (pxTraceEventBuffer->uiOptions)
97 	{
98 		case TRC_EVENT_BUFFER_OPTION_OVERWRITE:
99 		{
100 			uint32_t uiHead = pxTraceEventBuffer->uiHead;
101 
102 			/* If there isn't enough space in the buffer pop events until there is */
103 			while (pxTraceEventBuffer->uiFree < uiDataSize)
104 			{
105 				prvTraceEventBufferPop(pxTraceEventBuffer);
106 			}
107 
108 			/* Copy data */
109 			if ((uiBufferSize - uiHead) > uiDataSize)
110 			{
111 				TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiDataSize);
112 			}
113 			else
114 			{
115 				TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiBufferSize - uiHead);
116 				TRC_MEMCPY(pxTraceEventBuffer->puiBuffer,
117 							(void*)(&((uint8_t*)pxData)[(uiBufferSize - uiHead)]),
118 							uiDataSize - (uiBufferSize - uiHead));
119 			}
120 
121 			pxTraceEventBuffer->uiFree -= uiDataSize;
122 
123 			pxTraceEventBuffer->uiHead = (uiHead + uiDataSize) % uiBufferSize;
124 
125 			*piBytesWritten = uiDataSize;
126 
127 			break;
128 		}
129 
130 		case TRC_EVENT_BUFFER_OPTION_SKIP:
131 		{
132 			/* Since a consumer could potentially update tail (free) during the procedure
133 			 * we have to save it here to avoid problems with the push algorithm.
134 			 */
135 			uint32_t uiHead = pxTraceEventBuffer->uiHead;
136 			uint32_t uiTail = pxTraceEventBuffer->uiTail;
137 
138 			if (uiHead >= uiTail)
139 			{
140 				uint32_t uiFreeSpace = (uiBufferSize - uiHead - sizeof(uint32_t)) + uiTail;
141 
142 				if (uiFreeSpace < uiDataSize)
143 				{
144 					*piBytesWritten = 0;
145 
146 					return TRC_SUCCESS;
147 				}
148 
149 				/* Copy data */
150 				if ((uiBufferSize - uiHead) > uiDataSize)
151 				{
152 					TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pxData, uiDataSize);
153 				}
154 				else
155 				{
156 					TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[uiHead], pxData, uiBufferSize - uiHead);
157 					TRC_MEMCPY(pxTraceEventBuffer->puiBuffer,
158 								(void*)(&((uint8_t*)pxData)[(uiBufferSize - uiHead)]),
159 								uiDataSize - (uiBufferSize - uiHead));
160 				}
161 
162 				pxTraceEventBuffer->uiHead = (uiHead + uiDataSize) % uiBufferSize;
163 			}
164 			else
165 			{
166 				uint32_t uiFreeSpace = uiTail - uiHead - sizeof(uint32_t);
167 
168 				if (uiFreeSpace < uiDataSize)
169 				{
170 					*piBytesWritten = 0;
171 
172 					return TRC_SUCCESS;
173 				}
174 
175 				/* Copy data */
176 				TRC_MEMCPY(&pxTraceEventBuffer->puiBuffer[pxTraceEventBuffer->uiHead], pxData, uiDataSize);
177 
178 				pxTraceEventBuffer->uiHead = (uiHead + uiDataSize);
179 			}
180 
181 			*piBytesWritten = uiDataSize;
182 
183 			break;
184 		}
185 
186 		default:
187 		{
188 			return TRC_FAIL;
189 		}
190 	}
191 
192 	return TRC_SUCCESS;
193 }
194 
xTraceEventBufferTransfer(TraceEventBuffer_t * pxTraceEventBuffer,int32_t * piBytesWritten)195 traceResult xTraceEventBufferTransfer(TraceEventBuffer_t* pxTraceEventBuffer, int32_t* piBytesWritten)
196 {
197 	int32_t iBytesWritten = 0;
198 	int32_t iSumBytesWritten = 0;
199 	uint32_t uiHead;
200 	uint32_t uiTail;
201 
202 	/* This should never fail */
203 	TRC_ASSERT(pxTraceEventBuffer != 0);
204 
205 	/* This should never fail */
206 	TRC_ASSERT(piBytesWritten != 0);
207 
208 	uiHead = pxTraceEventBuffer->uiHead;
209 	uiTail = pxTraceEventBuffer->uiTail;
210 
211 	/* Check if core event buffer is empty */
212 	if (uiHead == uiTail)
213 	{
214 		return TRC_SUCCESS;
215 	}
216 
217 	/* Check if we can do a direct write or if we have to handle wrapping */
218 	if (uiHead > uiTail)
219 	{
220 		/* No wrapping */
221 		xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (uiHead - uiTail), &iBytesWritten);
222 	}
223 	else
224 	{
225 		/* Wrapping */
226 		xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (pxTraceEventBuffer->uiSize - uiTail), &iBytesWritten);
227 
228 		if (iBytesWritten == (int32_t)(pxTraceEventBuffer->uiSize - uiTail))
229 		{
230 			/* Everything written, do the rest as well */
231 
232 			/* uiTail is moved to start of buffer */
233 			pxTraceEventBuffer->uiTail = 0;
234 
235 			iSumBytesWritten += iBytesWritten;
236 
237 			iBytesWritten = 0;
238 
239 			xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[0], uiHead, &iBytesWritten);
240 		}
241 	}
242 
243 	/* Move tail */
244 	pxTraceEventBuffer->uiTail += iBytesWritten;
245 
246 	iSumBytesWritten += iBytesWritten;
247 
248 	*piBytesWritten = iSumBytesWritten;
249 
250 	return TRC_SUCCESS;
251 }
252 
xTraceEventBufferClear(TraceEventBuffer_t * pxTraceEventBuffer)253 traceResult xTraceEventBufferClear(TraceEventBuffer_t* pxTraceEventBuffer)
254 {
255 	/* This should never fail */
256 	TRC_ASSERT(pxTraceEventBuffer != 0);
257 
258 	pxTraceEventBuffer->uiHead = 0;
259 	pxTraceEventBuffer->uiTail = 0;
260 	pxTraceEventBuffer->uiFree = pxTraceEventBuffer->uiSize;
261 
262 	return TRC_SUCCESS;
263 }
264 
265 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
266 
267 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
268