use crate::config::WcetMode;
use std::time::Instant;
#[derive(Debug, Clone, Copy)]
pub struct WcetBudget {
pub envelope_parse_us: u64,
pub blake3_hash_us: u64,
pub ed25519_verify_us: u64,
pub ring_buffer_us: u64,
pub total_pipeline_us: u64,
}
impl Default for WcetBudget {
fn default() -> Self {
Self {
envelope_parse_us: 50,
blake3_hash_us: 100,
ed25519_verify_us: 500,
ring_buffer_us: 5,
total_pipeline_us: 1000,
}
}
}
pub struct WcetGuard {
operation: &'static str,
budget_us: u64,
mode: WcetMode,
start: Instant,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WcetResult {
Ok { elapsed_us: u64 },
Violation { elapsed_us: u64, budget_us: u64 },
}
#[derive(Debug, Clone)]
pub struct WcetViolation {
pub operation: &'static str,
pub elapsed_us: u64,
pub budget_us: u64,
}
impl core::fmt::Display for WcetViolation {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"WCET VIOLATION: {} took {}μs (budget: {}μs)",
self.operation, self.elapsed_us, self.budget_us
)
}
}
impl WcetGuard {
pub fn start(operation: &'static str, budget_us: u64, mode: WcetMode) -> Self {
Self {
operation,
budget_us,
mode,
start: Instant::now(),
}
}
pub fn finish(self) -> Result<WcetResult, WcetViolation> {
let elapsed = self.start.elapsed();
let elapsed_us = elapsed.as_micros() as u64;
if elapsed_us <= self.budget_us {
return Ok(WcetResult::Ok { elapsed_us });
}
match self.mode {
WcetMode::Log => {
println!(
"WCET WARNING: {} took {}μs (budget: {}μs)",
self.operation, elapsed_us, self.budget_us
);
Ok(WcetResult::Violation {
elapsed_us,
budget_us: self.budget_us,
})
}
WcetMode::HardFail => Err(WcetViolation {
operation: self.operation,
elapsed_us,
budget_us: self.budget_us,
}),
}
}
pub fn elapsed_us(&self) -> u64 {
self.start.elapsed().as_micros() as u64
}
}
pub fn timed<F, T>(
operation: &'static str,
budget_us: u64,
mode: WcetMode,
f: F,
) -> Result<(T, WcetResult), WcetViolation>
where
F: FnOnce() -> T,
{
let guard = WcetGuard::start(operation, budget_us, mode);
let result = f();
let wcet = guard.finish()?;
Ok((result, wcet))
}
#[cfg(feature = "std")]
pub fn init_realtime_thread(core_id: Option<usize>) {
#[cfg(feature = "core_affinity")]
if let Some(id) = core_id {
let core_ids = core_affinity::get_core_ids().unwrap_or_default();
if id < core_ids.len() {
if core_affinity::set_for_current(core_ids[id]) {
println!("WCET: Thread pinned to CPU core {}", id);
} else {
eprintln!("WCET WARNING: Failed to pin thread to CPU core {}", id);
}
} else {
eprintln!(
"WCET WARNING: Requested core ID {} exceeds available cores",
id
);
}
}
#[cfg(not(feature = "core_affinity"))]
let _ = core_id;
#[cfg(feature = "thread-priority")]
{
use thread_priority::*;
if let Err(e) = set_current_thread_priority(ThreadPriority::Max) {
eprintln!("WCET WARNING: Failed to set Max thread priority: {:?}", e);
} else {
println!("WCET: Thread priority elevated to Max");
}
}
}