git_perf/
audit.rs

1use crate::{
2    data::{MeasurementData, ReductionFunc},
3    measurement_retrieval::{self, summarize_measurements},
4    stats,
5};
6use anyhow::{anyhow, bail, Result};
7use itertools::Itertools;
8use std::iter;
9
10pub fn audit(
11    measurement: &str,
12    max_count: usize,
13    min_count: u16,
14    selectors: &[(String, String)],
15    summarize_by: ReductionFunc,
16    sigma: f64,
17) -> Result<()> {
18    let all = measurement_retrieval::walk_commits(max_count)?;
19
20    let filter_by = |m: &MeasurementData| {
21        m.name == measurement
22            && selectors
23                .iter()
24                .all(|s| m.key_values.get(&s.0).map(|v| *v == s.1).unwrap_or(false))
25    };
26
27    let mut aggregates = summarize_measurements(all, &summarize_by, &filter_by);
28
29    let head = aggregates
30        .next()
31        .ok_or(anyhow!("No commit at HEAD"))
32        .and_then(|s| {
33            eprintln!("Head measurement is: {s:?}");
34            s.and_then(|cs| {
35                cs.measurement
36                    .map(|m| m.val)
37                    .ok_or(anyhow!("No measurement for HEAD."))
38            })
39        })?;
40
41    let tail: Vec<_> = aggregates
42        .filter_map_ok(|cs| cs.measurement.map(|m| m.val))
43        .take(max_count)
44        .try_collect()?;
45
46    let head_summary = stats::aggregate_measurements(iter::once(head));
47    let tail_summary = stats::aggregate_measurements(tail.into_iter());
48
49    if tail_summary.len < min_count.into() {
50        // TODO(kaihowl) handle with explicit return? Print text somewhere else?
51        let number_measurements = tail_summary.len;
52        let plural_s = if number_measurements > 1 { "s" } else { "" };
53        eprintln!("Only {number_measurements} measurement{plural_s} found. Less than requested min_measurements of {min_count}. Skipping test.");
54        return Ok(());
55    }
56
57    if head_summary.significantly_different_from(&tail_summary, sigma) {
58        // TODO(kaihowl) print details
59        bail!(
60            "HEAD differs significantly from tail measurements.\nHead: {}\nTail: {}",
61            &head_summary,
62            &tail_summary
63        );
64    }
65
66    Ok(())
67}