Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

bench/examples/advertise-probe.rs

//! **`ls-refs` cost against ref count, on a real store.**
//!
//! Point it at a directory holding the prepared znippy stores
//! `repo<N>.git.gunnar-znippy` for a ladder of ref counts (the fixture builder
//! makes 40 / 400 / 4000 refs). It opens each store once and
//! times one `command=ls-refs` with `peel`, printing wall µs/ref and the
//! op-count that is the real red: `reads`, the full exploded-table pulls one
//! advertisement makes, which is `advertise_from` re-peeling every annotated tag
//! every time. The timing driver is `gunnar_bench::advertise::probe`, kept in
//! the library so a persisted `gunnar.advertise_*` arm reuses it, not a twin.
//!
//! ```text
//! GUNNAR_ENGINE=znippy cargo run --release --example advertise-probe \
//!     --manifest-path bench/Cargo.toml -- <fixtures-dir> [sha1|sha256]
//! ```
//!
//! A diagnostic, its own target for the reason `readside-probe` is: a table a
//! human reads once, not a `BenchRun` row. The 1-minute load is printed beside
//! the numbers so a contaminated run is visible: load < 3 or it is not a
//! measurement.

use std::path::PathBuf;

use anyhow::{bail, Context, Result};

fn one_min_load() -> f64 {
    std::fs::read_to_string("/proc/loadavg")
        .ok()
        .and_then(|s| s.split_whitespace().next().map(|t| t.to_owned()))
        .and_then(|t| t.parse().ok())
        .unwrap_or(f64::NAN)
}

fn main() -> Result<()> {
    let mut args = std::env::args().skip(1);
    let dir = PathBuf::from(
        args.next()
            .context("usage: advertise-probe <fixtures-dir> [sha1|sha256] [N,N,...]")?,
    );
    let kind = match args.next().as_deref() {
        None | Some("sha256") => gix_hash::Kind::Sha256,
        Some("sha1") => gix_hash::Kind::Sha1,
        Some(other) => bail!("unknown hash kind {other:?}"),
    };
    let counts: Vec<u32> = match args.next() {
        Some(list) => list
            .split(',')
            .map(|s| s.trim().parse().context("ref count"))
            .collect::<Result<_>>()?,
        None => vec![40, 400, 4000],
    };

    let load_before = one_min_load();
    println!(
        "# advertise-probe  engine={:?}  1-min load at start = {load_before:.2}",
        std::env::var("GUNNAR_ENGINE").unwrap_or_else(|_| "<default>".into())
    );
    if load_before >= 3.0 {
        eprintln!(
            "WARNING: 1-min load {load_before:.2} >= 3 — this is NOT a measurement. \
             Numbers below are for shape only; do not record them."
        );
    }
    println!(
        "{:>5} {:>7} {:>7} {:>8} {:>12} {:>10} {:>8} {:>8}",
        "mode", "refs", "peeled", "reads", "wall_us", "us/ref", "reads/r", "headers"
    );

    let mut row = |mode: &str, a: &gunnar_bench::advertise::Advertisement| {
        println!(
            "{:>5} {:>7} {:>7} {:>8} {:>12.1} {:>10.3} {:>8.2} {:>8}",
            mode,
            a.refs_held,
            a.peeled_lines,
            a.reads,
            a.best_wall_ns as f64 / 1000.0,
            a.us_per_ref(),
            a.reads_per_ref(),
            a.headers,
        );
    };

    for n in counts {
        let store = dir.join(format!("repo{n}.git.gunnar-znippy"));
        if !store.is_dir() {
            eprintln!("skip: {} is not a prepared store", store.display());
            continue;
        }
        let warm = gunnar_bench::advertise::probe(&store, kind, 3, 5)
            .with_context(|| format!("probing (warm) {}", store.display()))?;
        row("warm", &warm);
        // `cold`: page cache dropped before each run — the appliance's
        // cache-pressured regime, where each exploded read is a real batch decode.
        let cold = gunnar_bench::advertise::probe_cold(&store, kind, 4)
            .with_context(|| format!("probing (cold) {}", store.display()))?;
        row("cold", &cold);
    }
    let load_after = one_min_load();
    println!("# 1-min load at end = {load_after:.2}");
    if load_before >= 3.0 || load_after >= 3.0 {
        println!("# CONTAMINATED (load >= 3 at some point) — shape only, not for bench_history.");
    }
    Ok(())
}