How to deal with overflow in uxTaskGetSystemState?

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

How to deal with overflow in uxTaskGetSystemState?

Postby vonnieda » Wed Aug 22, 2018 6:20 pm

Hi all,

I use uxTaskGetSystemState to calculate a "cpu load" percentage which I need to report in my application. I use code very similar to the example in https://www.freertos.org/uxTaskGetSystemState.html. My question is: How do I know / handle when pulTotalRunTime overflows? This value is a uint32, and if my math is right, it will overflow every 71 minutes. When it does, my stats get all confused because the value is now counting from 0 again while the task run times may or may not have overflowed.

So, is there a good way to handle this? Or is there any way to reset the counters?

Thanks,
Jason

ESP_Dazz
Posts: 308
Joined: Fri Jun 02, 2017 6:50 am

Re: How to deal with overflow in uxTaskGetSystemState?

Postby ESP_Dazz » Tue Aug 28, 2018 12:29 pm

This isn't exactly a solution to the overflow issue, but the following workaround function might be useful for your purposes. It essentially measures FreeRTOS Task CPU usage over a given period instead of over the total run time.

This goes in task.h

Code: Select all

/**
 * Get the real time CPU usage statistics as a string
 *
 * This tasks measures the CPU usage of each task as a percentage over a given time.
 * This function will block over the measurement duration, and CPU usage will be shown
 * as a percentage of the overall measurement duration.
 *
 * @param pcWriteBuffer A buffer into which the execution times will be
 * written, in ASCII form.  This buffer is assumed to be large enough to
 * contain the generated report.  Approximately 40 bytes per task should
 * be sufficient.
 *
 * @param xTicksToWait The number of ticks the CPU consumption should be measured over.
 * This function will during the measurement, therefore the duration of measurement
 * may be extended if a higher priority tasks prevents the calling task from unblocking.
 *
 * @note The stats of any tasks that are created or deleted whilst this function is
 * blocked will not be shown.
 *
 * \ingroup TaskUtils
 */
BaseType_t vTaskGetRealTimeStats( char *pcWriteBuffer, TickType_t xTicksToWait );

This goes in task.c

Code: Select all

	BaseType_t vTaskGetRealTimeStats( char *pcWriteBuffer, TickType_t xTicksToWait )
	{
		#if( configUSE_TRACE_FACILITY != 1 )
		{
			#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
		}
		#endif

		TaskStatus_t *pxTaskStatusArrayStart = NULL, *pxTaskStatusArrayEnd = NULL;
		UBaseType_t uxArraySizeStart, uxArraySizeEnd;
		uint32_t ulTimeStart, ulTimeEnd, ulStatsAsPercentage;

		// Make sure the write buffer does not contain a string.
		*pcWriteBuffer = 0x00;

		//Allocate array to store the statuses of current tasks
		uxArraySizeStart = uxCurrentNumberOfTasks;
		pxTaskStatusArrayStart = pvPortMalloc( uxArraySizeStart * sizeof( TaskStatus_t ) );
		if(pxTaskStatusArrayStart == NULL) {
			//Failed to allocated starting task status arrays
			goto err;
		}

		//Get starting statuses of tasks
		uxArraySizeStart = uxTaskGetSystemState(pxTaskStatusArrayStart, uxArraySizeStart, &ulTimeStart);
		if (uxArraySizeStart == 0) {
			//Array was not large enough to store all task statuses
			goto err;
		}

		//Wait for the specified amount of time
		vTaskDelay(xTicksToWait);

		uxArraySizeEnd = uxCurrentNumberOfTasks;
		pxTaskStatusArrayEnd = pvPortMalloc( uxArraySizeEnd * sizeof( TaskStatus_t ) );
		if(pxTaskStatusArrayEnd == NULL) {
			//Failed to allocated ending task status arrays
			goto err;
		}

		//Get end statuses of tasks
		uxArraySizeEnd = uxTaskGetSystemState(pxTaskStatusArrayEnd, uxArraySizeEnd, &ulTimeEnd);
		if (uxArraySizeEnd == 0){
			//Array was not large enough to store all task statuses
			goto err;
		}

		//Get measurement duration for real time stats. Check if total time has overflowed
		uint32_t ulElapsedTime = (ulTimeStart <= ulTimeEnd) ? (ulTimeEnd - ulTimeStart) : (ulTimeStart - ulTimeEnd);
		ulElapsedTime = (ulElapsedTime/100UL)*portNUM_PROCESSORS;

		if (ulElapsedTime > 0) {
			//Calculate and write stats to buffer
			uint32_t ulTaskRunTime;
			for (UBaseType_t i = 0; i < uxArraySizeStart; i++) {
				//Before and After arrays may not store tasks in the same order
				bool found = false;
				for (UBaseType_t j = 0; j < uxArraySizeEnd; j++) {
					if (pxTaskStatusArrayStart[i].xHandle == pxTaskStatusArrayEnd[j].xHandle) {
						//Get duration task has run for. Check if duration has overflowed
						ulTaskRunTime = (pxTaskStatusArrayStart[i].ulRunTimeCounter <= pxTaskStatusArrayEnd[j].ulRunTimeCounter) ?
										(pxTaskStatusArrayEnd[j].ulRunTimeCounter - pxTaskStatusArrayStart[i].ulRunTimeCounter) :
										(pxTaskStatusArrayStart[i].ulRunTimeCounter - pxTaskStatusArrayEnd[j].ulRunTimeCounter);
						found = true;
						break;
					}
				}
				if (!found) {
					//Could not find the same task in task status end array. Could have been deleted while this function blocked.
					continue;
				}
				ulStatsAsPercentage = ulTaskRunTime / ulElapsedTime;
				pcWriteBuffer = prvWriteNameToBuffer( pcWriteBuffer, pxTaskStatusArrayStart[i].pcTaskName );

				if( ulStatsAsPercentage > 0UL ){
					#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
					{
						sprintf( pcWriteBuffer, "\t%lu\t\t%lu%%\r\n", ulTaskRunTime, ulStatsAsPercentage );
					}
					#else
					{
						/* sizeof( int ) == sizeof( long ) so a smaller
						printf() library can be used. */
						sprintf( pcWriteBuffer, "\t%u\t\t%u%%\r\n", ( unsigned int ) ulTaskRunTime, ( unsigned int ) ulStatsAsPercentage );
					}
					#endif
				} else {
					/* If the percentage is zero here then the task has
					consumed less than 1% of the total run time. */
					#ifdef portLU_PRINTF_SPECIFIER_REQUIRED
					{
						sprintf( pcWriteBuffer, "\t%lu\t\t<1%%\r\n", ulTaskRunTime );
					}
					#else
					{
						/* sizeof( int ) == sizeof( long ) so a smaller
						printf() library can be used. */
						sprintf( pcWriteBuffer, "\t%u\t\t<1%%\r\n", ( unsigned int ) ulTaskRunTime );
					}
					#endif
				}
				pcWriteBuffer += strlen( pcWriteBuffer );
			}
		}

		//Free memory used
		free(pxTaskStatusArrayStart);
		free(pxTaskStatusArrayEnd);
		return pdPASS;

		err:
		if (pxTaskStatusArrayStart != NULL) {
			free(pxTaskStatusArrayStart);
		}
		if (pxTaskStatusArrayEnd != NULL) {
			free(pxTaskStatusArrayEnd);
		}
		return pdFAIL;
	}

vonnieda
Posts: 145
Joined: Tue Nov 07, 2017 3:42 pm

Re: How to deal with overflow in uxTaskGetSystemState?

Postby vonnieda » Tue Aug 28, 2018 4:44 pm

ESP_Dazz wrote:This isn't exactly a solution to the overflow issue, but the following workaround function might be useful for your purposes. It essentially measures FreeRTOS Task CPU usage over a given period instead of over the total run time.

Thanks ESP_Dazz! I had considered writing something like this myself, so thank you for saving me the trouble! :)

Jason

Who is online

Users browsing this forum: axellin, Bing [Bot], Majestic-12 [Bot] and 101 guests