git_perf/
measurement_retrieval.rs1use crate::{
2 data::{CommitSummary, MeasurementData, MeasurementSummary},
3 git::git_interop::{self},
4 stats::NumericReductionFunc,
5};
6
7use git_perf_cli_types::ReductionFunc;
8
9use anyhow::Result;
10
11pub trait MeasurementReducer<'a>: Iterator<Item = &'a MeasurementData> {
12 fn reduce_by(self, fun: ReductionFunc) -> Option<MeasurementSummary>;
13}
14
15pub fn summarize_measurements<'a, F>(
16 commits: impl Iterator<Item = Result<Commit>> + 'a,
17 summarize_by: &'a ReductionFunc,
18 filter_by: &'a F,
19) -> impl Iterator<Item = Result<CommitSummary>> + 'a
20where
21 F: Fn(&MeasurementData) -> bool,
22{
23 commits.map(move |c| {
24 c.map(|c| {
25 let measurement = c
26 .measurements
27 .iter()
28 .filter(|m| filter_by(m))
29 .reduce_by(*summarize_by);
30
31 CommitSummary {
32 commit: c.commit,
33 measurement,
34 }
35 })
36 })
37}
38
39pub fn take_while_same_epoch<I>(iter: I) -> impl Iterator<Item = Result<CommitSummary>>
41where
42 I: Iterator<Item = Result<CommitSummary>>,
43{
44 let mut first_epoch: Option<u32> = None;
45 iter.take_while(move |m| match m {
46 Ok(CommitSummary {
47 measurement: Some(m),
48 ..
49 }) => {
50 let prev_epoch = first_epoch;
51 first_epoch = Some(m.epoch);
52 prev_epoch.unwrap_or(m.epoch) == m.epoch
53 }
54 _ => true,
55 })
56}
57
58impl<'a, T> MeasurementReducer<'a> for T
59where
60 T: Iterator<Item = &'a MeasurementData>,
61{
62 fn reduce_by(self, fun: ReductionFunc) -> Option<MeasurementSummary> {
63 let mut peekable = self.peekable();
64 let expected_epoch = peekable.peek().map(|m| m.epoch);
65 let mut vals = peekable.map(|m| {
66 debug_assert_eq!(Some(m.epoch), expected_epoch);
67 m.val
68 });
69
70 let aggregate_val = vals.aggregate_by(fun);
71
72 Some(MeasurementSummary {
73 epoch: expected_epoch?,
74 val: aggregate_val?,
75 })
76 }
77}
78
79#[derive(Debug, PartialEq)]
80pub struct Commit {
81 pub commit: String,
82 pub measurements: Vec<MeasurementData>,
83}
84
85pub fn walk_commits(num_commits: usize) -> Result<impl Iterator<Item = Result<Commit>>> {
88 let vec = git_interop::walk_commits(num_commits)?;
89 Ok(vec
90 .into_iter()
91 .take(num_commits)
92 .map(|(commit_id, lines)| -> Result<Commit> {
93 let measurements = crate::serialization::deserialize(&lines.join("\n"));
94 Ok(Commit {
95 commit: commit_id,
96 measurements,
97 })
98 }))
99 }