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

nordisk/nornir

examples/code_room_gap_bench.rs

//! Times the wait BETWEEN two members of a cold workspace read — after a
//! member's commit landed, before the next member's first commit begins —
//! while the lake grows. The real consumer (`CodeRoom::consume`) and the real
//! log; synthetic members: a scratch git repo each and a dumper that emits N
//! node rows for it (no nightly driver, no cargo).
//!
//! ```text
//! cargo run --release --no-default-features --features code-room \
//!   --example code_room_gap_bench -- <empty-dir> [scale]
//! ```
//! Rows per member: what each of the 21 nordisk members added in the
//! 2026-10-15 cold read (`rows_plus`), × `scale` (default 1.0). Prints one
//! line per member (its commit, then the gap before the next one) and the
//! totals.

#[cfg(feature = "code-room")]
fn main() -> anyhow::Result<()> {
    use std::collections::BTreeSet;
    use std::path::Path;
    use std::time::Instant;

    use mimir_ingest::{CommitDump, CrateDump, Dumper};
    use mimir_schema::{Level, NodeRow, Origin};
    use nornir::code_room::consumer_loop::{Dumpers, Event, Member, Request};
    use nornir::code_room::{CodeRoom, Layout, Refusal};

    /// The 2026-10-15 cold read: rows each member added, in member order.
    const MEMBERS: [(&str, u64); 21] = [
        ("Skidbladnir", 3129606),
        ("draupnir", 520148),
        ("dwarves", 11819349),
        ("edda", 5436002),
        ("facett", 2503338),
        ("funnel-core", 38113),
        ("gunnar", 9187071),
        ("gunnar-ui", 1421909),
        ("holger", 3509464),
        ("knut", 1379373),
        ("korp", 1516343),
        ("korp-collectors", 127648),
        ("modgunn", 221303),
        ("monetize", 1840052),
        ("nornir", 2807656),
        ("openzl-sys-rs", 51039),
        ("ordning", 194270),
        ("skade", 2322615),
        ("tunnr", 171970),
        ("znippy", 1930345),
        ("znippy-zoomies", 346375),
    ];
    const BATCH: u64 = 1 << 20;

    /// `rows` item nodes of one crate, keys about as long as the driver's.
    struct Synthetic {
        krate: String,
        rows: u64,
    }
    impl Dumper for Synthetic {
        fn dump(&mut self, _: &Path, _: &str) -> anyhow::Result<CommitDump> {
            let k = &self.krate;
            let owner = format!("{k}@0.1.0:lib");
            let mut nodes = Vec::new();
            let mut at = 0;
            while at < self.rows {
                let end = (at + BATCH).min(self.rows);
                let rows: Vec<NodeRow> = (at..end)
                    .map(|i| NodeRow::new(format!("{k} module_{:03}::item_{i:09}", i % 997), "fn", Level::Item, format!("item_{i}"), k.as_str(), "0.1.0", Origin::Local))
                    .collect();
                nodes.push(mimir_schema::nodes_batch(&rows)?);
                at = end;
            }
            Ok(CommitDump {
                toolchain: "nightly-bench".into(),
                workspace_crates: [owner.clone()].into(),
                workspace_targets: [format!("{k}:lib")].into(),
                failed_units: BTreeSet::new(),
                owner_disambiguations: 0,
                crates: vec![CrateDump { krate: owner, universe: false, nodes, edges: vec![mimir_schema::edges_batch(&[])?], spans: vec![] }],
                binary: false,
                binaries: vec![],
            })
        }
    }
    struct Synthetics(Vec<(String, u64)>);
    impl Dumpers for Synthetics {
        fn dumper(&self, _: &Layout, member: &Member) -> Result<Box<dyn Dumper + Send>, Refusal> {
            let rows = self.0.iter().find(|(n, _)| n == &member.name).map_or(0, |(_, r)| *r);
            Ok(Box::new(Synthetic { krate: member.name.replace('-', "_"), rows }))
        }
        fn describe(&self) -> String {
            "synthetic rows (bench)".into()
        }
    }

    let mut args = std::env::args().skip(1);
    let dir = std::path::PathBuf::from(args.next().expect("usage: code_room_gap_bench <empty-dir> [scale]"));
    let scale: f64 = args.next().map(|s| s.parse()).transpose()?.unwrap_or(1.0);
    std::fs::create_dir_all(&dir)?;
    let dir = dir.canonicalize()?;
    let rows: Vec<(String, u64)> = MEMBERS.iter().map(|(n, r)| (n.to_string(), ((*r as f64) * scale).round() as u64)).collect();
    let mut members = Vec::new();
    for (name, _) in &rows {
        let src = dir.join("ws").join("git").join(name);
        nornir::gitio::init(&src)?;
        std::fs::create_dir_all(src.join("src"))?;
        std::fs::write(src.join("src/lib.rs"), format!("// {name}\n"))?;
        let head = nornir::gitio::commit_all(&src, "c")?;
        members.push(Member { name: name.clone(), source: src, branch: None, head });
    }
    let room = CodeRoom::new("ws", &dir.join("builds"));
    let t0 = Instant::now();
    let mut landed: Option<(String, Instant)> = None;
    let mut gaps: Vec<(String, f64)> = Vec::new();
    let mut lake = 0u64;
    let mut on = |e: Event<'_>| match e {
        Event::Member { member, .. } => {
            if let Some((prev, at)) = landed.take() {
                gaps.push((prev.clone(), at.elapsed().as_secs_f64()));
                println!("{:>8.1}s  gap after {prev:<16} {:>7.2} s", t0.elapsed().as_secs_f64(), at.elapsed().as_secs_f64());
            }
            let _ = member;
        }
        Event::Commit { member, report: r } => {
            lake += r.rows_plus as u64;
            println!(
                "{:>8.1}s  {member:<16} commit {:>7} ms (dump {:>6} delta {:>6} commit {:>6})  +{:>9}  lake {:>10} rows",
                t0.elapsed().as_secs_f64(),
                r.ms,
                r.phase_ms.dump,
                r.phase_ms.delta,
                r.phase_ms.commit,
                r.rows_plus,
                lake
            );
            landed = Some((member.to_string(), Instant::now()));
        }
        _ => {}
    };
    let report = room.consume(&Synthetics(rows), &[], &Request { members: &members, ..Default::default() }, &mut on).map_err(|r| anyhow::anyhow!("{}", r.note))?;
    // the last member's commit → the run's end (the same save, nothing after it)
    if let Some((prev, at)) = landed.take() {
        println!("          after the last ({prev}): {:.2} s to the run's end", at.elapsed().as_secs_f64());
    }
    let total: f64 = gaps.iter().map(|(_, g)| g).sum();
    println!(
        "GAPS scale {scale}: after the 1st {:.2} s · after the {}th {:.2} s · total {:.1} s over {} gaps · run {:.1} s · failed members {}",
        gaps.first().map_or(0.0, |g| g.1),
        gaps.len(),
        gaps.last().map_or(0.0, |g| g.1),
        total,
        gaps.len(),
        t0.elapsed().as_secs_f64(),
        report.failed().len()
    );
    Ok(())
}

#[cfg(not(feature = "code-room"))]
fn main() {
    eprintln!("build with --features code-room");
}