| 
1 |  | -use std::collections::{BTreeMap, HashMap, HashSet};  | 
2 | 1 | use std::fmt::Debug;  | 
3 | 2 | 
 
  | 
4 | 3 | use build_helper::metrics::{  | 
5 | 4 |     BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name,  | 
6 | 5 |     format_build_steps,  | 
7 | 6 | };  | 
 | 7 | +use std::collections::{BTreeMap, HashMap, HashSet};  | 
 | 8 | +use std::time::Duration;  | 
8 | 9 | 
 
  | 
9 | 10 | use crate::metrics;  | 
10 | 11 | use crate::metrics::{JobMetrics, JobName, get_test_suites};  | 
@@ -184,11 +185,61 @@ fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {  | 
184 | 185 | }  | 
185 | 186 | 
 
  | 
186 | 187 | /// Outputs a report of test differences between the `parent` and `current` commits.  | 
187 |  | -pub fn output_test_diffs(job_metrics: HashMap<JobName, JobMetrics>) {  | 
 | 188 | +pub fn output_test_diffs(job_metrics: &HashMap<JobName, JobMetrics>) {  | 
188 | 189 |     let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);  | 
189 | 190 |     report_test_diffs(aggregated_test_diffs);  | 
190 | 191 | }  | 
191 | 192 | 
 
  | 
 | 193 | +/// Prints the ten largest differences in bootstrap durations.  | 
 | 194 | +pub fn output_largest_duration_changes(job_metrics: &HashMap<JobName, JobMetrics>) {  | 
 | 195 | +    struct Entry<'a> {  | 
 | 196 | +        job: &'a JobName,  | 
 | 197 | +        before: Duration,  | 
 | 198 | +        after: Duration,  | 
 | 199 | +        change: f64,  | 
 | 200 | +    }  | 
 | 201 | + | 
 | 202 | +    let mut changes: Vec<Entry> = vec![];  | 
 | 203 | +    for (job, metrics) in job_metrics {  | 
 | 204 | +        if let Some(parent) = &metrics.parent {  | 
 | 205 | +            let duration_before = parent  | 
 | 206 | +                .invocations  | 
 | 207 | +                .iter()  | 
 | 208 | +                .map(|i| BuildStep::from_invocation(i).duration)  | 
 | 209 | +                .sum::<Duration>();  | 
 | 210 | +            let duration_after = metrics  | 
 | 211 | +                .current  | 
 | 212 | +                .invocations  | 
 | 213 | +                .iter()  | 
 | 214 | +                .map(|i| BuildStep::from_invocation(i).duration)  | 
 | 215 | +                .sum::<Duration>();  | 
 | 216 | +            let pct_change = duration_after.as_secs_f64() / duration_before.as_secs_f64();  | 
 | 217 | +            let pct_change = pct_change * 100.0;  | 
 | 218 | +            // Normalize around 100, to get + for regression and - for improvements  | 
 | 219 | +            let pct_change = pct_change - 100.0;  | 
 | 220 | +            changes.push(Entry {  | 
 | 221 | +                job,  | 
 | 222 | +                before: duration_before,  | 
 | 223 | +                after: duration_after,  | 
 | 224 | +                change: pct_change,  | 
 | 225 | +            });  | 
 | 226 | +        }  | 
 | 227 | +    }  | 
 | 228 | +    changes.sort_by(|e1, e2| e1.change.partial_cmp(&e2.change).unwrap().reverse());  | 
 | 229 | + | 
 | 230 | +    println!("# Job duration changes");  | 
 | 231 | +    for (index, entry) in changes.into_iter().take(10).enumerate() {  | 
 | 232 | +        println!(  | 
 | 233 | +            "{}. `{}`: {:.1}s -> {:.1}s ({:.1}%)",  | 
 | 234 | +            index + 1,  | 
 | 235 | +            entry.job,  | 
 | 236 | +            entry.before.as_secs_f64(),  | 
 | 237 | +            entry.after.as_secs_f64(),  | 
 | 238 | +            entry.change  | 
 | 239 | +        );  | 
 | 240 | +    }  | 
 | 241 | +}  | 
 | 242 | + | 
192 | 243 | #[derive(Default)]  | 
193 | 244 | struct TestSuiteRecord {  | 
194 | 245 |     passed: u64,  | 
 | 
0 commit comments