supermachine 0.7.105

Run any OCI/Docker image as a hardware-isolated microVM on macOS HVF (Linux KVM and Windows WHP in progress). Single library API, zero flags for the common case, sub-100 ms cold-restore from snapshot.
Documentation
#[cfg(any(
    all(target_os = "linux", target_arch = "x86_64"),
    all(target_os = "macos", target_arch = "aarch64")
))]
mod supported {
    //! Generate a flame graph from supermachine's tracing spans.
    //!
    //! Wires the `tracing-flame` subscriber to write a folded-stack
    //! file. After the run, convert it to SVG with `inferno-flamegraph`:
    //!
    //! ```sh
    //! cargo install inferno
    //! cargo run --release --example _flame_graph
    //! inferno-flamegraph < /tmp/supermachine-flame.folded > /tmp/flame.svg
    //! open /tmp/flame.svg
    //! ```
    //!
    //! The flame graph shows where wall-clock time is spent across
    //! the bake / acquire / snapshot / exec phases. Useful for
    //! integrators wanting to see where their workload's
    //! supermachine-side time goes (vs the rustc-side or Anthropic-API-
    //! side time, which is in their own code).
    //!
    //! What the spans look like:
    //!
    //!   supermachine.bake_pipelined (image=rust:1-slim, …)
    //!     ├─ supermachine.acquire (during warmup callback)
    //!     │   ├─ supermachine.exec (argv0=rustc, argc=4)
    //!     │   └─ supermachine.exec (argv0=/tmp/seed, argc=1)
    //!     └─ … snapshot capture / save phases ...
    //!
    //!   supermachine.pool.acquire (memory_mib=2048, vcpus=1)
    //!   supermachine.exec (argv0=sh, argc=3)
    //!   supermachine.snapshot (dest_dir=/tmp/...)

    use std::io::Read;
    use std::time::Duration;
    use supermachine::Image;
    use tracing_flame::FlameLayer;
    use tracing_subscriber::prelude::*;

    pub(super) fn main() -> Result<(), Box<dyn std::error::Error>> {
        let flame_path = std::env::var("SUPERMACHINE_FLAME_OUT")
            .unwrap_or_else(|_| "/tmp/supermachine-flame.folded".to_owned());
        eprintln!("[flame] writing folded stacks → {flame_path}");

        let (flame_layer, _guard) = FlameLayer::with_file(&flame_path)?;
        tracing_subscriber::registry().with(flame_layer).init();

        // Bake — emits `supermachine.bake_pipelined` span and nested
        // acquire/exec spans from the warmup callback.
        let image = Image::builder("rust:1-slim")
            .with_name("rust_1_slim_flame")
            .with_memory_mib(2048)
            .with_warmup(|vm| {
                vm.exec_builder()
                    .stage_file(
                        "/tmp/seed.rs",
                        b"fn main() { println!(\"flame\"); }".to_vec(),
                    )
                    .argv(["rustc", "-O", "/tmp/seed.rs", "-o", "/tmp/seed"])
                    .chain(["/tmp/seed"])
                    .timeout(Duration::from_secs(60))
                    .output()?;
                Ok(())
            })
            .with_warmup_tag("flame_v1")
            .build()?;

        // Pool build + a few acquire/exec cycles — emits
        // `supermachine.pool.acquire` and `supermachine.exec` spans
        // per cycle.
        let pool = image
            .pool()
            .min(2)
            .max(2)
            .restore_on_release(false)
            .build()?;

        for i in 0..5 {
            let vm = pool.acquire()?;
            let mut child = vm.exec(["sh", "-c", &format!("echo cycle-{i}")])?;
            let mut buf = String::new();
            if let Some(mut stdout) = child.stdout() {
                let _ = stdout.read_to_string(&mut buf);
            }
            let _ = buf; // discard; we just want the spans
            let _ = child.wait();
        }

        // Drop the _guard explicitly so the folded file is flushed
        // before main exits. The subscriber writes incrementally;
        // missing flush leaves a truncated file.
        drop(_guard);

        eprintln!(
            "[flame] done. Convert with:\n  inferno-flamegraph < {flame_path} > /tmp/flame.svg"
        );
        Ok(())
    }
}

#[cfg(any(
    all(target_os = "linux", target_arch = "x86_64"),
    all(target_os = "macos", target_arch = "aarch64")
))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    supported::main()
}

#[cfg(not(any(
    all(target_os = "linux", target_arch = "x86_64"),
    all(target_os = "macos", target_arch = "aarch64")
)))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    eprintln!("this example requires a linux-x86_64 (KVM) or macos-aarch64 (HVF) host; unsupported on this platform");
    Ok(())
}