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

nordisk/nornir

src/mimir_lens/benchcov.rs

//! **BENCH coverage — the un-benched hot paths.** The model is dwarves'
//! (`dwarves/crates/dwarves/src/coverage/benchcov.rs`).
//!
//! `Gap_bench = HotPaths − Benched − Allowlist`. Hot paths are ranked from fan-in
//! (call sites arriving at a module's functions, from the code room) × churn
//! (`git_heat_facts`) × perf-name hint × test coverage; a module with no matching
//! `bench_results` arm is the gap L3 says must not exist. A repo with zero bench
//! runs reads as NEVER BENCHED, never as a clean bill.

use std::collections::{BTreeMap, BTreeSet};

use edda_autonom::{BencherRow, Gap, benchers, compute_gap, covered_benchers};
use serde::{Deserialize, Serialize};

use super::rows::{BenchResultFact, BenchRunFact, GitHeatFact};

/// Module/crate name fragments that mark a perf-sensitive path.
pub const PERF_MODULE_HINTS: &[&str] = &[
    "alloc",
    "batch",
    "buffer",
    "cache",
    "chunk",
    "codec",
    "compress",
    "decode",
    "decompress",
    "encode",
    "hash",
    "index",
    "parse",
    "pack",
    "scan",
    "search",
    "serde",
    "serialize",
    "sort",
    "stream",
    "unpack",
    "vector",
    "zstd",
];

pub const W_FAN_IN: f64 = 0.40;
pub const W_CHURN: f64 = 0.25;
pub const W_HINT: f64 = 0.10;
pub const W_COVERAGE: f64 = 0.25;

/// One module ranked as a hot path, with the evidence for the ranking.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HotPath {
    pub repo: String,
    pub module: String,
    pub surface_id: String,
    pub fan_in: u32,
    pub commits_90d: u64,
    pub hint: Option<String>,
    pub test_coverage: f64,
    pub score: f64,
    pub bench_ids: Vec<String>,
}

impl HotPath {
    pub fn is_benched(&self) -> bool {
        !self.bench_ids.is_empty()
    }
}

/// The per-repo bench-coverage verdict.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RepoBenchCoverage {
    pub repo: String,
    pub hot_paths: usize,
    pub benched: usize,
    pub allowlisted: usize,
    pub unbenched: usize,
    pub bench_arms: usize,
    pub bench_runs: usize,
    pub worst: Vec<HotPath>,
}

impl RepoBenchCoverage {
    pub fn never_benched(&self) -> bool {
        self.bench_runs == 0
    }
    pub fn benched_frac(&self) -> f64 {
        if self.hot_paths == 0 {
            return 0.0;
        }
        self.benched as f64 / self.hot_paths as f64
    }
}

/// What the code room knows about one module of a repo.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ModuleFacts {
    /// The module's path (`znippy::decode`; the crate name for the root).
    pub module: String,
    /// CALLS sites arriving at the module's functions.
    pub fan_in: u32,
    /// The files its items lie in.
    pub files: BTreeSet<String>,
    /// `fn` + `method` items defined in it.
    pub fns_total: u32,
    /// Of those, the ones in the test-reachable set.
    pub fns_covered: u32,
}

/// **Is this module a TEST module?** Test/bench harness modules are excluded from
/// the bench surface entirely.
pub fn is_test_module(module: &str) -> bool {
    module.split("::").any(|seg| {
        let s = seg.to_ascii_lowercase();
        s == "tests" || s == "test" || s.ends_with("_tests") || s.starts_with("test_")
    }) || module.to_ascii_lowercase().contains("::benches")
}

/// Structural tokens carrying no scenario meaning — excluded from both sides of
/// [`arm_covers_module`].
pub const STOP_TOKENS: &[&str] = &[
    "all", "bench", "common", "core", "crate", "demo", "error", "full", "get", "impl", "lib",
    "main", "mod", "new", "real", "run", "set", "test", "tests", "type", "types", "util", "utils",
];

const MIN_TOKEN: usize = 3;

/// **Does bench arm `arm` cover module `module`?**
pub fn arm_covers_module(repo: &str, arm: &str, module: &str) -> bool {
    let repo_lc = repo.to_ascii_lowercase();
    let repo_parts: BTreeSet<&str> = repo_lc
        .split(|c: char| !c.is_ascii_alphanumeric())
        .collect();
    let tokens = |s: &'_ str| -> BTreeSet<String> {
        s.split(|c: char| !c.is_ascii_alphanumeric())
            .filter(|t| t.len() >= MIN_TOKEN && !STOP_TOKENS.contains(t) && !repo_parts.contains(t))
            .map(str::to_string)
            .collect()
    };
    let scenario = arm
        .split_once('.')
        .map(|(_, s)| s)
        .unwrap_or(arm)
        .to_ascii_lowercase();
    let arm_tokens = tokens(&scenario);
    if arm_tokens.is_empty() {
        return false;
    }
    let module_lc = module.to_ascii_lowercase();
    arm_tokens
        .intersection(&tokens(&module_lc))
        .next()
        .is_some()
}

/// Which perf hint (if any) fires for a module name.
pub fn perf_hint(module: &str) -> Option<String> {
    let m = module.to_ascii_lowercase();
    PERF_MODULE_HINTS
        .iter()
        .find(|h| m.contains(*h))
        .map(|h| (*h).to_string())
}

/// **Rank a repo's modules as hot paths and mark which carry a bench.**
pub fn hot_paths(repo: &str, modules: &[ModuleFacts], heat: &[GitHeatFact], arms: &BTreeSet<String>, top_n: usize) -> Vec<HotPath> {
    // test / bench harness modules are not part of the bench surface
    let modules: Vec<&ModuleFacts> = modules.iter().filter(|m| !is_test_module(&m.module)).collect();
    let heat_by_file: BTreeMap<&str, u64> = heat.iter().map(|h| (h.file.as_str(), h.commits_90d)).collect();
    let churn = |m: &ModuleFacts| -> u64 { m.files.iter().filter_map(|f| heat_by_file.get(f.as_str())).sum() };
    let coverage_of = |m: &ModuleFacts| -> f64 {
        match m.fns_total {
            0 => 0.0,
            t => m.fns_covered.min(t) as f64 / t as f64,
        }
    };

    let max_fan = modules.iter().map(|m| m.fan_in).max().unwrap_or(0).max(1) as f64;
    let max_churn = modules.iter().map(|m| churn(m)).max().unwrap_or(0).max(1) as f64;

    let mut out: Vec<HotPath> = modules
        .iter()
        .map(|m| {
            let f = m.fan_in;
            let c = churn(m);
            let hint = perf_hint(&m.module);
            let cov = coverage_of(m);
            let score = W_FAN_IN * (f as f64 / max_fan)
                + W_CHURN * (c as f64 / max_churn)
                + W_COVERAGE * cov
                + if hint.is_some() { W_HINT } else { 0.0 };
            let bench_ids: Vec<String> = arms.iter().filter(|a| arm_covers_module(repo, a, &m.module)).cloned().collect();
            HotPath {
                repo: repo.to_string(),
                module: m.module.clone(),
                surface_id: format!("{repo}.{}", m.module),
                fan_in: f,
                commits_90d: c,
                hint,
                test_coverage: cov,
                score,
                bench_ids,
            }
        })
        .collect();
    out.sort_by(|a, b| {
        b.score
            .partial_cmp(&a.score)
            .unwrap_or(std::cmp::Ordering::Equal)
            .then_with(|| a.module.cmp(&b.module))
    });
    out.truncate(top_n);
    out
}

/// **The per-repo bench-coverage verdict**, computed through autonom's gate.
pub fn repo_bench_coverage(
    repo: &str,
    modules: &[ModuleFacts],
    heat: &[GitHeatFact],
    runs: &[BenchRunFact],
    results: &[BenchResultFact],
    allowlist: &BTreeSet<String>,
    top_n: usize,
) -> RepoBenchCoverage {
    let run_ids: BTreeSet<&str> = runs
        .iter()
        .filter(|r| r.repo == repo)
        .map(|r| r.run_id.as_str())
        .collect();
    let arms: BTreeSet<String> = results
        .iter()
        .filter(|r| run_ids.contains(r.run_id.as_str()))
        .map(|r| r.result_name.clone())
        .collect();

    let hot = hot_paths(repo, modules, heat, &arms, top_n);

    let bench_rows: Vec<BencherRow> = hot
        .iter()
        .map(|h| BencherRow {
            module: h.surface_id.clone(),
            has_bencher: h.is_benched(),
            bench_ids: h.bench_ids.clone(),
        })
        .collect();
    let mut surface = edda_autonom::Surface::new();
    surface.extend(benchers(&bench_rows));
    let gap: Gap = compute_gap(&surface, &covered_benchers(&bench_rows), allowlist);

    let worst: Vec<HotPath> = hot.iter().filter(|h| !h.is_benched()).cloned().collect();

    RepoBenchCoverage {
        repo: repo.to_string(),
        hot_paths: gap.total,
        benched: gap.covered,
        allowlisted: gap.allowlisted.len(),
        unbenched: gap.missing.len(),
        bench_arms: arms.len(),
        bench_runs: run_ids.len(),
        worst,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn module(path: &str, fan_in: u32) -> ModuleFacts {
        ModuleFacts { module: path.into(), fan_in, files: [format!("{path}.rs")].into(), fns_total: 1, fns_covered: 0 }
    }
    fn run(repo: &str, id: &str, machine: &str) -> BenchRunFact {
        BenchRunFact {
            run_id: id.into(),
            repo: repo.into(),
            ts_micros: 1,
            date: "2026-07-22".into(),
            version: "0.1.0".into(),
            machine: machine.into(),
            cores: 32,
            ..Default::default()
        }
    }
    fn result(run_id: &str, arm: &str) -> BenchResultFact {
        BenchResultFact {
            run_id: run_id.into(),
            result_name: arm.into(),
            metric_name: "ms".into(),
            metric_value: 1.0,
        }
    }

    #[test]
    fn arm_covers_the_module_its_scenario_names_and_no_other() {
        assert!(arm_covers_module(
            "znippy",
            "znippy.decode_mt",
            "znippy::decode"
        ));
        assert!(!arm_covers_module(
            "znippy",
            "znippy.decode_mt",
            "znippy::vault"
        ));
        assert!(!arm_covers_module(
            "skade",
            "osm_ingest_skade_ram",
            "skade::catalog"
        ));
    }

    #[test]
    fn a_repo_that_was_never_benched_reads_as_never_benched_not_as_clean() {
        let modules = [module("korp::clip", 1), module("korp::io", 0)];
        let cov = repo_bench_coverage("korp", &modules, &[], &[], &[], &BTreeSet::new(), 10);
        assert!(cov.never_benched());
        assert_eq!(cov.benched, 0);
        assert_eq!(cov.unbenched, cov.hot_paths);
        assert!(cov.hot_paths > 0);
    }

    #[test]
    fn the_unbenched_hot_path_is_named_and_the_benched_one_is_not() {
        let modules = [module("znippy::decode", 20), module("znippy::encode", 20), module("znippy::caller", 0)];
        let cov = repo_bench_coverage("znippy", &modules, &[], &[run("znippy", "r1", "oden")], &[result("r1", "znippy.decode_mt")], &BTreeSet::new(), 10);
        let named: Vec<&str> = cov.worst.iter().map(|h| h.module.as_str()).collect();
        assert!(named.contains(&"znippy::encode"), "{named:?}");
        assert!(!named.contains(&"znippy::decode"));
    }

    #[test]
    fn fan_in_churn_and_coverage_each_move_the_rank_and_test_modules_are_no_surface() {
        let heat = [GitHeatFact { repo: "korp".into(), file: "korp::hot.rs".into(), commits_90d: 30 }];
        let mut covered = module("korp::covered", 0);
        covered.fns_covered = 1;
        let modules = [module("korp::called", 9), module("korp::hot", 0), covered, module("korp::quiet", 0), module("korp::tests", 50)];
        let hot = hot_paths("korp", &modules, &heat, &BTreeSet::new(), 10);
        let order: Vec<&str> = hot.iter().map(|h| h.module.as_str()).collect();
        assert_eq!(order, vec!["korp::called", "korp::covered", "korp::hot", "korp::quiet"]);
        assert_eq!((hot[0].fan_in, hot[2].commits_90d, hot[1].test_coverage), (9, 30, 1.0));
    }
}