From: RichardBarry Date: Tue, 19 May 2009 10:38:26 +0000 (+0000) Subject: Added run time stats functions. X-Git-Tag: V5.3.0~41 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=10a29b47974645c681790fc12728604c04d3d17a;p=freertos Added run time stats functions. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@725 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/Source/tasks.c b/Source/tasks.c index d84e2f70e..62b0a3070 100644 --- a/Source/tasks.c +++ b/Source/tasks.c @@ -3,20 +3,20 @@ This file is part of the FreeRTOS.org distribution. - FreeRTOS.org is free software; you can redistribute it and/or modify it + FreeRTOS.org is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation and modified by the FreeRTOS exception. FreeRTOS.org is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 + You should have received a copy of the GNU General Public License along + with FreeRTOS.org; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - A special exception to the GPL is included to allow you to distribute a + A special exception to the GPL is included to allow you to distribute a combined work that includes FreeRTOS.org without being obliged to provide the source code for any proprietary components. See the licensing section of http://www.FreeRTOS.org for full details. @@ -85,16 +85,20 @@ typedef struct tskTaskControlBlock #endif #if ( configUSE_TRACE_FACILITY == 1 ) - unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */ + unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */ #endif #if ( configUSE_MUTEXES == 1 ) - unsigned portBASE_TYPE uxBasePriority; + unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ #endif #if ( configUSE_APPLICATION_TASK_TAG == 1 ) pdTASK_HOOK_CODE pxTaskTag; #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + unsigned portLONG ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */ + #endif } tskTCB; @@ -144,6 +148,14 @@ static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE; static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0; +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + static portCHAR pcStatsString[ 50 ]; + static unsigned portLONG ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ + static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime ); + +#endif + /* Debugging and trace facilities private variables and macros. ------------*/ /* @@ -172,6 +184,7 @@ static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0; static signed portBASE_TYPE xTracing = pdFALSE; static unsigned portBASE_TYPE uxPreviousTask = 255; static portCHAR pcStatusString[ 50 ]; + #endif /*-----------------------------------------------------------*/ @@ -303,7 +316,9 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); * allocated by calls to pvPortMalloc from within the tasks application code). */ #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) ) + static void prvDeleteTCB( tskTCB *pxTCB ); + #endif /* @@ -826,7 +841,7 @@ tskTCB * pxNewTCB; /* If null is passed in here then we are suspending ourselves. */ pxTCB = prvGetTCBFromHandle( pxTaskToSuspend ); - traceTASK_SUSPEND( pxTaskToSuspend ); + traceTASK_SUSPEND( pxTCB ); /* Remove task from the ready/delayed list and place in the suspended list. */ vListRemove( &( pxTCB->xGenericListItem ) ); @@ -987,6 +1002,11 @@ portBASE_TYPE xReturn; xSchedulerRunning = pdTRUE; xTickCount = ( portTickType ) 0; + /* If configGENERATE_RUN_TIME_STATS is defined then the following + macro must be defined to configure the timer/counter used to generate + the run time counter time base. */ + portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); + /* Setting up the timer tick is hardware specific and thus in the portable interface. */ if( xPortStartScheduler() ) @@ -1126,7 +1146,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) } /*-----------------------------------------------------------*/ -#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) +#if ( configUSE_TRACE_FACILITY == 1 ) void vTaskList( signed portCHAR *pcWriteBuffer ) { @@ -1165,15 +1185,88 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR ); } - if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) + #if( INCLUDE_vTaskDelete == 1 ) { - prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR ); + if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) + { + prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR ); + } } + #endif - if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + #if ( INCLUDE_vTaskSuspend == 1 ) { - prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR ); + if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + { + prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR ); + } } + #endif + } + xTaskResumeAll(); + } + +#endif +/*----------------------------------------------------------*/ + +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + void vTaskGetRunTimeStats( signed portCHAR *pcWriteBuffer ) + { + unsigned portBASE_TYPE uxQueue; + unsigned portLONG ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE(); + + /* This is a VERY costly function that should be used for debug only. + It leaves interrupts disabled for a LONG time. */ + + vTaskSuspendAll(); + { + /* Run through all the lists that could potentially contain a TCB, + generating a table of run timer percentages in the provided + buffer. */ + + pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00; + strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" ); + + uxQueue = uxTopUsedPriority + 1; + + do + { + uxQueue--; + + if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) ) + { + prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), ulTotalRunTime ); + } + }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY ); + + if( !listLIST_IS_EMPTY( pxDelayedTaskList ) ) + { + prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, ulTotalRunTime ); + } + + if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) ) + { + prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, ulTotalRunTime ); + } + + #if ( INCLUDE_vTaskDelete == 1 ) + { + if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) + { + prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, ulTotalRunTime ); + } + } + #endif + + #if ( INCLUDE_vTaskSuspend == 1 ) + { + if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) + { + prvGenerateRunTimeStatsForTasksInList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, ulTotalRunTime ); + } + } + #endif } xTaskResumeAll(); } @@ -1394,6 +1487,21 @@ void vTaskSwitchContext( void ) { traceTASK_SWITCHED_OUT(); + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + unsigned portLONG ulTempCounter = portGET_RUN_TIME_COUNTER_VALUE(); + + /* Add the amount of time the task has been running to the accumulated + time so far. The time the task started running was stored in + ulTaskSwitchedInTime. Note that there is no overflow protection here + so count values are only valid until the timer overflows. Generally + this will be about 1 hour assuming a 1uS timer increment. */ + pxCurrentTCB->ulRunTimeCounter += ( ulTempCounter - ulTaskSwitchedInTime ); + ulTaskSwitchedInTime = ulTempCounter; + } + #endif + + if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE ) { /* The scheduler is currently suspended - do not allow a context @@ -1709,6 +1817,12 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * co pxTCB->pxTaskTag = NULL; } #endif + + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + { + pxTCB->ulRunTimeCounter = 0UL; + } + #endif } /*-----------------------------------------------------------*/ @@ -1833,6 +1947,38 @@ tskTCB *pxNewTCB; #endif /*-----------------------------------------------------------*/ +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + + static void prvGenerateRunTimeStatsForTasksInList( const signed portCHAR *pcWriteBuffer, xList *pxList, unsigned portLONG ulTotalRunTime ) + { + volatile tskTCB *pxNextTCB, *pxFirstTCB; + unsigned portLONG ulStatsAsPercentage; + + /* Write the run time stats of all the TCB's in pxList into the buffer. */ + listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); + do + { + listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList ); + + ulStatsAsPercentage = ( 100UL * pxNextTCB->ulRunTimeCounter ) / ulTotalRunTime; + + if( ulStatsAsPercentage > 0UL ) + { + sprintf( pcStatsString, ( portCHAR * ) "%s\t\t\t%lu\t\t\t%lu%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter, ulStatsAsPercentage ); + } + else + { + sprintf( pcStatsString, ( portCHAR * ) "%s\t\t\t%lu\t\t\t< 1%%\r\n", pxNextTCB->pcTaskName, pxNextTCB->ulRunTimeCounter ); + } + + strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatsString ); + + } while( pxNextTCB != pxFirstTCB ); + } + +#endif +/*-----------------------------------------------------------*/ + #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )