use core::sync::atomic::Ordering;
use crate::embassy_net::EmacDriverState;
pub const HISTOGRAM_BUCKETS: usize = 16;
pub const HISTOGRAM_UPPER_US: [u32; HISTOGRAM_BUCKETS] = [
1,
2,
5,
10,
20,
50,
100,
200,
500,
1_000,
2_000,
5_000,
10_000,
20_000,
50_000,
u32::MAX,
];
#[inline]
#[must_use]
pub fn histogram_bucket(d_us: u32) -> usize {
let mut i = 0;
while i < HISTOGRAM_BUCKETS {
if d_us <= HISTOGRAM_UPPER_US[i] {
return i;
}
i += 1;
}
HISTOGRAM_BUCKETS - 1
}
#[inline]
pub(crate) fn now_us() -> u32 {
let dur = esp_hal::time::Instant::now()
.duration_since_epoch()
.as_micros();
dur as u32
}
pub(crate) const IRQ_TIMESTAMP_NONE: u32 = u32::MAX;
#[derive(Debug, Clone, Copy, Default)]
pub struct EmacInstrumentation {
pub rx_calls: u32,
pub rx_some: u32,
pub rx_bytes: u32,
pub rx_dropped: u32,
pub tx_calls: u32,
pub tx_some: u32,
pub tx_bytes: u32,
pub tx_dropped: u32,
pub dma_missed_frames: u32,
pub dma_fifo_overflow: u32,
pub rx_irq_to_token_histogram: [u32; HISTOGRAM_BUCKETS],
pub tx_token_to_dma_histogram: [u32; HISTOGRAM_BUCKETS],
}
impl EmacInstrumentation {
#[must_use]
pub fn snapshot(state: &EmacDriverState) -> Self {
let (mfc_delta, ovf_delta) = crate::regs::dma::missed_frames();
state
.dma_missed_frames
.fetch_add(mfc_delta, Ordering::Relaxed);
state
.dma_fifo_overflow
.fetch_add(ovf_delta, Ordering::Relaxed);
let mut rx_hist = [0u32; HISTOGRAM_BUCKETS];
let mut tx_hist = [0u32; HISTOGRAM_BUCKETS];
for (i, b) in rx_hist.iter_mut().enumerate() {
*b = state.rx_irq_to_token_us[i].load(Ordering::Relaxed);
}
for (i, b) in tx_hist.iter_mut().enumerate() {
*b = state.tx_token_to_dma_us[i].load(Ordering::Relaxed);
}
Self {
rx_calls: state.drv_rx_calls.load(Ordering::Relaxed),
rx_some: state.drv_rx_some.load(Ordering::Relaxed),
rx_bytes: state.drv_rx_bytes.load(Ordering::Relaxed),
rx_dropped: state.drv_rx_dropped.load(Ordering::Relaxed),
tx_calls: state.drv_tx_calls.load(Ordering::Relaxed),
tx_some: state.drv_tx_some.load(Ordering::Relaxed),
tx_bytes: state.drv_tx_bytes.load(Ordering::Relaxed),
tx_dropped: state.drv_tx_dropped.load(Ordering::Relaxed),
dma_missed_frames: state.dma_missed_frames.load(Ordering::Relaxed),
dma_fifo_overflow: state.dma_fifo_overflow.load(Ordering::Relaxed),
rx_irq_to_token_histogram: rx_hist,
tx_token_to_dma_histogram: tx_hist,
}
}
pub fn reset(state: &EmacDriverState) {
let _ = crate::regs::dma::missed_frames();
state.drv_rx_calls.store(0, Ordering::Relaxed);
state.drv_rx_some.store(0, Ordering::Relaxed);
state.drv_rx_bytes.store(0, Ordering::Relaxed);
state.drv_rx_dropped.store(0, Ordering::Relaxed);
state.drv_tx_calls.store(0, Ordering::Relaxed);
state.drv_tx_some.store(0, Ordering::Relaxed);
state.drv_tx_bytes.store(0, Ordering::Relaxed);
state.drv_tx_dropped.store(0, Ordering::Relaxed);
state.dma_missed_frames.store(0, Ordering::Relaxed);
state.dma_fifo_overflow.store(0, Ordering::Relaxed);
state
.last_rx_irq_us
.store(IRQ_TIMESTAMP_NONE, Ordering::Relaxed);
for b in &state.rx_irq_to_token_us {
b.store(0, Ordering::Relaxed);
}
for b in &state.tx_token_to_dma_us {
b.store(0, Ordering::Relaxed);
}
}
}