/* * Percepio Trace Recorder for Tracealyzer v4.6.0 * Copyright 2021 Percepio AB * www.percepio.com * * SPDX-License-Identifier: Apache-2.0 * * The implementation for the stack monitor. */ #include #if ( TRC_USE_TRACEALYZER_RECORDER == 1 ) #if ( TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING ) #if ( ( ( TRC_CFG_ENABLE_STACK_MONITOR ) == 1 ) && ( ( TRC_CFG_SCHEDULING_ONLY ) == 0 ) ) typedef struct TraceStackMonitorEntry { void * pvTask; TraceUnsignedBaseType_t uxPreviousLowWaterMark; } TraceStackMonitorEntry_t; typedef struct TraceStackMonitor { TraceStackMonitorEntry_t xEntries[ TRC_CFG_STACK_MONITOR_MAX_TASKS ]; uint32_t uiEntryCount; } TraceStackMonitor_t; static TraceStackMonitor_t * pxStackMonitor; traceResult xTraceStackMonitorInitialize( TraceStackMonitorBuffer_t * pxBuffer ) { uint32_t i; TRC_ASSERT_EQUAL_SIZE( TraceStackMonitorBuffer_t, TraceStackMonitor_t ); /* This should never fail */ TRC_ASSERT( pxBuffer != 0 ); pxStackMonitor = ( TraceStackMonitor_t * ) pxBuffer; pxStackMonitor->uiEntryCount = 0; for( i = 0; i < ( TRC_CFG_STACK_MONITOR_MAX_TASKS ); i++ ) { pxStackMonitor->xEntries[ i ].pvTask = 0; } xTraceSetComponentInitialized( TRC_RECORDER_COMPONENT_STACK_MONITOR ); return TRC_SUCCESS; } traceResult xTraceStackMonitorAdd( void * pvTask ) { TraceUnsignedBaseType_t uxLowMark; TRACE_ALLOC_CRITICAL_SECTION(); /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_STACK_MONITOR ) ); if( pvTask == 0 ) { /* We don't add null addresses */ return TRC_FAIL; } TRACE_ENTER_CRITICAL_SECTION(); if( pxStackMonitor->uiEntryCount >= ( TRC_CFG_STACK_MONITOR_MAX_TASKS ) ) { xTraceDiagnosticsIncrease( TRC_DIAGNOSTICS_STACK_MONITOR_NO_SLOTS ); TRACE_EXIT_CRITICAL_SECTION(); return TRC_FAIL; } if( xTraceKernelPortGetUnusedStack( pvTask, &uxLowMark ) == TRC_SUCCESS ) { pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount ].pvTask = pvTask; pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount ].uxPreviousLowWaterMark = uxLowMark; pxStackMonitor->uiEntryCount++; } TRACE_EXIT_CRITICAL_SECTION(); return TRC_SUCCESS; } traceResult xTraceStackMonitorRemove( void * pvTask ) { uint32_t i; TRACE_ALLOC_CRITICAL_SECTION(); /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_STACK_MONITOR ) ); if( pvTask == 0 ) { /* We don't add null addresses */ return TRC_FAIL; } TRACE_ENTER_CRITICAL_SECTION(); for( i = 0; i < pxStackMonitor->uiEntryCount; i++ ) { if( pxStackMonitor->xEntries[ i ].pvTask == pvTask ) { if( ( pxStackMonitor->uiEntryCount > 1 ) && ( i != ( pxStackMonitor->uiEntryCount - 1 ) ) ) { /* There are more entries and this is NOT the last entry. Move last entry to this slot. */ pxStackMonitor->xEntries[ i ].pvTask = pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount - 1 ].pvTask; pxStackMonitor->xEntries[ i ].uxPreviousLowWaterMark = pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount - 1 ].uxPreviousLowWaterMark; /* Clear old entry that was moved */ pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount - 1 ].pvTask = 0; pxStackMonitor->xEntries[ pxStackMonitor->uiEntryCount - 1 ].uxPreviousLowWaterMark = 0; } else { /* No other entries or last entry. */ pxStackMonitor->xEntries[ i ].pvTask = 0; pxStackMonitor->xEntries[ i ].uxPreviousLowWaterMark = 0; } pxStackMonitor->uiEntryCount--; TRACE_EXIT_CRITICAL_SECTION(); return TRC_SUCCESS; } } TRACE_EXIT_CRITICAL_SECTION(); return TRC_FAIL; } traceResult xTraceStackMonitorGetAtIndex( uint32_t uiIndex, void ** ppvTask, TraceUnsignedBaseType_t * puxLowWaterMark ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_STACK_MONITOR ) ); /* This should never fail */ TRC_ASSERT( ppvTask != 0 ); /* This should never fail */ TRC_ASSERT( puxLowWaterMark != 0 ); /* This should never fail */ TRC_ASSERT( uiIndex < ( TRC_CFG_STACK_MONITOR_MAX_TASKS ) ); *ppvTask = pxStackMonitor->xEntries[ uiIndex ].pvTask; *puxLowWaterMark = pxStackMonitor->xEntries[ uiIndex ].uxPreviousLowWaterMark; return TRC_SUCCESS; } traceResult xTraceStackMonitorReport( void ) { TraceUnsignedBaseType_t uxLowWaterMark; TraceEventHandle_t xEventHandle = 0; TraceStackMonitorEntry_t * pxStackMonitorEntry; uint32_t uiToReport; uint32_t i; static uint32_t uiCurrentIndex = 0; TRACE_ALLOC_CRITICAL_SECTION(); /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_STACK_MONITOR ) ); TRACE_ENTER_CRITICAL_SECTION(); /* Never report more than there are entries */ uiToReport = TRC_CFG_STACK_MONITOR_MAX_REPORTS <= pxStackMonitor->uiEntryCount ? TRC_CFG_STACK_MONITOR_MAX_REPORTS : pxStackMonitor->uiEntryCount; for( i = 0; i < uiToReport; i++ ) { /* If uiCurrentIndex is too large, reset it */ uiCurrentIndex = uiCurrentIndex < pxStackMonitor->uiEntryCount ? uiCurrentIndex : 0; pxStackMonitorEntry = &pxStackMonitor->xEntries[ uiCurrentIndex ]; xTraceKernelPortGetUnusedStack( pxStackMonitorEntry->pvTask, &uxLowWaterMark ); if( uxLowWaterMark < pxStackMonitorEntry->uxPreviousLowWaterMark ) { pxStackMonitorEntry->uxPreviousLowWaterMark = uxLowWaterMark; } if( xTraceEventBegin( PSF_EVENT_UNUSED_STACK, sizeof( void * ) + sizeof( uint32_t ), &xEventHandle ) == TRC_SUCCESS ) { xTraceEventAddPointer( xEventHandle, pxStackMonitorEntry->pvTask ); xTraceEventAdd32( xEventHandle, ( uint32_t ) pxStackMonitorEntry->uxPreviousLowWaterMark ); xTraceEventEnd( xEventHandle ); } uiCurrentIndex++; } TRACE_EXIT_CRITICAL_SECTION(); return TRC_SUCCESS; } #endif /* (((TRC_CFG_ENABLE_STACK_MONITOR) == 1) && ((TRC_CFG_SCHEDULING_ONLY) == 0)) */ #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */ #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */