2023-11-15 03:59 AM
I want to know my board(STM32H750)'s CPU usage when it is running. I used freeRTOS in my softwrae system.
Is there any tools or any ways to get CPU usage during the system is running?
Solved! Go to Solution.
2023-11-15 11:13 AM - edited 2023-11-15 12:04 PM
Some time ago we used the following code to measure the CPU usage - defined as time consumed by any task except of the idle task:
#include <stdatomic.h>
// Measurements for the last second (1000 ms), by 10 ms periods:
volatile uint32_t timestamps_per_10ms[1000/10];
volatile uint32_t usage_counts_per_10ms[1000/10];
atomic_uint_fast32_t usage_counts_index;
atomic_uint_fast32_t idle_time_sum = 0; // total idle time in 1µs units
uint32_t get_hrtime32(void); // get timestamp in µs
/** idle task runtime measurement hook.
* Called from RTOS scheduler, traceTASK_SWITCHED_IN/OUT
* We'll count time between entry and exit from the RTOS idle task.
* in_idle = 1 when idle task gets CPU, 0 when any other task gets CPU
* Note: time in interrupts is not counted here!
*/
void hookIdleTaskSwitch(int in_idle)
{
static uint32_t idle_time_begin; // init value doesn't matter, ignore 1st span
if (in_idle) {
idle_time_begin = get_hrtime32();
} else {
atomic_fetch_add(&idle_time_sum, (_get_hrtime32() - idle_time_begin));
}
}
// Fetch and zero the idle time counter
uint32_t get_idle_span(void)
{
return (uint32_t)atomic_exchange(&idle_time_sum, 0);
}
// This is called every 10 ms, from a periodic low prio task:
void cpu_utilization_10ms_tick()
{
unsigned n = atomic_load(&usage_counts_index) + 1;
if (n >= ARRAY_SIZE(usage_counts_per_10ms)) {
n = 0;
}
timestamps_per_10ms[n] = get_hrtime32();
usage_counts_per_10ms[n] = get_idle_span();
atomic_store_explicit(&usage_counts_index, n, memory_order_release);
}
Then, add the following macros in FreeRTOSConfig.h:
extern void hookIdleTaskSwitch(int);
#define traceTASK_SWITCHED_IN() \
if ( (TaskHandle_t)pxCurrentTCB == xIdleTaskHandle ) { hookIdleTaskSwitch(1); }
#define traceTASK_SWITCHED_OUT() \
if ( (TaskHandle_t)pxCurrentTCB == xIdleTaskHandle ) { hookIdleTaskSwitch(0); }
And the code to retrieve and print the statistics of few recent samples:
void print_CPU_usage(unsigned Nsamples)
{
printf("--- CPU %% ---\n");
unsigned const N = ARRAY_SIZE(usage_counts_per_10ms);
uint32_t ix = atomic_load_explicit(&usage_counts_index, memory_order_relaxed);
unsigned sum_idle = 0;
__disable_irq();
unsigned prev_ts = 0;
for (unsigned n = 0; n < Nsamples; n++) {
unsigned v = usage_counts_per_10ms[ix];
sum_idle += v;
if (n > 0) {
prev_ts -= timestamps_per_10ms[ix];
}
printf("[%u|%u] %u\n", n, prev_ts, v);
prev_ts = timestamps_per_10ms[ix];
if (ix == 0) {
ix = N - 1;
} else {
--ix;
}
}
__enable_irq();
// % of used time = (10*100*1000us - sum_idle) / (10*10*1000us) * 100%
printf("Idle time for 100 ms = %u us; usage %%=%u\n", sum_idle, (100 - sum_idle / 1000));
}
2023-11-15 11:13 AM - edited 2023-11-15 12:04 PM
Some time ago we used the following code to measure the CPU usage - defined as time consumed by any task except of the idle task:
#include <stdatomic.h>
// Measurements for the last second (1000 ms), by 10 ms periods:
volatile uint32_t timestamps_per_10ms[1000/10];
volatile uint32_t usage_counts_per_10ms[1000/10];
atomic_uint_fast32_t usage_counts_index;
atomic_uint_fast32_t idle_time_sum = 0; // total idle time in 1µs units
uint32_t get_hrtime32(void); // get timestamp in µs
/** idle task runtime measurement hook.
* Called from RTOS scheduler, traceTASK_SWITCHED_IN/OUT
* We'll count time between entry and exit from the RTOS idle task.
* in_idle = 1 when idle task gets CPU, 0 when any other task gets CPU
* Note: time in interrupts is not counted here!
*/
void hookIdleTaskSwitch(int in_idle)
{
static uint32_t idle_time_begin; // init value doesn't matter, ignore 1st span
if (in_idle) {
idle_time_begin = get_hrtime32();
} else {
atomic_fetch_add(&idle_time_sum, (_get_hrtime32() - idle_time_begin));
}
}
// Fetch and zero the idle time counter
uint32_t get_idle_span(void)
{
return (uint32_t)atomic_exchange(&idle_time_sum, 0);
}
// This is called every 10 ms, from a periodic low prio task:
void cpu_utilization_10ms_tick()
{
unsigned n = atomic_load(&usage_counts_index) + 1;
if (n >= ARRAY_SIZE(usage_counts_per_10ms)) {
n = 0;
}
timestamps_per_10ms[n] = get_hrtime32();
usage_counts_per_10ms[n] = get_idle_span();
atomic_store_explicit(&usage_counts_index, n, memory_order_release);
}
Then, add the following macros in FreeRTOSConfig.h:
extern void hookIdleTaskSwitch(int);
#define traceTASK_SWITCHED_IN() \
if ( (TaskHandle_t)pxCurrentTCB == xIdleTaskHandle ) { hookIdleTaskSwitch(1); }
#define traceTASK_SWITCHED_OUT() \
if ( (TaskHandle_t)pxCurrentTCB == xIdleTaskHandle ) { hookIdleTaskSwitch(0); }
And the code to retrieve and print the statistics of few recent samples:
void print_CPU_usage(unsigned Nsamples)
{
printf("--- CPU %% ---\n");
unsigned const N = ARRAY_SIZE(usage_counts_per_10ms);
uint32_t ix = atomic_load_explicit(&usage_counts_index, memory_order_relaxed);
unsigned sum_idle = 0;
__disable_irq();
unsigned prev_ts = 0;
for (unsigned n = 0; n < Nsamples; n++) {
unsigned v = usage_counts_per_10ms[ix];
sum_idle += v;
if (n > 0) {
prev_ts -= timestamps_per_10ms[ix];
}
printf("[%u|%u] %u\n", n, prev_ts, v);
prev_ts = timestamps_per_10ms[ix];
if (ix == 0) {
ix = N - 1;
} else {
--ix;
}
}
__enable_irq();
// % of used time = (10*100*1000us - sum_idle) / (10*10*1000us) * 100%
printf("Idle time for 100 ms = %u us; usage %%=%u\n", sum_idle, (100 - sum_idle / 1000));
}
2023-11-16 10:13 PM
Thanks, @Pavel A.