Added run time stats functions.

pull/4/head
Richard Barry 16 years ago
parent 886be58c58
commit 8b4ef53b69

@ -89,13 +89,17 @@ typedef struct tskTaskControlBlock
#endif #endif
#if ( configUSE_MUTEXES == 1 ) #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 #endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 ) #if ( configUSE_APPLICATION_TASK_TAG == 1 )
pdTASK_HOOK_CODE pxTaskTag; pdTASK_HOOK_CODE pxTaskTag;
#endif #endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
unsigned portLONG ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
#endif
} tskTCB; } tskTCB;
/* /*
@ -144,6 +148,14 @@ static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
static unsigned portBASE_TYPE uxTaskNumber = ( unsigned 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. ------------*/ /* 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 signed portBASE_TYPE xTracing = pdFALSE;
static unsigned portBASE_TYPE uxPreviousTask = 255; static unsigned portBASE_TYPE uxPreviousTask = 255;
static portCHAR pcStatusString[ 50 ]; static portCHAR pcStatusString[ 50 ];
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -303,7 +316,9 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
* allocated by calls to pvPortMalloc from within the tasks application code). * allocated by calls to pvPortMalloc from within the tasks application code).
*/ */
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) ) #if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
static void prvDeleteTCB( tskTCB *pxTCB ); static void prvDeleteTCB( tskTCB *pxTCB );
#endif #endif
/* /*
@ -826,7 +841,7 @@ tskTCB * pxNewTCB;
/* If null is passed in here then we are suspending ourselves. */ /* If null is passed in here then we are suspending ourselves. */
pxTCB = prvGetTCBFromHandle( pxTaskToSuspend ); pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
traceTASK_SUSPEND( pxTaskToSuspend ); traceTASK_SUSPEND( pxTCB );
/* Remove task from the ready/delayed list and place in the suspended list. */ /* Remove task from the ready/delayed list and place in the suspended list. */
vListRemove( &( pxTCB->xGenericListItem ) ); vListRemove( &( pxTCB->xGenericListItem ) );
@ -987,6 +1002,11 @@ portBASE_TYPE xReturn;
xSchedulerRunning = pdTRUE; xSchedulerRunning = pdTRUE;
xTickCount = ( portTickType ) 0; 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 /* Setting up the timer tick is hardware specific and thus in the
portable interface. */ portable interface. */
if( xPortStartScheduler() ) 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 ) void vTaskList( signed portCHAR *pcWriteBuffer )
{ {
@ -1165,16 +1185,89 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR ); prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
} }
#if( INCLUDE_vTaskDelete == 1 )
{
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) ) if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
{ {
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR ); prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
} }
}
#endif
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) ) if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
{ {
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR ); 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(); xTaskResumeAll();
} }
@ -1394,6 +1487,21 @@ void vTaskSwitchContext( void )
{ {
traceTASK_SWITCHED_OUT(); 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 ) if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
{ {
/* The scheduler is currently suspended - do not allow a context /* 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; pxTCB->pxTaskTag = NULL;
} }
#endif #endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
pxTCB->ulRunTimeCounter = 0UL;
}
#endif
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -1833,6 +1947,38 @@ tskTCB *pxNewTCB;
#endif #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 ) ) #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ) unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte )

Loading…
Cancel
Save