Skip to main content

midx_lookup_timing/
midx_lookup_timing.rs

1//! Time verified reads of an explicit object list from a repository containing many packs.
2//! Generate the repository and list independently, then run with MIDX enabled and disabled.
3//! Arguments: repository, ID list, rounds, optional mode (`read`, `contains`, `index-scan`,
4//! `midx`). Use separate present/absent lists and roughly 100 packs for lookup-only comparisons.
5//! `midx` checks the parsed MIDX alone; it omits candidate verification and loose/outside-pack
6//! fallback, so compare it to `index-scan` as an index-search microbenchmark, not an end-to-end
7//! guarantee.
8use std::hint::black_box;
9use std::time::Instant;
10
11use girt::{ObjectId, Repository};
12
13fn main() -> Result<(), Box<dyn std::error::Error>> {
14    let mut args = std::env::args().skip(1);
15    let path = args.next().ok_or("expected repository path")?;
16    let list = args.next().ok_or("expected object-ID list path")?;
17    let rounds: usize = args.next().ok_or("expected number of rounds")?.parse()?;
18    let mode = args.next().unwrap_or_else(|| "read".to_owned());
19    let ids = std::fs::read_to_string(list)?
20        .lines()
21        .map(str::parse)
22        .collect::<Result<Vec<ObjectId>, _>>()?;
23    let repo = Repository::open(path)?;
24    let start = Instant::now();
25    let objects = repo.objects()?;
26    let opening = start.elapsed();
27    let packs: Vec<_> = objects.packs().collect();
28    let bytes = if mode == "midx" {
29        std::fs::read(repo.object_dir().join("pack/multi-pack-index"))?
30    } else {
31        Vec::new()
32    };
33    let midx = if mode == "midx" {
34        Some(girt::multi_pack_index::MultiPackIndex::parse(
35            &bytes,
36            repo.object_format(),
37        )?)
38    } else {
39        None
40    };
41    let start = Instant::now();
42    let mut found = 0_usize;
43    for _ in 0..rounds {
44        for id in &ids {
45            let present = match mode.as_str() {
46                "read" => {
47                    black_box(objects.read(*id)?.ok_or("object absent")?);
48                    true
49                }
50                "contains" => objects.contains(*id)?,
51                "index-scan" => scan(&packs, *id)?,
52                "midx" => midx.as_ref().ok_or("index absent")?.find(*id).is_some(),
53                _ => return Err("expected read, contains, index-scan or midx".into()),
54            };
55            found += usize::from(black_box(present));
56        }
57    }
58    println!(
59        "objects={} rounds={rounds} mode={mode} found={found} open_ns={} read_ns={}",
60        ids.len(),
61        opening.as_nanos(),
62        start.elapsed().as_nanos(),
63    );
64    Ok(())
65}
66
67fn scan(packs: &[girt::IndexedPack<'_>], id: ObjectId) -> Result<bool, girt::ObjectReadError> {
68    for pack in packs {
69        if pack.contains(id)? {
70            return Ok(true);
71        }
72    }
73    Ok(false)
74}