Skip to content

Commit a8fb050

Browse files
authored
Merge pull request #1465 from rust-lang/runtime-measurement-precision
Split measurement of walltime and perf. counters
2 parents a987a52 + c1bb6d3 commit a8fb050

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

collector/benchlib/src/benchmark.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,13 @@ impl BenchmarkSuite {
3434

3535
/// Registers a single benchmark.
3636
/// `func` should return a closure that will be benchmarked.
37-
pub fn register<F: Fn() -> Bench + 'static, R, Bench: FnOnce() -> R + 'static>(
37+
pub fn register<F: Fn() -> Bench + Clone + 'static, R, Bench: FnOnce() -> R + 'static>(
3838
&mut self,
3939
name: &'static str,
40-
func: F,
40+
constructor: F,
4141
) {
42-
// We want to monomorphize the target `func` and then wrap it in a Box, to avoid going
43-
// through a vtable when we execute the benchmarked function.
44-
let benchmark_func = Box::new(move || {
45-
let bench_fn = func();
46-
benchmark_function(name, bench_fn)
47-
});
42+
// We want to type-erase the target `func` by wrapping it in a Box.
43+
let benchmark_func = Box::new(move || benchmark_function(name, constructor.clone()));
4844
let benchmark_def = BenchmarkWrapper {
4945
func: benchmark_func,
5046
};

collector/benchlib/src/measure/perf_counter/unix.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,42 @@ struct Counters {
1212
cache_references: Counter,
1313
}
1414

15-
/// Benchmarks a single function.
16-
pub fn benchmark_function<F: FnOnce() -> R, R>(
15+
/// Benchmarks a single function generated by `benchmark_constructor`.
16+
/// The function is executed twice, once to gather wall-time measurement and the second time to
17+
/// gather perf. counters.
18+
pub fn benchmark_function<F: Fn() -> Bench + 'static, R, Bench: FnOnce() -> R + 'static>(
1719
name: &'static str,
18-
func: F,
20+
benchmark_constructor: F,
1921
) -> anyhow::Result<BenchmarkResult> {
2022
let mut group = create_group()?;
2123
let counters = prepare_counters(&mut group)?;
2224

23-
// FIXME: don't run perf counters and time measurements together, run the benchmark twice
24-
// instead.
25-
let start = Instant::now();
25+
// Measure perf. counters.
26+
let func = benchmark_constructor();
2627

2728
// Do not act on the return value to avoid including the branch in the measurement
2829
let enable_ret = group.enable();
2930
let output = func();
3031
group.disable()?;
3132

32-
let duration = start.elapsed();
33+
// Try to avoid optimizing the result out.
34+
black_box(output);
3335

3436
// Check if we have succeeded before
3537
enable_ret?;
3638

37-
// Try to avoid optimizing the result out
38-
black_box(output);
39-
4039
let measurement = group.read()?;
4140

41+
// Measure wall time.
42+
let func = benchmark_constructor();
43+
44+
let start = Instant::now();
45+
let output = func();
46+
let duration = start.elapsed();
47+
48+
// Try to avoid optimizing the result out.
49+
black_box(output);
50+
4251
let result = BenchmarkResult {
4352
name: String::from(name),
4453
cycles: measurement[&counters.cycles],

0 commit comments

Comments
 (0)