|
1 | 1 | use std::collections::{BTreeMap, HashMap, HashSet};
|
2 | 2 | use std::fmt::Debug;
|
| 3 | +use std::time::Duration; |
3 | 4 |
|
4 | 5 | use build_helper::metrics::{
|
5 | 6 | BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name,
|
@@ -184,11 +185,70 @@ 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 | + println!(); |
| 243 | + output_details("How to interpret the job duration changes?", || { |
| 244 | + println!( |
| 245 | + r#"Job durations can vary a lot, based on the actual runner instance |
| 246 | +that executed the job, system noise, invalidated caches, etc. The table above is provided |
| 247 | +mostly for t-infra members, for simpler debugging of potential CI slow-downs."# |
| 248 | + ); |
| 249 | + }); |
| 250 | +} |
| 251 | + |
192 | 252 | #[derive(Default)]
|
193 | 253 | struct TestSuiteRecord {
|
194 | 254 | passed: u64,
|
|
0 commit comments