#[cfg(feature = "mem-probe")]
use embassy_time::Instant;
#[cfg(feature = "mem-probe")]
use portable_atomic::{AtomicU64, Ordering};
#[macro_export]
macro_rules! bench_emit {
($($arg:tt)*) => {
::log::info!("@BENCH {}", ::core::format_args!($($arg)*))
};
}
#[derive(Clone, Copy)]
pub enum Checkpoint {
Boot,
PeripheralsReady,
WifiUp,
TcpListening,
TcpAccept,
KexComplete,
AuthSuccess,
ChannelOpen,
}
#[cfg(feature = "mem-probe")]
impl Checkpoint {
const fn name(self) -> &'static str {
match self {
Self::Boot => "bench_boot",
Self::PeripheralsReady => "bench_peripherals_ready",
Self::WifiUp => "bench_wifi_up",
Self::TcpListening => "bench_tcp_listening",
Self::TcpAccept => "bench_tcp_accept",
Self::KexComplete => "bench_kex_complete",
Self::AuthSuccess => "bench_auth_success",
Self::ChannelOpen => "bench_channel_open",
}
}
}
#[cfg(feature = "mem-probe")]
const ALL: [Checkpoint; 8] = [
Checkpoint::Boot,
Checkpoint::PeripheralsReady,
Checkpoint::WifiUp,
Checkpoint::TcpListening,
Checkpoint::TcpAccept,
Checkpoint::KexComplete,
Checkpoint::AuthSuccess,
Checkpoint::ChannelOpen,
];
#[cfg(feature = "mem-probe")]
static T_US: [AtomicU64; ALL.len()] = [const { AtomicU64::new(0) }; ALL.len()];
#[cfg(feature = "mem-probe")]
pub fn checkpoint(c: Checkpoint) {
let t_us = Instant::now().as_micros();
bench_emit!("checkpoint={} t_us={t_us}", c.name());
T_US[c as usize].store(t_us, Ordering::Relaxed);
}
#[cfg(not(feature = "mem-probe"))]
pub fn checkpoint(_c: Checkpoint) {}
#[cfg(feature = "mem-probe")]
pub fn replay_checkpoints() {
for c in ALL {
if let t_us @ 1.. = T_US[c as usize].load(Ordering::Relaxed) {
crate::bench_emit!("checkpoint={} t_us={t_us}", c.name());
}
}
}
#[cfg(not(feature = "mem-probe"))]
pub fn replay_checkpoints() {}
#[cfg(feature = "mem-probe")]
static KEX_START_TICKS: AtomicU64 = AtomicU64::new(0);
#[cfg(feature = "mem-probe")]
pub fn mark_kex_start() {
KEX_START_TICKS.store(Instant::now().as_ticks(), Ordering::Relaxed);
}
#[cfg(not(feature = "mem-probe"))]
pub fn mark_kex_start() {}
#[cfg(feature = "mem-probe")]
pub fn log_kex_elapsed(label: &str) {
let start_ticks = KEX_START_TICKS.swap(0, Ordering::Relaxed);
if start_ticks == 0 {
return;
}
let elapsed = Instant::from_ticks(start_ticks).elapsed();
bench_emit!("kex={label} elapsed_us={}", elapsed.as_micros());
}
#[cfg(not(feature = "mem-probe"))]
pub fn log_kex_elapsed(_label: &str) {}