Skip to content

Commit 3b169c7

Browse files
committed
Add benchlib
Library for defining and measuring (micro)benchmarks.
1 parent e78840c commit 3b169c7

File tree

8 files changed

+320
-35
lines changed

8 files changed

+320
-35
lines changed

Cargo.lock

Lines changed: 76 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["collector", "site", "database", "intern"]
2+
members = ["collector", "collector/benchlib", "site", "database", "intern"]
33
exclude = ["collector/benchmarks", "rust/src"]
44

55
[profile.release.package.site]

collector/benchlib/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "benchlib"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "Library for defining and measuring benchmarks of Rust code"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
perf-event = "0.4.7"
11+
anyhow = "1.0.61"
12+
serde = { version = "1.0.143", features = ["derive"] }
13+
serde_json = "1.0.83"
14+
log = "0.4.17"
15+
env_logger = "0.9.0"
16+
clap = { version = "3.2", features = ["derive"] }

collector/benchlib/src/benchmark.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use crate::cli::{parse_cli, Args, BenchmarkArgs};
2+
use crate::measure::benchmark;
3+
use crate::messages::BenchmarkResult;
4+
use log::LevelFilter;
5+
use std::collections::HashMap;
6+
7+
/// Create a new benchmark suite. Use the closure argument to define benchmarks.
8+
pub fn benchmark_suite<F: FnOnce(&mut BenchmarkSuite) -> ()>(define_func: F) {
9+
env_logger::Builder::from_default_env()
10+
.filter_level(LevelFilter::Info)
11+
.init();
12+
let mut suite = BenchmarkSuite::new();
13+
define_func(&mut suite);
14+
suite.run().expect("Benchmark suite has failed");
15+
}
16+
17+
pub struct BenchmarkSuite {
18+
benchmarks: HashMap<&'static str, BenchmarkWrapper>,
19+
}
20+
21+
impl BenchmarkSuite {
22+
pub fn new() -> Self {
23+
Self {
24+
benchmarks: Default::default(),
25+
}
26+
}
27+
28+
/// Registers a single benchmark.
29+
/// `func` should return a closure that will be benchmarked.
30+
pub fn register<F: Fn() -> Bench + 'static, R, Bench: FnOnce() -> R + 'static>(
31+
&mut self,
32+
name: &'static str,
33+
func: F,
34+
) {
35+
// We want to monomorphize the target `func` and then wrap it in a Box, to avoid going
36+
// through a vtable when we execute the benchmarked function.
37+
let benchmark_func = Box::new(move || {
38+
let bench_fn = func();
39+
benchmark(name, bench_fn)
40+
});
41+
let benchmark_def = BenchmarkWrapper {
42+
func: benchmark_func,
43+
};
44+
if let Some(_) = self.benchmarks.insert(name, benchmark_def) {
45+
panic!("Benchmark {} was registered twice", name);
46+
}
47+
}
48+
49+
/// Execute the benchmark suite. It will parse CLI arguments and decide what to do based on
50+
/// them.
51+
pub fn run(self) -> anyhow::Result<()> {
52+
let args = parse_cli()?;
53+
match args {
54+
Args::Benchmark(args) => {
55+
self.run_benchmark(args)?;
56+
}
57+
}
58+
59+
Ok(())
60+
}
61+
62+
fn run_benchmark(self, args: BenchmarkArgs) -> anyhow::Result<()> {
63+
let mut items: Vec<_> = self.benchmarks.into_iter().collect();
64+
items.sort_unstable_by_key(|item| item.0);
65+
66+
let mut results: Vec<BenchmarkResult> = Vec::with_capacity(items.len());
67+
for (name, def) in items {
68+
for i in 0..args.iterations {
69+
let result = (def.func)()?;
70+
log::info!("Benchmark (run {i}) `{}` completed: {:?}", name, result);
71+
results.push(result);
72+
}
73+
}
74+
75+
println!("{}", serde_json::to_string(&results)?);
76+
Ok(())
77+
}
78+
}
79+
80+
struct BenchmarkWrapper {
81+
func: Box<dyn Fn() -> anyhow::Result<BenchmarkResult>>,
82+
}

0 commit comments

Comments
 (0)