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