#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
fn main() {
eprintln!("_kvm_warm_bench: Linux/x86_64 (KVM) only");
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
use std::time::{Duration, Instant};
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
use supermachine::{Image, VmConfig};
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let home = std::env::var("HOME")?;
let base = format!("{home}/.local/supermachine-snapshots/nginx_1v");
eprintln!("=== KVM warm-restore bench (base cold image: {base}) ===");
let cold = Image::from_snapshot(&base)?;
let vm = cold.start(&VmConfig::new())?;
std::thread::sleep(Duration::from_secs(6)); let snap_dir = std::env::temp_dir().join("sm-warm-bench-snap");
let _ = std::fs::remove_dir_all(&snap_dir);
let t_snap = Instant::now();
let warm = vm.snapshot(&snap_dir)?; eprintln!("snapshot capture+save: {} ms", t_snap.elapsed().as_millis());
drop(warm);
let n = 10;
let mut times = Vec::with_capacity(n);
let mut teardowns = Vec::with_capacity(n);
for i in 0..n {
let img = Image::from_snapshot(&snap_dir)?;
let t0 = Instant::now();
let vm = img.start(&VmConfig::new())?;
let us = t0.elapsed().as_micros() as u64;
times.push(us);
let t_drop = Instant::now();
drop(vm);
let drop_us = t_drop.elapsed().as_micros() as u64;
teardowns.push(drop_us);
eprintln!(
" restore {i}: {:.2} ms teardown: {:.3} ms",
us as f64 / 1000.0,
drop_us as f64 / 1000.0
);
std::thread::sleep(Duration::from_millis(150));
}
times.sort();
teardowns.sort();
let median = times[times.len() / 2];
let p95 = times[(times.len() as f64 * 0.95) as usize % times.len()];
let td_median = teardowns[teardowns.len() / 2];
let td_max = *teardowns.last().unwrap();
eprintln!(
"\nKVM warm-restore: median {:.2} ms p95 {:.2} ms (n={n})",
median as f64 / 1000.0,
p95 as f64 / 1000.0
);
eprintln!(
"KVM teardown: median {:.3} ms max {:.3} ms (n={n})",
td_median as f64 / 1000.0,
td_max as f64 / 1000.0
);
Ok(())
}