Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions lib/firmware-base/system-status.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <driver/timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>

#include <stdio.h>

#define TIMER_DIVIDER 80 // Divide Base by 80
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is self-evident, would you mind #defineing constants for an expression as to how you arrived to this value?



// Timer group 0, timer 0 configuration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See how these comments are redundant? Even the last field wouldn't need a comment if you use a descriptive constant name.

timer_config_t timer_config = {
.alarm_en = TIMER_ALARM_DIS, // Disable alarm
.intr_type = TIMER_INTR_DISABLE, // No timer interrupts
.counter_dir = TIMER_COUNT_UP, // Count up
.auto_reload = TIMER_AUTORELOAD_EN, // Auto-reload
.divider = TIMER_DIVIDER // Set divider for 1ms (assumption that base
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do expand this into a proper #define you wouldn't need to make this assumption! FreeRTOS should have a config #define that has the CPU frequency.

// runs at 80Mhz)
};

// Initialization
void init_timer0()
{
timer_init(TIMER_GROUP_0, TIMER_0, &timer_config);
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
timer_start(TIMER_GROUP_0, TIMER_0);
}

volatile uint64_t core0_idle_cycles = 0;
volatile uint64_t core1_idle_cycles = 0;

// When idle
void vAppliocationIdleHook(void)
{
// For ISR to handle (?)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

// Which core? (assumption 1 cycle == 1 tick)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FreeRTOS tick is triggered by some kind of SysTick timer (in our case I believe it's TIMER0.

// Can ccheck by creating vApplicationTickHook and comparing # tick and
// # idle cycles << todo

if (xPortGetCoreID() == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be cleaner to make the variable an array and index into it with the output of the function to increment the variable. Just make sure it always succeeds or else you need to add error checking.

core0_idle_cycles++;
} else if (xPortGetCoreID() == 1) {
core1_idle_cycles++;
}
}

void print_cpu_utilization(void *pvParameters)
{
while (1) {
uint64_t start_time = 0, end_time = 0;

timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &start_time);

// Let run for 5 sec
// Interrupts can be called here to run other tasks
// What if interrupt task runs for more than 5 secs?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watchdog should trip.

vTaskDelay(pdMS_TO_TICKS(5000));

timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &end_time);

// Calculate total ticks/cycles in 1 sec
uint64_t ticks_elapsed = end_time - start_time;

float core0_utilization = 100.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should use ticks to calculate this over cpu cycles since that's much harder to keep track of. There is a FreeRTOS config #define that sets the SysTick frequency in Hz. ESP-IDF is quirky and sets this in the sdkconfig and I think it generates the config for their custom fork automatically. You can either look at the file manually or run the menuconfig target to see this.

- ((float) core0_idle_cycles / ticks_elapsed) * 100.0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also try to keep the CPU utilization similar to how Linux reports it (as a float between 0 and 1 per core).

float core1_utilization = 100.0
- ((float) core1_idle cycles / ticks_elapsed) * 100.0;

// Print CPU utilization
printf("Core 0 CPU Utilization: %.2f\n", core0_utilization);
printf("Core 1 CPU Utilization: %.2f\n", core1_utilization);

// Reset idle cycles
core0_idle_cycles = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for discarding these? Ideally we keep a global running count and a sliding window which we would average so that we have current stats and stats for the duration of the power cycle.

core1_idle_cycles = 0;

// Might need to handle overflow if it does occur
}
}

void app_main()
{
init_timer0();

xTaskCreate(print_cpu_utilization,
"Print CPU Utilization",
2048,
NULL,
1,
NULL);

vTaskStartScheduler();
}