Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrated-timers: Dequeue in alarm_callback #3579

Closed
wants to merge 13 commits into from

Conversation

bugadani
Copy link
Contributor

@bugadani bugadani commented Nov 26, 2024

Before: Test OK, count=8537, cycles=140564/100
After: Test OK, count=70747, cycles=16961/100

Still somewhat slower than generic queue but at least not by 10x (it clocks in at count=70666, cycles=16981/100).

Benchmark source

//! Embassy executor benchmark, used to try out optimization ideas.

//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: esp-hal-embassy/integrated-timers

#![no_std]
#![no_main]

use core::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

use embassy_executor::{raw::TaskStorage, Spawner};
use esp_backtrace as _;
use esp_hal::{
    prelude::*,
    time::Duration,
    timer::{systimer::SystemTimer, OneShotTimer},
};
use esp_println::println;

static mut COUNTER: u32 = 0;

const CLOCK: CpuClock = CpuClock::max();
const TEST_MILLIS: u64 = 50;

#[handler]
fn timer_handler() {
    let c = unsafe { COUNTER } as u64;
    let cpu_clock = CLOCK.hz() as u64;
    let timer_ticks_per_second = SystemTimer::ticks_per_second();
    let cpu_cycles_per_timer_ticks = cpu_clock / timer_ticks_per_second;
    println!(
        "Test OK, count={}, cycles={}/100",
        c,
        (100 * timer_ticks_per_second * cpu_cycles_per_timer_ticks * TEST_MILLIS / 1000) / c
    );
    loop {}
}

struct Task1 {}
impl Future for Task1 {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        unsafe { COUNTER += 1 };
        cx.waker().wake_by_ref();
        Poll::Pending
    }
}

static TASK1: TaskStorage<Task1> = TaskStorage::new();

#[embassy_executor::task]
async fn task2() {
    loop {
        embassy_time::Timer::after(embassy_time::Duration::from_millis(1)).await;
    }
}

#[esp_hal_embassy::main]
async fn main(spawner: Spawner) {
    let peripherals = esp_hal::init({
        let mut config = esp_hal::Config::default();
        config.cpu_clock = CLOCK;
        config
    });
    let systimer = SystemTimer::new(peripherals.SYSTIMER);
    esp_hal_embassy::init(systimer.alarm0);
    println!("Embassy initialized!");

    spawner.spawn(TASK1.spawn(|| Task1 {})).unwrap();
    spawner.spawn(task2()).unwrap();

    println!("Starting test");

    let mut timer = OneShotTimer::new(systimer.alarm1);
    timer.set_interrupt_handler(timer_handler);
    timer.enable_interrupt(true);
    timer.schedule(Duration::millis(TEST_MILLIS)).unwrap();
}

@bugadani bugadani force-pushed the timers branch 2 times, most recently from f381c63 to 39883f2 Compare November 26, 2024 23:11
@bugadani bugadani marked this pull request as ready for review November 27, 2024 23:12
@bugadani bugadani marked this pull request as draft November 27, 2024 23:24
@bugadani bugadani force-pushed the timers branch 2 times, most recently from 9640afd to 2e0a09f Compare November 28, 2024 10:33
@bugadani
Copy link
Contributor Author

bugadani commented Nov 28, 2024

Numbers got a bit worse because the previous iteration was broken :)

Unfortunately expires_at is now accessed in interrupt contexts as well so we need to wrap it in a Mutex, making things slightly worse.

There is room for improvement:

  • The critical sections could probably be reduced/tightened on devices with Atomic instrs
  • We could add a RawMutex type parameter to the executor so that multi-cores don't need to use their global locks.
  • We could cache the next expiration time. Firing an alarm may not be ideal when nothing has actually expired (could happen if a task was waken by something else), but scanning through the timer queue on every poll even if nothing changes is probably more expensive. Done

@bugadani bugadani marked this pull request as ready for review November 28, 2024 11:13
@bugadani bugadani force-pushed the timers branch 2 times, most recently from 0ba2d24 to 751ab22 Compare November 28, 2024 13:13
@Dirbaio
Copy link
Member

Dirbaio commented Nov 29, 2024

bender run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants