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)21traceResult 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)42traceResult 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)81traceResult 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)132traceResult 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)152traceResult 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