From 9a363cf7bbe8b3ce18fc41282febe17da336adb1 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Wed, 10 Sep 2025 15:09:10 +0200 Subject: [PATCH] perf(executor): Catch up on network work before returning When the point in time that smoltcp thinks the interface should be polled again is in the past, we should try to poll it immediately to avoid lagging behind. Signed-off-by: Jens Reidel --- src/executor/mod.rs | 62 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/executor/mod.rs b/src/executor/mod.rs index 298805a992..c78112aeca 100644 --- a/src/executor/mod.rs +++ b/src/executor/mod.rs @@ -143,6 +143,36 @@ where } } +fn maybe_set_network_timer(now: u64) { + if let Some(mut guard) = crate::executor::network::NIC.try_lock() { + let delay = if let Ok(nic) = guard.as_nic_mut() { + let mut delay_micros = nic + .poll_delay(Instant::from_micros_const(now.try_into().unwrap())) + .map(|d| d.total_micros()); + + // Under heavy workloads, we may be lagging behind, in which case we + // need to try to catch up immediately + while delay_micros == Some(0) { + nic.poll_common(crate::executor::network::now()); + delay_micros = nic + .poll_delay(crate::executor::network::now()) + .map(|d| d.total_micros()); + } + + // We will yield back to userspace and may not have an opportunity to handle + // network traffic unless we enable interrupts + nic.set_polling_mode(false); + + delay_micros + } else { + None + }; + + core_local::core_scheduler() + .add_network_timer(delay.map(|d| crate::arch::processor::get_timer_ticks() + d)); + } +} + /// Blocks the current thread on `f`, running the executor when idling. pub(crate) fn block_on(future: F, timeout: Option) -> io::Result where @@ -166,21 +196,7 @@ where if let Poll::Ready(t) = result { // allow network interrupts #[cfg(feature = "net")] - { - if let Some(mut guard) = crate::executor::network::NIC.try_lock() { - let delay = if let Ok(nic) = guard.as_nic_mut() { - nic.set_polling_mode(false); - - nic.poll_delay(Instant::from_micros_const(now.try_into().unwrap())) - .map(|d| d.total_micros()) - } else { - None - }; - core_local::core_scheduler().add_network_timer( - delay.map(|d| crate::arch::processor::get_timer_ticks() + d), - ); - } - } + maybe_set_network_timer(now); return t; } @@ -190,21 +206,7 @@ where { // allow network interrupts #[cfg(feature = "net")] - { - if let Some(mut guard) = crate::executor::network::NIC.try_lock() { - let delay = if let Ok(nic) = guard.as_nic_mut() { - nic.set_polling_mode(false); - - nic.poll_delay(Instant::from_micros_const(now.try_into().unwrap())) - .map(|d| d.total_micros()) - } else { - None - }; - core_local::core_scheduler().add_network_timer( - delay.map(|d| crate::arch::processor::get_timer_ticks() + d), - ); - } - } + maybe_set_network_timer(now); return Err(Errno::Time); }