diff --git a/esp-hal-embassy/CHANGELOG.md b/esp-hal-embassy/CHANGELOG.md index 7e39a289fad..639f49184c4 100644 --- a/esp-hal-embassy/CHANGELOG.md +++ b/esp-hal-embassy/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - +- Embassy executor CPU stats (#3728) ### Changed diff --git a/esp-hal-embassy/esp_config.yml b/esp-hal-embassy/esp_config.yml index 635a77a0fa9..1377c0810c1 100644 --- a/esp-hal-embassy/esp_config.yml +++ b/esp-hal-embassy/esp_config.yml @@ -45,3 +45,8 @@ options: constraints: - type: validator: positive_integer + +- name: low-power-wait-stats + description: Enables statistics for the low-power wait feature. Needs the `low-power-wait` config option to be enabled + default: + - value: true \ No newline at end of file diff --git a/esp-hal-embassy/src/executor/thread.rs b/esp-hal-embassy/src/executor/thread.rs index f715b6c01f0..70f90f2b3fc 100644 --- a/esp-hal-embassy/src/executor/thread.rs +++ b/esp-hal-embassy/src/executor/thread.rs @@ -3,15 +3,24 @@ use core::marker::PhantomData; use embassy_executor::Spawner; +#[cfg(all(low_power_wait, low_power_wait_stats))] +use embassy_time::Instant; #[cfg(all(low_power_wait, multi_core))] use esp_hal::interrupt::software::SoftwareInterrupt; use esp_hal::{interrupt::Priority, system::Cpu}; +#[cfg(all(low_power_wait, low_power_wait_stats))] +use portable_atomic::AtomicU64; +#[cfg(low_power_wait)] use portable_atomic::{AtomicBool, Ordering}; use super::InnerExecutor; pub(crate) const THREAD_MODE_CONTEXT: usize = 16; +// Count the ticks the CPU was in wait_impl +#[cfg(all(low_power_wait, low_power_wait_stats))] +static SLEEP_TICKS: AtomicU64 = AtomicU64::new(0); + /// global atomic used to keep track of whether there is work to do since sev() /// is not available on either Xtensa or RISC-V static SIGNAL_WORK_THREAD_MODE: [AtomicBool; Cpu::COUNT] = @@ -172,6 +181,15 @@ This will use software-interrupt 3 which isn't available for anything else to wa unsafe { self.inner.inner.poll() }; + #[cfg(all(low_power_wait, low_power_wait_stats))] + let before = Instant::now().as_ticks(); + #[cfg(low_power_wait)] + Self::wait_impl(self.cpu as usize); + #[cfg(all(low_power_wait, low_power_wait_stats))] + { + let after = Instant::now().as_ticks(); + SLEEP_TICKS.fetch_add(after - before, Ordering::Relaxed); + } hooks.on_idle(); #[cfg(low_power_wait)] @@ -239,3 +257,52 @@ impl Default for Executor { Self::new() } } + +// Based on https://github.com/embassy-rs/embassy/pull/3920 +#[cfg(all(low_power_wait, low_power_wait_stats))] +pub mod thread_low_power_wait_stats { + use embassy_time::Instant; + use portable_atomic::Ordering; + + /// Statistics for the thread low power wait usage. + pub struct ThreadLowPowerWaitStats { + previous_tick: u64, + previous_sleep_tick: u64, + } + + impl ThreadLowPowerWaitStats { + /// Create a new instance of `ThreadLowPowerWaitStats`. + /// This initializes the previous tick and sleep tick values + /// to the current time and the current sleep tick count. + /// Run get_usage() to get the current usage percentage periodically. + pub fn new() -> Self { + Self { + previous_tick: Instant::now().as_ticks(), + previous_sleep_tick: super::SLEEP_TICKS.load(Ordering::Relaxed), + } + } + + /// Get the current usage percentage of the thread low power wait. + pub fn get_usage(&mut self) -> f32 { + let current_tick = Instant::now().as_ticks(); + let current_sleep_tick = super::SLEEP_TICKS.load(Ordering::Relaxed); + + // Calculate the ratio of time spent sleeping to total time since last report, + // the inverse of which is the time spent busy + let sleep_tick_difference = (current_sleep_tick - self.previous_sleep_tick) as f32; + let tick_difference = (current_tick - self.previous_tick) as f32; + let usage = 1f32 - sleep_tick_difference / tick_difference; + + self.previous_tick = current_tick; + self.previous_sleep_tick = current_sleep_tick; + + usage * 100.0 + } + } + + impl Default for ThreadLowPowerWaitStats { + fn default() -> Self { + Self::new() + } + } +} diff --git a/esp-hal-embassy/src/lib.rs b/esp-hal-embassy/src/lib.rs index 9a40bf6a507..80272c69940 100644 --- a/esp-hal-embassy/src/lib.rs +++ b/esp-hal-embassy/src/lib.rs @@ -55,6 +55,8 @@ mod fmt; use esp_hal::timer::{AnyTimer, timg::Timer as TimgTimer}; pub use macros::embassy_main as main; +#[cfg(all(low_power_wait, low_power_wait_stats, feature = "executors"))] +pub use self::executor::thread_low_power_wait_stats::ThreadLowPowerWaitStats; #[cfg(feature = "executors")] pub use self::executor::{Callbacks, Executor, InterruptExecutor}; use self::time_driver::{EmbassyTimer, Timer};