cancel
Showing results for 
Search instead for 
Did you mean: 

How to measure CPU usage using CMSIS FreeRTOS?

rrnicolay
Associate II

Hi! How do I measure CPU usage for every task in CMSIS FreeRTOS?

I enabled all run time and task stats gathering related definitions (GENERATE_RUN_TIME_STATS, USE_TRACE_FACILITY and USE_STATS_FORMATTING_FUNCTIONS) in STM32CubeIDE GUI.

When I call vTaskGetRunTimeStats(), nothing is returned. The function uxTaskGetSystemState() inside vTaskGetRunTimeStats() returns that the task used 0 clock cycles every time.

Do I need to set a timer or redefine some functions to get things working? How to do that?

P.S.: I don't know if this is the correct place to ask about this.

Thanks in advance.

6 REPLIES 6
Jack Peacock_2
Senior III

FreeRTOS requires a hardware timer to measure CPU time in a task context. If you read the FreeRTOS section on runtime stats and task profiling there are some routines you must supply:

vConfigureTimerForRunTmeStats() - set up a timer (I use TIM7) at a relatively high frequency (I use 10KHz for 100usec statistics ticks). The timer is free running; FreeRTOS takes the diference, with wraparound, to determine elapsed time in a task.

vRunTimeCounterValue() - read the time count, but don;t stop the timer.

If you use tickless mode or low power modes you'll have to stop/start the profiling timer while sleeping.

You see zero time becuase there's no active timer to track time in task context.

Jack Peacock

I'm not succeding in this task.

What I did:

* Configured TIM7 (16MHz) through Cube (PSC=1600, Up-counter, ARR=65535, to get a 10kHz timer)

* In main, did a function to return the handle for TIM7.

* Configured the functions(freertos.c) as:

__weak void configureTimerForRunTimeStats(void)
{
	HAL_TIM_Base_Start(getTim7Handler());
}
 
__weak unsigned long getRunTimeCounterValue(void)
{
	return getTim7Handler()->Instance->CNT;
}

* Once a second, I call vTaskGetRunTimeStats().

I'm getting wrong values, like:

ledTask         88656           152%
IDLE            1385034         2379%
iwdgTask        120             <1%
memsTask        484251          832%
uartParserTask  288956          496%

The time consumed by the task isnt getting reset, just incremented in a 32b variable(without overflow protection). The total time(TIM7, in my case) used to calculate the percentage, which has only 16b, keeps overflowing all the time. So, Its not possible to get CPU usage of last second?

I still can get nice results when application starts, but the idea was to monitor continously. I think I didnt understand it correctly, because it is not monitoring last second stats, and due to overflows, it cant measure long term stats either.

Using:

CMSIS_V1 (1.02)

FreeRTOS 10.0.1

STM32F103

Jack Peacock_2
Senior III

It's a task profiler. The purpose is to show overall execution time by task. If you only want the last second, look at it as if you are sampling from an ADC. You gather the task times at time X0, then one second later at time X1. You don't care about the absolute values (i.e. 32-bit rollover isn't critical); all you want is the change from X0 to X1, adjusted for 32-bit rollover. The sum of the task deltas is the time the CPU spent in a task context (and it won't sum to exactly one second, there's overhead plus the errors from sampling at a 10KHz rate.

Bear in mind long or frequent interrupt handlers will skew your results since the service routine time will be charged to whatever task happens to be in context. Task scheduling will also affect total time since the scheduler is not a task.

Jack Peacock

"The purpose is to show overall execution time by task."

Ok, this is working fine. But the percentage calculation really gets messed up for you too? Its not just for me? The correct would be a value between 0 and 100% for each task. Right? Then, it would be a history of execution time since app startup (doesnt make much sense to me, either way).

So, to get the stats from the last second (like in any OS) I need to modify the code from FreeRTOS (vTaskGetRunTimeStats, in tasks.c)? I will need to store the values for time X0 for every task and the total (in TIM7), taking overflows into account. Then I can do the math to isolate the time of overhead (everything thats not a task).

Am I seeing the whole picture here?

rrnicolay
Associate II

For the ones looking to get stats for last second:

In this link, there's a function to clear stats, posted by user "richarddamon". The function is called "vTaskClearUsage".

Every second, I have a task that wakes up, calls vTaskGetRunTimeStats() and clear the stats with vTaskClearUsage().

This prevents any kind of overflow aswell.

Changed my configureTimerForRunTimeStats() (will get called automatically from vTaskClearUsage) to:

__weak void configureTimerForRunTimeStats(void)
{
	HAL_TIM_Base_Stop(getTim7Handler());
	getTim7Handler()->Instance->CNT = 0;
	HAL_TIM_Base_Start(getTim7Handler());
}

As a result, the CPU time of every task get printed at each second. Yes, some time is used by ISR, task switching, etc... that needs to be decremented from IDLE time to get more realistic time.

debugTask       103             1%
IDLE            7506            74%
iwdgTask        1               <1%
ledTask         0               <1%
memsTask        2281            22%
uartParserTask  265             2%

Brian TIDAL
ST Employee

Hi,

instead of using a timer, it is possible to use the Cycle Counter from the DWT unit.

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.