simon-w wrote on Tuesday, July 02, 2019:
I’m also interested to have this included in the standard package.
In the mean time I have an alternative approch - based on Richard Damon’s suggestion. This is an additional function ‘vTaskGetCombinedRunTimeStats()’ - below - in ‘freertos_tacks_c_additions.h’ that combines the output of ‘vTaskGetRunTimeStats()’ and ‘vTaskList()’ with the option to clear the counters on every call.
The size of ‘pcWriteBuffer’ passed in needs to increase from 40 to 60 bytes per task.
It basically works, but there are 2 issues. 1) when counters are not cleared, the total percentage adds up to 110-111% - not sure why. 2) when counters are cleared, the bulk of the execution time is recorded aganist the task calling this function instead of IDLE task (using hardware output this function takes 1% of CPU time - which is what is displayed when the counters are not cleared). Can anyone explain this?
The ESC[ codes to format the output need more work. I was trying to use cursor save and restore - maybe not supported properly by my terminal application.
void vTaskGetCombinedRunTimeStats( char* pcWriteBuffer, UBaseType_t uxClear)
{
TaskStatus_t *pxTaskStatusArray;
UBaseType_t uxArraySize, x;
uint32_t ulTotalTime, ulStatsAsPercentage;
char cStatus;
pcWriteBuffer += sprintf( pcWriteBuffer, “\x1b[1;1HTsk# TaskName\t State\tPrio\t HWM CPUtime(us) CPUload\r\n”);
// Snapshot number of tasks
// Allocate memory for the binary task data structure
uxArraySize = uxTaskGetNumberOfTasks();
pxTaskStatusArray = pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
if( pxTaskStatusArray != NULL )
{
/* Generate the (binary) data - returns the number of tasks */
uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalTime);
/* For percentage calculations. */
ulTotalTime /= 100UL;
/* Create a human readable table from the binary data. */
for( x = 0; x < uxArraySize; x++ )
{
pcWriteBuffer += sprintf( pcWriteBuffer, "%3u ", pxTaskStatusArray[ x ].xTaskNumber );
sprintf(pcWriteBuffer, "%s ", pxTaskStatusArray[ x ].pcTaskName);
pcWriteBuffer += 14; // Assumes task name is less than 12 characters and more than 2
switch(pxTaskStatusArray[ x ].eCurrentState )
{
case eRunning:
cStatus = 'X';
break;
case eReady:
cStatus = 'R';
break;
case eBlocked:
cStatus = 'B';
break;
case eSuspended:
cStatus = 'S';
break;
case eDeleted:
cStatus = 'D';
break;
default: /* Should not get here, but it is included to prevent static checking errors. */
cStatus = 'I';
break;
}
pcWriteBuffer += sprintf( pcWriteBuffer, " %c %2i %6i", cStatus, pxTaskStatusArray[ x ].uxCurrentPriority, pxTaskStatusArray[ x ].usStackHighWaterMark);
if(ulTotalTime > 0UL)
{
ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
if( ulStatsAsPercentage > 0UL )
{
pcWriteBuffer += sprintf( pcWriteBuffer, "%13u %3u%%", pxTaskStatusArray[ x ].ulRunTimeCounter, ulStatsAsPercentage );
}
else
{
pcWriteBuffer += sprintf( pcWriteBuffer, "%13u <1%%", pxTaskStatusArray[ x ].ulRunTimeCounter );
}
if(uxClear)
{
pxTaskStatusArray[ x ].xHandle->ulRunTimeCounter = 0;
}
}
pcWriteBuffer += sprintf(pcWriteBuffer, "\r\n\x1b[0K");
}
if(uxClear)
{
ulTaskSwitchedInTime = 0;
ulTotalRunTime = 0;
}
vPortFree( pxTaskStatusArray );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}