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)25traceResult 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)46traceResult 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)85traceResult 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)136traceResult 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)156traceResult 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