veridian_kernel/ipc/
perf.rs1use core::sync::atomic::{AtomicU64, Ordering};
9
10use crate::arch::entropy::read_timestamp;
11
12pub struct IpcPerfStats {
14 pub total_ops: AtomicU64,
16 pub total_cycles: AtomicU64,
18 pub min_latency: AtomicU64,
20 pub max_latency: AtomicU64,
22 pub fast_path_count: AtomicU64,
24 pub slow_path_count: AtomicU64,
26}
27
28impl IpcPerfStats {
29 pub const fn new() -> Self {
30 Self {
31 total_ops: AtomicU64::new(0),
32 total_cycles: AtomicU64::new(0),
33 min_latency: AtomicU64::new(u64::MAX),
34 max_latency: AtomicU64::new(0),
35 fast_path_count: AtomicU64::new(0),
36 slow_path_count: AtomicU64::new(0),
37 }
38 }
39
40 pub fn record_operation(&self, cycles: u64, is_fast_path: bool) {
42 self.total_ops.fetch_add(1, Ordering::Relaxed);
43 self.total_cycles.fetch_add(cycles, Ordering::Relaxed);
44
45 let mut current_min = self.min_latency.load(Ordering::Relaxed);
47 while cycles < current_min {
48 match self.min_latency.compare_exchange_weak(
49 current_min,
50 cycles,
51 Ordering::Relaxed,
52 Ordering::Relaxed,
53 ) {
54 Ok(_) => break,
55 Err(val) => current_min = val,
56 }
57 }
58
59 let mut current_max = self.max_latency.load(Ordering::Relaxed);
61 while cycles > current_max {
62 match self.max_latency.compare_exchange_weak(
63 current_max,
64 cycles,
65 Ordering::Relaxed,
66 Ordering::Relaxed,
67 ) {
68 Ok(_) => break,
69 Err(val) => current_max = val,
70 }
71 }
72
73 if is_fast_path {
75 self.fast_path_count.fetch_add(1, Ordering::Relaxed);
76 } else {
77 self.slow_path_count.fetch_add(1, Ordering::Relaxed);
78 }
79 }
80
81 pub fn average_latency(&self) -> u64 {
83 let ops = self.total_ops.load(Ordering::Relaxed);
84 let cycles = self.total_cycles.load(Ordering::Relaxed);
85 if ops > 0 {
86 cycles / ops
87 } else {
88 0
89 }
90 }
91
92 pub fn get_report(&self) -> IpcPerfReport {
94 let total_ops = self.total_ops.load(Ordering::Relaxed);
95 let fast_path = self.fast_path_count.load(Ordering::Relaxed);
96 let _slow_path = self.slow_path_count.load(Ordering::Relaxed);
97
98 IpcPerfReport {
99 total_operations: total_ops,
100 average_latency_cycles: self.average_latency(),
101 min_latency_cycles: self.min_latency.load(Ordering::Relaxed),
102 max_latency_cycles: self.max_latency.load(Ordering::Relaxed),
103 fast_path_percentage: if total_ops > 0 {
104 (fast_path * 100) / total_ops
105 } else {
106 0
107 },
108 average_latency_ns: cycles_to_ns(self.average_latency()),
109 min_latency_ns: cycles_to_ns(self.min_latency.load(Ordering::Relaxed)),
110 max_latency_ns: cycles_to_ns(self.max_latency.load(Ordering::Relaxed)),
111 }
112 }
113}
114
115impl Default for IpcPerfStats {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121pub(crate) static IPC_PERF_STATS: IpcPerfStats = IpcPerfStats::new();
123
124#[derive(Debug, Clone, Copy)]
126pub struct IpcPerfReport {
127 pub total_operations: u64,
128 pub average_latency_cycles: u64,
129 pub min_latency_cycles: u64,
130 pub max_latency_cycles: u64,
131 pub fast_path_percentage: u64,
132 pub average_latency_ns: u64,
133 pub min_latency_ns: u64,
134 pub max_latency_ns: u64,
135}
136
137impl IpcPerfReport {
138 pub fn meets_phase1_targets(&self) -> bool {
140 self.average_latency_ns < 5000 && self.max_latency_ns < 10000
142 }
143
144 pub fn meets_phase5_targets(&self) -> bool {
146 self.average_latency_ns < 1000
148 }
149
150 pub fn print(&self) {
152 println!("\n=== IPC Performance Report ===");
153 println!("Total operations: {}", self.total_operations);
154 println!("Fast path usage: {}%", self.fast_path_percentage);
155 println!("\nLatency (cycles):");
156 println!(" Average: {}", self.average_latency_cycles);
157 println!(" Min: {}", self.min_latency_cycles);
158 println!(" Max: {}", self.max_latency_cycles);
159 println!("\nLatency (nanoseconds):");
160 println!(" Average: {} ns", self.average_latency_ns);
161 println!(" Min: {} ns", self.min_latency_ns);
162 println!(" Max: {} ns", self.max_latency_ns);
163
164 let _phase1_status = if self.meets_phase1_targets() {
165 "\n[PASS] Meets Phase 1 targets (<5us)"
166 } else {
167 "\n[FAIL] Does not meet Phase 1 targets"
168 };
169 println!("{}", _phase1_status);
170
171 let _phase5_status = if self.meets_phase5_targets() {
172 "[PASS] Meets Phase 5 targets (<1us average)"
173 } else {
174 "[FAIL] Does not meet Phase 5 targets"
175 };
176 println!("{}", _phase5_status);
177 }
178}
179
180pub fn cycles_to_ns(cycles: u64) -> u64 {
182 cycles / 2
185}
186
187#[inline(always)]
189pub fn measure_ipc_operation<F, R>(f: F) -> (R, u64)
190where
191 F: FnOnce() -> R,
192{
193 let start = read_timestamp();
194 let result = f();
195 let elapsed = read_timestamp() - start;
196 (result, elapsed)
197}
198
199pub mod bench {
201 use super::*;
202
203 pub fn run_perf_test<F>(name: &str, iterations: usize, mut f: F)
205 where
206 F: FnMut(),
207 {
208 kprintln!("\nRunning performance test:");
209 kprint_rt!(name);
210 kprintln!();
211
212 for _ in 0..10 {
214 f();
215 }
216
217 let start = read_timestamp();
219 for _ in 0..iterations {
220 f();
221 }
222 let total_cycles = read_timestamp() - start;
223 let avg_cycles = total_cycles / iterations as u64;
224
225 let avg_ns = cycles_to_ns(avg_cycles);
226
227 kprintln!(" Iterations:");
228 kprint_u64!(iterations);
229 kprintln!();
230 kprintln!(" Average cycles:");
231 kprint_u64!(avg_cycles);
232 kprintln!();
233 kprintln!(" Average ns:");
234 kprint_u64!(avg_ns);
235 kprintln!();
236
237 if avg_ns < 1000 {
238 kprintln!(" Sub-microsecond performance!");
239 }
240 }
241
242 pub fn measure_throughput<F>(name: &str, duration_ms: u64, mut f: F) -> u64
244 where
245 F: FnMut(),
246 {
247 kprintln!("\nMeasuring throughput:");
248 kprint_rt!(name);
249 kprintln!();
250
251 let duration_cycles = duration_ms * 2_000_000; let start = read_timestamp();
253 let mut operations = 0u64;
254
255 while read_timestamp() - start < duration_cycles {
256 f();
257 operations += 1;
258 }
259
260 let actual_duration_ms = cycles_to_ns(read_timestamp() - start) / 1_000_000;
261
262 kprintln!(" Operations:");
263 kprint_u64!(operations);
264 kprintln!();
265 kprintln!(" Duration ms:");
266 kprint_u64!(actual_duration_ms);
267 kprintln!();
268
269 (operations * 1000) / actual_duration_ms
270 }
271}