1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.8.1
3 * Copyright 2023 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The implementation for the stack monitor.
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 
17 #if (((TRC_CFG_ENABLE_STACK_MONITOR) == 1) && ((TRC_CFG_SCHEDULING_ONLY) == 0))
18 
19 #ifndef TRC_CFG_ALLOW_TASK_DELETE
20 #define TRC_CFG_ALLOW_TASK_DELETE 1
21 #endif
22 
23 static TraceStackMonitorData_t* pxStackMonitor TRC_CFG_RECORDER_DATA_ATTRIBUTE;
24 
xTraceStackMonitorInitialize(TraceStackMonitorData_t * pxBuffer)25 traceResult xTraceStackMonitorInitialize(TraceStackMonitorData_t *pxBuffer)
26 {
27 	uint32_t i;
28 
29 	/* This should never fail */
30 	TRC_ASSERT(pxBuffer != 0);
31 
32 	pxStackMonitor = pxBuffer;
33 
34 	pxStackMonitor->uxEntryCount = 0;
35 
36 	for (i = 0; i < (TRC_CFG_STACK_MONITOR_MAX_TASKS); i++)
37 	{
38 		pxStackMonitor->xEntries[i].pvTask = 0;
39 	}
40 
41 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_STACK_MONITOR);
42 
43 	return TRC_SUCCESS;
44 }
45 
xTraceStackMonitorAdd(void * pvTask)46 traceResult xTraceStackMonitorAdd(void *pvTask)
47 {
48 	TraceUnsignedBaseType_t uxLowMark = 0;
49 
50 	TRACE_ALLOC_CRITICAL_SECTION();
51 
52 	/* This should never fail */
53 	TRC_ASSERT(xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_STACK_MONITOR));
54 
55 	if (pvTask == 0)
56 	{
57 		/* We don't add null addresses */
58 		return TRC_FAIL;
59 	}
60 
61 	TRACE_ENTER_CRITICAL_SECTION();
62 
63 	if (pxStackMonitor->uxEntryCount >= (TRC_CFG_STACK_MONITOR_MAX_TASKS))
64 	{
65 		xTraceDiagnosticsIncrease(TRC_DIAGNOSTICS_STACK_MONITOR_NO_SLOTS);
66 
67 		TRACE_EXIT_CRITICAL_SECTION();
68 
69 		return TRC_FAIL;
70 	}
71 
72 	if (xTraceKernelPortGetUnusedStack(pvTask, &uxLowMark) == TRC_SUCCESS)
73 	{
74 		pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount].pvTask = pvTask;
75 		pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount].uxPreviousLowWaterMark = uxLowMark;
76 
77 		pxStackMonitor->uxEntryCount++;
78 	}
79 
80 	TRACE_EXIT_CRITICAL_SECTION();
81 
82 	return TRC_SUCCESS;
83 }
84 
xTraceStackMonitorRemove(void * pvTask)85 traceResult xTraceStackMonitorRemove(void* pvTask)
86 {
87 	uint32_t i;
88 
89 	TRACE_ALLOC_CRITICAL_SECTION();
90 
91 	/* This should never fail */
92 	TRC_ASSERT(xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_STACK_MONITOR));
93 
94 	if (pvTask == 0)
95 	{
96 		/* We don't add null addresses */
97 		return TRC_FAIL;
98 	}
99 
100 	TRACE_ENTER_CRITICAL_SECTION();
101 
102 	for (i = 0; i < pxStackMonitor->uxEntryCount; i++)
103 	{
104 		if (pxStackMonitor->xEntries[i].pvTask == pvTask)
105 		{
106 			if (pxStackMonitor->uxEntryCount > 1 && i != (pxStackMonitor->uxEntryCount - 1))
107 			{
108 				/* There are more entries and this is NOT the last entry. Move last entry to this slot. */
109 				pxStackMonitor->xEntries[i].pvTask = pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount - 1].pvTask;
110 				pxStackMonitor->xEntries[i].uxPreviousLowWaterMark = pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount - 1].uxPreviousLowWaterMark;
111 
112 				/* Clear old entry that was moved */
113 				pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount - 1].pvTask = 0;
114 				pxStackMonitor->xEntries[pxStackMonitor->uxEntryCount - 1].uxPreviousLowWaterMark = 0;
115 			}
116 			else
117 			{
118 				/* No other entries or last entry. */
119 				pxStackMonitor->xEntries[i].pvTask = 0;
120 				pxStackMonitor->xEntries[i].uxPreviousLowWaterMark = 0;
121 			}
122 
123 			pxStackMonitor->uxEntryCount--;
124 
125 			TRACE_EXIT_CRITICAL_SECTION();
126 
127 			return TRC_SUCCESS;
128 		}
129 	}
130 
131 	TRACE_EXIT_CRITICAL_SECTION();
132 
133 	return TRC_FAIL;
134 }
135 
xTraceStackMonitorGetAtIndex(uint32_t uiIndex,void ** ppvTask,TraceUnsignedBaseType_t * puxLowWaterMark)136 traceResult xTraceStackMonitorGetAtIndex(uint32_t uiIndex, void **ppvTask, TraceUnsignedBaseType_t *puxLowWaterMark)
137 {
138 	/* This should never fail */
139 	TRC_ASSERT(xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_STACK_MONITOR));
140 
141 	/* This should never fail */
142 	TRC_ASSERT(ppvTask != 0);
143 
144 	/* This should never fail */
145 	TRC_ASSERT(puxLowWaterMark != 0);
146 
147 	/* This should never fail */
148 	TRC_ASSERT(uiIndex < (TRC_CFG_STACK_MONITOR_MAX_TASKS));
149 
150 	*ppvTask = pxStackMonitor->xEntries[uiIndex].pvTask;
151 	*puxLowWaterMark = pxStackMonitor->xEntries[uiIndex].uxPreviousLowWaterMark;
152 
153 	return TRC_SUCCESS;
154 }
155 
xTraceStackMonitorReport(void)156 traceResult xTraceStackMonitorReport(void)
157 {
158 	TraceUnsignedBaseType_t uxLowWaterMark = 0;
159 	TraceStackMonitorEntry_t *pxStackMonitorEntry;
160 	TraceUnsignedBaseType_t uxToReport;
161 	TraceUnsignedBaseType_t i;
162 	static uint32_t uiCurrentIndex = 0;
163 
164 #if (TRC_CFG_ALLOW_TASK_DELETE == 1)
165 	TRACE_ALLOC_CRITICAL_SECTION();
166 #endif
167 
168 	/* This should never fail */
169 	TRC_ASSERT(xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_STACK_MONITOR));
170 
171 #if (TRC_CFG_ALLOW_TASK_DELETE == 1)
172 	TRACE_ENTER_CRITICAL_SECTION();
173 #endif
174 
175 	/* Never report more than there are entries */
176 	uxToReport = TRC_CFG_STACK_MONITOR_MAX_REPORTS <= pxStackMonitor->uxEntryCount ? TRC_CFG_STACK_MONITOR_MAX_REPORTS : pxStackMonitor->uxEntryCount;
177 
178 	for (i = 0; i < uxToReport; i++)
179 	{
180 		/* If uiCurrentIndex is too large, reset it */
181 		uiCurrentIndex = uiCurrentIndex < pxStackMonitor->uxEntryCount ? uiCurrentIndex : 0;
182 
183 		pxStackMonitorEntry = &pxStackMonitor->xEntries[uiCurrentIndex];
184 
185 		if (xTraceKernelPortGetUnusedStack(pxStackMonitorEntry->pvTask, &uxLowWaterMark) != TRC_SUCCESS)
186 		{
187 			uiCurrentIndex++;
188 			continue;
189 		}
190 
191 		if (uxLowWaterMark < pxStackMonitorEntry->uxPreviousLowWaterMark)
192 		{
193 			pxStackMonitorEntry->uxPreviousLowWaterMark = uxLowWaterMark;
194 		}
195 
196 		xTraceEventCreate2(PSF_EVENT_UNUSED_STACK, (TraceUnsignedBaseType_t)pxStackMonitorEntry->pvTask, pxStackMonitorEntry->uxPreviousLowWaterMark);
197 
198 		uiCurrentIndex++;
199 	}
200 
201 #if (TRC_CFG_ALLOW_TASK_DELETE == 1)
202 	TRACE_EXIT_CRITICAL_SECTION();
203 #endif
204 
205 	return TRC_SUCCESS;
206 }
207 #endif /* (((TRC_CFG_ENABLE_STACK_MONITOR) == 1) && ((TRC_CFG_SCHEDULING_ONLY) == 0)) */
208 
209 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
210 
211 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
212