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