⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/perf/
bench.rs

1//! In-kernel micro-benchmark suite for Phase 5 performance validation.
2//!
3//! Measures latency of core kernel operations and compares against Phase 5
4//! performance targets. Accessible via the "perf" shell builtin.
5
6#![allow(dead_code)]
7
8use crate::bench::{black_box, cycles_to_ns, read_timestamp};
9
10/// Phase 5 performance targets (nanoseconds, x86_64 with KVM)
11pub(crate) const TARGET_SYSCALL_NS: u64 = 500;
12pub(crate) const TARGET_CONTEXT_SWITCH_NS: u64 = 10_000;
13pub(crate) const TARGET_IPC_SMALL_NS: u64 = 1_000;
14pub(crate) const TARGET_FRAME_ALLOC_NS: u64 = 2000;
15pub(crate) const TARGET_CAP_LOOKUP_NS: u64 = 100;
16
17/// Individual benchmark result
18pub(crate) struct BenchResult {
19    pub(crate) name: &'static str,
20    pub(crate) iterations: u64,
21    pub(crate) min_ns: u64,
22    pub(crate) avg_ns: u64,
23    pub(crate) max_ns: u64,
24    pub(crate) target_ns: u64,
25}
26
27impl BenchResult {
28    pub(crate) fn meets_target(&self) -> bool {
29        self.avg_ns <= self.target_ns
30    }
31}
32
33/// Run a micro-benchmark: execute `f` for `iterations`, return min/avg/max.
34fn run_bench<F: FnMut()>(
35    name: &'static str,
36    iterations: u64,
37    target_ns: u64,
38    mut f: F,
39) -> BenchResult {
40    // Warmup
41    for _ in 0..10 {
42        f();
43    }
44
45    let mut min = u64::MAX;
46    let mut max = 0u64;
47    let mut total = 0u64;
48
49    for _ in 0..iterations {
50        let start = read_timestamp();
51        f();
52        let elapsed = read_timestamp().saturating_sub(start);
53        let ns = cycles_to_ns(elapsed);
54        if ns < min {
55            min = ns;
56        }
57        if ns > max {
58            max = ns;
59        }
60        total += ns;
61    }
62
63    BenchResult {
64        name,
65        iterations,
66        min_ns: min,
67        avg_ns: total / iterations,
68        max_ns: max,
69        target_ns,
70    }
71}
72
73/// Benchmark: sys_getpid() round-trip (minimal syscall overhead)
74fn bench_syscall_latency() -> BenchResult {
75    run_bench("syscall_getpid", 1000, TARGET_SYSCALL_NS, || {
76        let pid = crate::sched::current_process_id();
77        black_box(pid);
78    })
79}
80
81/// Benchmark: frame allocator single-frame alloc+free
82fn bench_frame_alloc() -> BenchResult {
83    run_bench("frame_alloc_1", 1000, TARGET_FRAME_ALLOC_NS, || {
84        // Use per-CPU cache path for single frames
85        if let Ok(frame) = crate::mm::frame_allocator::per_cpu_alloc_frame() {
86            let _ = crate::mm::frame_allocator::per_cpu_free_frame(frame);
87        }
88    })
89}
90
91/// Benchmark: frame allocator via global path (for comparison)
92fn bench_frame_alloc_global() -> BenchResult {
93    use crate::mm::FRAME_ALLOCATOR;
94    run_bench(
95        "frame_alloc_global",
96        1000,
97        TARGET_FRAME_ALLOC_NS * 2,
98        || {
99            let alloc = FRAME_ALLOCATOR.lock();
100            if let Ok(frame) = alloc.allocate_frames(1, None) {
101                let _ = alloc.free_frames(frame, 1);
102            }
103        },
104    )
105}
106
107/// Benchmark: capability range validation (fast path)
108fn bench_capability_lookup() -> BenchResult {
109    run_bench("cap_validate", 1000, TARGET_CAP_LOOKUP_NS, || {
110        // Fast-path validation as done in IPC
111        let cap = black_box(42u64);
112        let valid = cap != 0 && cap < 0x1_0000_0000;
113        black_box(valid);
114    })
115}
116
117/// Benchmark: perf counter increment (atomic operation baseline)
118fn bench_atomic_counter() -> BenchResult {
119    use core::sync::atomic::{AtomicU64, Ordering};
120    static COUNTER: AtomicU64 = AtomicU64::new(0);
121
122    run_bench("atomic_counter", 1000, 50, || {
123        COUNTER.fetch_add(1, Ordering::Relaxed);
124    })
125}
126
127/// Benchmark: IPC fast path stats read (lightweight)
128fn bench_ipc_stats() -> BenchResult {
129    run_bench("ipc_stats_read", 1000, TARGET_CAP_LOOKUP_NS, || {
130        let stats = crate::ipc::fast_path::get_fast_path_stats();
131        black_box(stats);
132    })
133}
134
135/// Benchmark: scheduler current task lookup
136fn bench_sched_current() -> BenchResult {
137    run_bench("sched_current", 1000, 200, || {
138        let sched = crate::sched::scheduler::SCHEDULER.lock();
139        let current = sched.current();
140        black_box(current);
141    })
142}
143
144/// Run all benchmarks and print results.
145pub(crate) fn run_all_benchmarks() {
146    crate::println!("=== VeridianOS Phase 5 Performance Benchmarks ===");
147    crate::println!();
148    crate::println!(
149        "{:<20} {:>8} {:>8} {:>8} {:>8} {:>6}",
150        "Benchmark",
151        "Min(ns)",
152        "Avg(ns)",
153        "Max(ns)",
154        "Target",
155        "Pass?"
156    );
157    crate::println!("{}", "-".repeat(68));
158
159    let benchmarks = [
160        bench_syscall_latency(),
161        bench_frame_alloc(),
162        bench_frame_alloc_global(),
163        bench_capability_lookup(),
164        bench_atomic_counter(),
165        bench_ipc_stats(),
166        bench_sched_current(),
167    ];
168
169    let mut passed = 0;
170    let total = benchmarks.len();
171
172    for result in &benchmarks {
173        let status = if result.meets_target() {
174            passed += 1;
175            "PASS"
176        } else {
177            "FAIL"
178        };
179        crate::println!(
180            "{:<20} {:>8} {:>8} {:>8} {:>8} {:>6}",
181            result.name,
182            result.min_ns,
183            result.avg_ns,
184            result.max_ns,
185            result.target_ns,
186            status
187        );
188    }
189
190    crate::println!("{}", "-".repeat(68));
191    crate::println!(
192        "Results: {}/{} benchmarks meet Phase 5 targets",
193        passed,
194        total
195    );
196
197    // Also show IPC fast path stats
198    let (fast_count, fast_avg) = crate::ipc::fast_path::get_fast_path_stats();
199    let slow_count = crate::ipc::fast_path::get_slow_path_count();
200    crate::println!();
201    crate::println!("IPC Statistics:");
202    crate::println!("  Fast path: {} calls, {} avg cycles", fast_count, fast_avg);
203    crate::println!("  Slow path fallbacks: {}", slow_count);
204
205    // Show trace stats if tracing is enabled
206    if crate::perf::trace::is_enabled() {
207        crate::println!(
208            "  Trace events: {} total",
209            crate::perf::trace::total_events()
210        );
211    }
212
213    crate::println!();
214}