cancel
Showing results for 
Search instead for 
Did you mean: 

How can I get the CPU usage on STM32H7XX with freeRTOS

HarryXia
Associate II

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?

1 ACCEPTED SOLUTION

Accepted Solutions
Pavel A.
Evangelist III

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));
}

 

 

View solution in original post

2 REPLIES 2
Pavel A.
Evangelist III

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));
}

 

 

HarryXia
Associate II

Thanks, @Pavel A.