Skip to content

Commit 9db060d

Browse files
committed
fix: divan walltime metric; support variable iter count
1 parent b6a7be8 commit 9db060d

File tree

4 files changed

+92
-24
lines changed

4 files changed

+92
-24
lines changed

crates/cargo-codspeed/src/walltime_results.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,17 @@ impl WalltimeBenchmark {
5353

5454
impl From<RawWallTimeData> for WalltimeBenchmark {
5555
fn from(value: RawWallTimeData) -> Self {
56-
let times_ns: Vec<f64> = value.times_ns.iter().map(|&t| t as f64).collect();
57-
let mut data = Data::new(times_ns.clone());
56+
let total_time = value.times_per_round_ns.iter().sum::<u128>() as f64 / 1_000_000_000.0;
57+
let time_per_iteration_per_round_ns: Vec<_> = value
58+
.times_per_round_ns
59+
.into_iter()
60+
.zip(&value.iters_per_round)
61+
.map(|(time_per_round, iter_per_round)| time_per_round / iter_per_round)
62+
.map(|t| t as f64)
63+
.collect::<Vec<f64>>();
64+
65+
let mut data = Data::new(time_per_iteration_per_round_ns);
5866
let rounds = data.len() as u64;
59-
let total_time = times_ns.iter().sum::<f64>() / 1_000_000_000.0;
6067

6168
let mean_ns = data.mean().unwrap();
6269

@@ -91,7 +98,9 @@ impl From<RawWallTimeData> for WalltimeBenchmark {
9198
let min_ns = data.min();
9299
let max_ns = data.max();
93100

94-
let iter_per_round = value.iter_per_round as u64;
101+
// TODO(COD-1056): We currently only support single iteration count per round
102+
let iter_per_round = (value.iters_per_round.iter().sum::<u128>()
103+
/ value.iters_per_round.len() as u128) as u64;
95104
let warmup_iters = 0; // FIXME: add warmup detection
96105

97106
let stats = BenchmarkStats {
@@ -172,9 +181,9 @@ mod tests {
172181
};
173182
let raw_bench = RawWallTimeData {
174183
metadata,
175-
iter_per_round: 1,
184+
iters_per_round: vec![1],
176185
max_time_ns: None,
177-
times_ns: vec![42],
186+
times_per_round_ns: vec![42],
178187
};
179188

180189
let benchmark: WalltimeBenchmark = raw_bench.into();
@@ -183,4 +192,31 @@ mod tests {
183192
assert_eq!(benchmark.stats.max_ns, 42.);
184193
assert_eq!(benchmark.stats.mean_ns, 42.);
185194
}
195+
196+
#[test]
197+
fn test_parse_bench_with_variable_iterations() {
198+
let metadata = BenchmarkMetadata {
199+
name: "benchmark".to_string(),
200+
uri: "test::benchmark".to_string(),
201+
};
202+
203+
let raw_bench = RawWallTimeData {
204+
metadata,
205+
iters_per_round: vec![1, 2, 3, 4, 5, 6],
206+
max_time_ns: None,
207+
times_per_round_ns: vec![42, 42 * 2, 42 * 3, 42 * 4, 42 * 5, 42 * 6],
208+
};
209+
210+
let total_rounds = raw_bench.iters_per_round.iter().sum::<u128>() as f64;
211+
212+
let benchmark: WalltimeBenchmark = raw_bench.into();
213+
assert_eq!(benchmark.stats.stdev_ns, 0.);
214+
assert_eq!(benchmark.stats.min_ns, 42.);
215+
assert_eq!(benchmark.stats.max_ns, 42.);
216+
assert_eq!(benchmark.stats.mean_ns, 42.);
217+
assert_eq!(
218+
benchmark.stats.total_time,
219+
42. * total_rounds / 1_000_000_000.0
220+
);
221+
}
186222
}

crates/codspeed/src/walltime.rs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,24 @@ pub struct BenchmarkMetadata {
1515
pub struct RawWallTimeData {
1616
#[serde(flatten)]
1717
pub metadata: BenchmarkMetadata,
18-
pub iter_per_round: u32,
18+
pub iters_per_round: Vec<u128>,
19+
pub times_per_round_ns: Vec<u128>,
1920
pub max_time_ns: Option<u128>,
20-
pub times_ns: Vec<u128>,
2121
}
2222

2323
impl RawWallTimeData {
2424
fn from_runtime_data(
2525
name: String,
2626
uri: String,
27-
iter_per_round: u32,
27+
iters_per_round: Vec<u128>,
28+
times_per_round_ns: Vec<u128>,
2829
max_time_ns: Option<u128>,
29-
times_ns: Vec<u128>,
3030
) -> Self {
3131
RawWallTimeData {
3232
metadata: BenchmarkMetadata { name, uri },
33-
iter_per_round,
33+
iters_per_round,
3434
max_time_ns,
35-
times_ns,
35+
times_per_round_ns,
3636
}
3737
}
3838

@@ -50,13 +50,37 @@ impl RawWallTimeData {
5050
/// Entry point called in patched integration to harvest raw walltime data
5151
///
5252
/// `CODSPEED_CARGO_WORKSPACE_ROOT` is expected to be set for this to work
53+
///
54+
/// # Arguments
55+
///
56+
/// - `scope`: The used integration, e.g. "divan" or "criterion"
57+
/// - `name`: The name of the benchmark
58+
/// - `uri`: The URI of the benchmark
59+
/// - `iters_per_round`: The number of iterations for each round (=sample_size), e.g. `[1, 2, 3]` (variable) or `[2, 2, 2, 2]` (constant).
60+
/// - `times_per_round_ns`: The measured time for each round in nanoseconds, e.g. `[1000, 2000, 3000]`
61+
/// - `max_time_ns`: The time limit for the benchmark in nanoseconds (if defined)
62+
///
63+
/// # Pseudo-code
64+
///
65+
/// ```text
66+
/// let sample_count = /* The number of executions for the same benchmark. */
67+
/// let sample_size = iters_per_round = vec![/* The number of iterations within each sample. */];
68+
/// for round in 0..sample_count {
69+
/// let times_per_round_ns = 0;
70+
/// for iteration in 0..sample_size[round] {
71+
/// run_benchmark();
72+
/// times_per_round_ns += /* measured execution time */;
73+
/// }
74+
/// }
75+
/// ```
76+
///
5377
pub fn collect_raw_walltime_results(
5478
scope: &str,
5579
name: String,
5680
uri: String,
57-
iter_per_round: u32,
81+
iters_per_round: Vec<u128>,
82+
times_per_round_ns: Vec<u128>,
5883
max_time_ns: Option<u128>,
59-
times_ns: Vec<u128>,
6084
) {
6185
if !crate::utils::running_with_codspeed_runner() {
6286
return;
@@ -66,7 +90,13 @@ pub fn collect_raw_walltime_results(
6690
eprintln!("codspeed failed to get workspace root. skipping");
6791
return;
6892
};
69-
let data = RawWallTimeData::from_runtime_data(name, uri, iter_per_round, max_time_ns, times_ns);
93+
let data = RawWallTimeData::from_runtime_data(
94+
name,
95+
uri,
96+
iters_per_round,
97+
times_per_round_ns,
98+
max_time_ns,
99+
);
70100
data.dump_to_results(&workspace_root, scope);
71101
}
72102

crates/criterion_compat/criterion_fork/src/analysis/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ pub(crate) fn common<M: Measurement, T: ?Sized>(
258258
}
259259

260260
if criterion.should_save_baseline() && ::codspeed::utils::running_with_codspeed_runner() {
261-
codspeed::collect_walltime_results(id, criterion, &iters, avg_times);
261+
codspeed::collect_walltime_results(id, criterion, &iters, &times);
262262
}
263263
}
264264

@@ -293,7 +293,7 @@ mod codspeed {
293293
id: &BenchmarkId,
294294
c: &Criterion<M>,
295295
iters: &[f64],
296-
avg_times: &[f64],
296+
times: &[f64],
297297
) {
298298
let (uri, bench_name) = create_uri_and_name(id, c);
299299

@@ -306,17 +306,17 @@ mod codspeed {
306306
}
307307
}
308308

309-
let avg_iter_per_round = iters.iter().sum::<f64>() / iters.len() as f64;
309+
let iters_per_round = iters.iter().map(|t| *t as u128).collect();
310+
let times_per_round_ns = times.iter().map(|t| *t as u128).collect();
310311
let max_time_ns = Some(c.config.measurement_time.as_nanos());
311-
let times_ns = avg_times.iter().map(|t| *t as u128).collect();
312312

313313
::codspeed::walltime::collect_raw_walltime_results(
314314
"criterion",
315315
bench_name,
316316
uri,
317-
avg_iter_per_round as u32,
317+
iters_per_round,
318+
times_per_round_ns,
318319
max_time_ns,
319-
times_ns,
320320
);
321321
}
322322
}

crates/divan_compat/divan_fork/src/divan.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,9 @@ mod codspeed {
424424
};
425425

426426
let iter_per_round = bench_context.samples.sample_size;
427-
let times_ns: Vec<_> =
427+
let iters_per_round =
428+
vec![iter_per_round as u128; bench_context.samples.time_samples.len()];
429+
let times_per_round_ns: Vec<_> =
428430
bench_context.samples.time_samples.iter().map(|s| s.duration.picos / 1_000).collect();
429431
let max_time_ns = bench_context.options.max_time.map(|t| t.as_nanos());
430432

@@ -441,9 +443,9 @@ mod codspeed {
441443
"divan",
442444
bench_name,
443445
uri,
444-
iter_per_round,
446+
iters_per_round,
447+
times_per_round_ns,
445448
max_time_ns,
446-
times_ns,
447449
);
448450
}
449451
}

0 commit comments

Comments
 (0)