Skip to main content
Visitor II
November 15, 2023
Solved

How can I get the CPU usage on STM32H7XX with freeRTOS

  • November 15, 2023
  • 2 replies
  • 1774 views

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?

    This topic has been closed for replies.
    Best answer by Pavel A.

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

     

     

    2 replies

    Pavel A.Answer
    Super User
    November 15, 2023

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

     

     

    HarryXiaAuthor
    Visitor II
    November 17, 2023

    Thanks, @Pavel A.