FreeRTOS task runtime stats: can't we just let the timer rollover?

I want to use vTaskGetRunTimeStats() to check task runtime in long-running system and make sure that some tasks aren’t taking more time than I expect. ulTotalRuntime is a uint32_t, meaning that - if my system is up for a month - its maximum frequency without rolling over will be about 4kHz, which is a bit more modest than I’d like. Also, a month of uptime really isn’t that much; I’d like to be able to collect stats for longer than that.

It looks like the accumulation happens here in vTaskSwitchContext. If the timer rolls over, FreeRTOS skips counting .

Why do this? It limits task stats on long-running systems. As long as the user-provided timer doesn’t roll over twice between calls to vTaskSwitchContext, doing an unsigned subtract on two uint32_t that have rolled over will work out just fine. (of course, the user-provided timer has to have a period of 0x1_0000_0000).

Would it be possible to add a macro - say “configALLOW_RUN_TIME_STAT_TIMER_ROLLOVER” - that skips this check in vTaskSwitchContext?

Thanks

  • John

edit: I just realized that only the time accumulated for the task period where the timer rolls over will be discarded and that it won’t add up to much error at all. It would be nice if some info could be added to the documentation about portGET_RUN_TIME_COUNTER_VALUE saying that timer overflow is okay, and that it’ll just result in a little bit of unaccounted-for time.

There are two rollovers to account for.
ulTotalRunTime
pxCurrentTCB->ulRunTimeCounter
If ulTotalRunTime wraps, it will cause a minor loss of accuracy for ulRunTimeCounter.
But if ulRunTimeCounter wraps you will need to compensate by adding 4.2e6 counts per rollover. A typical tick rate is 1mS so the system tick will roll ~49 days. If there are two tasks with equal priority, then their task counters will roll in ~100 days.

Is this sufficient for your application?

Thanks for the reply. I hadn’t considered that ulRunTimeCounter would also have to not wrap.

In my case, the tasks I’m concerned about run at very low CPU utilization (~1%), so even with a 10KHz counter, it would take about 500 days for rollover to happen in the individual counters. That’s more than enough for my application.

I still think it would be nice if the documentation for vTaskGetRunTimeStats() explained this stuff.

I have created a feature request for additional clarification.

We already have a feature request to provide an API that allows the run-time counter to be reset to 0. That would be easy enough to do on a task by task basis but more complex if you want to reset the counter back to zero for all tasks at the same time as doing so requires all the state and blocked lists to be traversed to find all the tasks (in the same way other functions do today, such as xTaskGetSystemState() which provides details of every task in the system).

A very simple thing we could do is allow the application writer to determine the type of the variable used to hold the accumulated time. Then the application writer could use a 64-bit time - trading space and execution time for longevity. We already do that for some types - for example the type used to specify the stack size - which is going to be different for 8-bit MCUs with little memory compared to 64-bit MCUs with Gigs of memory.