//! Probe stage_file size at which the deadlock manifests.

use std::time::{Duration, Instant};
use supermachine::Image;

fn try_size(snap: &str, n: usize) -> Result<Duration, String> {
    let image = Image::from_snapshot(snap).map_err(|e| e.to_string())?;
    let pool = image
        .pool()
        .min(1)
        .max(1)
        .restore_on_release(false)
        .build()
        .map_err(|e| e.to_string())?;
    let vm = pool.acquire().map_err(|e| e.to_string())?;
    let payload: Vec<u8> = (0..n).map(|i| (i % 251) as u8).collect();
    let t0 = Instant::now();
    let path = format!("/tmp/probe_{n}.bin");
    let out = vm
        .exec_builder()
        .stage_file(path.clone(), payload)
        .argv(["wc", "-c", &path].iter().copied())
        .timeout(Duration::from_secs(15))
        .output()
        .map_err(|e| e.to_string())?;
    let elapsed = t0.elapsed();
    if !out.success() {
        return Err(format!("nonzero exit: {}", out.status));
    }
    Ok(elapsed)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let snap = format!(
        "{}/.local/supermachine-snapshots/rust_1_slim",
        std::env::var("HOME")?
    );
    for n in [
        4 * 1024,    // 1 packet
        16 * 1024,   // 4 packets
        64 * 1024,   // 16 packets
        256 * 1024,  // 64 packets
        512 * 1024,  // 128 packets
        768 * 1024,  // 192 packets
        1024 * 1024, // 256 packets
    ] {
        print!("size={:>7} ... ", n);
        match try_size(&snap, n) {
            Ok(d) => println!("OK in {:?}", d),
            Err(e) => {
                println!("ERR: {e}");
                break;
            }
        }
    }
    Ok(())
}
