Skip to content

Commit 7eb35cf

Browse files
authored
feat: package benchmark runner into a re-usable binary (canbench) (#175)
Packages the benchmarking logic into a re-usable binary which I'm calling `canbench`. Once this binary is generally available, canister developers can use this tool by: 1. Installing `canbench` - something like `cargo install canbench`. 2. Define a `canbench.yml` configuration. 3. Run benchmarks by running the `canbench` command. A few more improvements in the UX will be done first before `canbench` is ready for general availability.
1 parent 0be1270 commit 7eb35cf

File tree

8 files changed

+47
-11
lines changed

8 files changed

+47
-11
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
**/target
22
**/.dfx
3+
**/.canbench
34

45
# Various IDEs and Editors
56
.vscode/

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ serde_yaml = "0.9"
3434
tempfile = "3.3.0"
3535
test-strategy = "0.3.1"
3636

37-
[[bench]]
38-
name = "benchmarks"
39-
harness = false
40-
path = "benchmarks/benchmark.rs"
41-
4237
[workspace]
4338
members = ["benchmark-canisters"]
4439

benchmarks/benchmark_ci.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#!/usr/bin/env bash
22
set -Eexuo pipefail
33

4-
BENCH_OUTPUT=$(cargo bench)
4+
# Install cargobench
5+
cargo install --path ./profiler --features bin
6+
7+
BENCH_OUTPUT=$(canbench)
58

69
set +e
710
REGRESSIONS=$( echo "$BENCH_OUTPUT" | grep -c "regressed by" )

bench.yml renamed to canbench.yml

File renamed without changes.

profiler/Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@ edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

8+
[lib]
9+
name = "profiler"
10+
path = "src/lib.rs"
11+
12+
[[bin]]
13+
name = "canbench"
14+
path = "src/bin.rs"
15+
required-features = ["bin"]
16+
817
[dependencies]
918
candid.workspace = true
1019
ic-cdk.workspace= true
1120
maplit = "1.0.2"
1221
serde = "1.0"
1322

23+
clap = { version = "4.0.11", features = ["derive"], optional = true }
1424
colored = { version = "2.0.4", optional = true }
1525
flate2 = { version = "1.0.28", optional = true }
1626
hex = { version = "0.4.3", optional = true }
@@ -31,3 +41,5 @@ benchmark = [
3141
"tempfile",
3242
"wasmparser",
3343
]
44+
45+
bin = ["clap", "benchmark"]

profiler/src/benchmark.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,16 @@ pub fn run_benchmarks(
109109
}
110110
}
111111

112-
fn drun_path() -> PathBuf {
112+
// Path to the canbench directory where we keep internal data.
113+
fn canbench_dir() -> PathBuf {
113114
PathBuf::new()
114-
.join(env::var("CARGO_MANIFEST_DIR").unwrap())
115-
.join("drun")
115+
.join(env::current_dir().unwrap())
116+
.join(".canbench")
117+
}
118+
119+
// Path to drun.
120+
fn drun_path() -> PathBuf {
121+
canbench_dir().join("drun")
116122
}
117123

118124
// Downloads drun if it's not already downloaded.
@@ -140,6 +146,9 @@ fn maybe_download_drun() {
140146
fn download_drun() {
141147
println!("Downloading drun (will be cached for future uses)...");
142148

149+
// Create the canbench directory if it doesn't exist.
150+
std::fs::create_dir_all(canbench_dir()).unwrap();
151+
143152
let os = if cfg!(target_os = "linux") {
144153
"linux"
145154
} else if cfg!(target_os = "macos") {

benchmarks/benchmark.rs renamed to profiler/src/bin.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
use clap::Parser;
44
use std::{collections::BTreeMap, fs::File, io::Read, path::PathBuf, process::Command};
55

6+
const CFG_FILE_NAME: &str = "canbench.yml";
7+
68
#[derive(Parser, Debug)]
79
#[command(author, version, about, long_about = None)]
810
struct Args {
@@ -21,8 +23,21 @@ struct Args {
2123
fn main() {
2224
let args = Args::parse();
2325

24-
// Read and parse the configuration in `bench.yml` file.
25-
let mut file = File::open("bench.yml").expect("bench.yml not found");
26+
// Read and parse the configuration file.
27+
let mut file = match File::open(CFG_FILE_NAME) {
28+
Ok(file) => file,
29+
Err(err) => {
30+
match err.kind() {
31+
std::io::ErrorKind::NotFound => {
32+
println!("{} not found in current directory.", CFG_FILE_NAME)
33+
}
34+
other => println!("Error while opening `{}`: {}", CFG_FILE_NAME, other),
35+
}
36+
37+
std::process::exit(1);
38+
}
39+
};
40+
2641
let mut config_str = String::new();
2742
file.read_to_string(&mut config_str).unwrap();
2843
let cfg: BTreeMap<String, String> = serde_yaml::from_str(&config_str).unwrap();

0 commit comments

Comments
 (0)