Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 93bb62c

Browse files
committedSep 1, 2022
Add bench_runtime_local command to collector and a simple hashmap runtime benchmark
1 parent 392248c commit 93bb62c

File tree

12 files changed

+672
-36
lines changed

12 files changed

+672
-36
lines changed
 

‎Cargo.lock

Lines changed: 36 additions & 0 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,6 +1,6 @@
11
[workspace]
22
members = ["collector", "collector/benchlib", "site", "database", "intern"]
3-
exclude = ["collector/compile-benchmarks", "rust/src"]
3+
exclude = ["collector/compile-benchmarks", "collector/runtime-benchmarks", "rust/src"]
44

55
[profile.release.package.site]
66
debug = 1

‎collector/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ filetime = "0.2.14"
3333
walkdir = "2"
3434
flate2 = { version = "1.0.22", features = ["rust_backend"] }
3535
rayon = "1.5.2"
36+
cargo_metadata = "0.15.0"
37+
benchlib = { path = "benchlib" }
3638

3739
[target.'cfg(windows)'.dependencies]
3840
miow = "0.3"

‎collector/runtime-benchmarks/Cargo.lock

Lines changed: 433 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[workspace]
2+
members = ["hashmap"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "hashmap-bench"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
benchlib = { path = "../../benchlib" }
10+
hashbrown = "0.12.3"
11+
fxhash = "0.2.1"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use benchlib;
2+
use benchlib::benchmark::BenchmarkSuite;
3+
4+
fn main() {
5+
let mut suite = BenchmarkSuite::new();
6+
7+
suite.register("hashmap-insert-10k", || {
8+
let mut map =
9+
hashbrown::HashMap::with_capacity_and_hasher(10000, fxhash::FxBuildHasher::default());
10+
move || {
11+
for index in 0..10000 {
12+
map.insert(index, index);
13+
}
14+
}
15+
});
16+
suite.run().unwrap();
17+
}

‎collector/src/benchmark/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,20 @@ impl Benchmark {
305305
}
306306
}
307307

308-
pub fn compile_time_benchmark_dir() -> PathBuf {
308+
/// Directory containing compile-time benchmarks.
309+
/// We measure how long does it take to compile these crates.
310+
pub fn compile_benchmark_dir() -> PathBuf {
309311
PathBuf::from("collector/compile-benchmarks")
310312
}
311313

312-
pub fn get_benchmarks(
314+
/// Directory containing runtime benchmarks.
315+
/// We measure how long does it take to execute these crates, which is a proxy of the quality
316+
/// of code generated by rustc.
317+
pub fn runtime_benchmark_dir() -> PathBuf {
318+
PathBuf::from("collector/runtime-benchmarks")
319+
}
320+
321+
pub fn get_compile_benchmarks(
313322
benchmark_dir: &Path,
314323
include: Option<&str>,
315324
exclude: Option<&str>,

‎collector/src/bin/collector.rs

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use collector::api::next_artifact::NextArtifact;
77
use collector::benchmark::category::Category;
88
use collector::benchmark::profile::Profile;
99
use collector::benchmark::scenario::Scenario;
10-
use collector::benchmark::{compile_time_benchmark_dir, get_benchmarks, Benchmark, BenchmarkName};
10+
use collector::benchmark::{
11+
compile_benchmark_dir, get_compile_benchmarks, runtime_benchmark_dir, Benchmark, BenchmarkName,
12+
};
1113
use collector::utils;
1214
use database::{ArtifactId, Commit, CommitType, Pool};
1315
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
@@ -24,6 +26,7 @@ use tokio::runtime::Runtime;
2426

2527
use collector::execute::bencher::BenchProcessor;
2628
use collector::execute::profiler::{ProfileProcessor, Profiler};
29+
use collector::runtime::bench_runtime;
2730
use collector::toolchain::{get_local_toolchain, Compiler, Sysroot};
2831

2932
fn n_normal_benchmarks_remaining(n: usize) -> String {
@@ -557,6 +560,13 @@ struct BenchRustcOption {
557560
#[derive(Debug, clap::Subcommand)]
558561
#[clap(rename_all = "snake_case")]
559562
enum Commands {
563+
/// Benchmarks the performance of programs generated by a local rustc
564+
BenchRuntimeLocal {
565+
rustc: String,
566+
/// Identifier to associate benchmark results with
567+
#[clap(long)]
568+
id: Option<String>,
569+
},
560570
/// Benchmarks a local rustc
561571
BenchLocal {
562572
#[clap(flatten)]
@@ -667,7 +677,8 @@ fn main_result() -> anyhow::Result<i32> {
667677

668678
let args = Cli::parse();
669679

670-
let benchmark_dir = compile_time_benchmark_dir();
680+
let compile_benchmark_dir = compile_benchmark_dir();
681+
let runtime_benchmark_dir = runtime_benchmark_dir();
671682

672683
let mut builder = tokio::runtime::Builder::new_multi_thread();
673684
// We want to minimize noise from the runtime
@@ -681,6 +692,10 @@ fn main_result() -> anyhow::Result<i32> {
681692
let target_triple = format!("{}-unknown-linux-gnu", std::env::consts::ARCH);
682693

683694
match args.command {
695+
Commands::BenchRuntimeLocal { rustc, id } => {
696+
bench_runtime(&rustc, id.as_deref(), runtime_benchmark_dir)?;
697+
Ok(0)
698+
}
684699
Commands::BenchLocal {
685700
local,
686701
db,
@@ -693,7 +708,7 @@ fn main_result() -> anyhow::Result<i32> {
693708

694709
let pool = database::Pool::open(&db.db);
695710

696-
let (rustc, rustdoc, cargo, id) = get_local_toolchain(
711+
let toolchain = get_local_toolchain(
697712
&profiles,
698713
&local.rustc,
699714
local.rustdoc.as_deref(),
@@ -702,8 +717,8 @@ fn main_result() -> anyhow::Result<i32> {
702717
"",
703718
)?;
704719

705-
let mut benchmarks = get_benchmarks(
706-
&benchmark_dir,
720+
let mut benchmarks = get_compile_benchmarks(
721+
&compile_benchmark_dir,
707722
local.include.as_deref(),
708723
local.exclude.as_deref(),
709724
)?;
@@ -712,17 +727,11 @@ fn main_result() -> anyhow::Result<i32> {
712727
let res = bench(
713728
&mut rt,
714729
pool,
715-
&ArtifactId::Tag(id),
730+
&ArtifactId::Tag(toolchain.id.clone()),
716731
&profiles,
717732
&scenarios,
718733
bench_rustc.bench_rustc,
719-
Compiler {
720-
rustc: &rustc,
721-
rustdoc: rustdoc.as_deref(),
722-
cargo: &cargo,
723-
triple: &target_triple,
724-
is_nightly: true,
725-
},
734+
Compiler::from_toolchain(&toolchain, &target_triple),
726735
&benchmarks,
727736
Some(iterations),
728737
self_profile.self_profile,
@@ -755,7 +764,13 @@ fn main_result() -> anyhow::Result<i32> {
755764

756765
match next {
757766
NextArtifact::Release(tag) => {
758-
bench_published_artifact(tag, pool, &mut rt, &target_triple, &benchmark_dir)?;
767+
bench_published_artifact(
768+
tag,
769+
pool,
770+
&mut rt,
771+
&target_triple,
772+
&compile_benchmark_dir,
773+
)?;
759774
}
760775
NextArtifact::Commit {
761776
commit,
@@ -766,8 +781,11 @@ fn main_result() -> anyhow::Result<i32> {
766781
let sysroot = Sysroot::install(commit.sha.to_string(), &target_triple)
767782
.with_context(|| format!("failed to install sysroot for {:?}", commit))?;
768783

769-
let mut benchmarks =
770-
get_benchmarks(&benchmark_dir, include.as_deref(), exclude.as_deref())?;
784+
let mut benchmarks = get_compile_benchmarks(
785+
&compile_benchmark_dir,
786+
include.as_deref(),
787+
exclude.as_deref(),
788+
)?;
771789
benchmarks.retain(|b| b.category().is_primary_or_secondary());
772790

773791
let res = bench(
@@ -794,7 +812,13 @@ fn main_result() -> anyhow::Result<i32> {
794812

795813
Commands::BenchPublished { toolchain, db } => {
796814
let pool = database::Pool::open(&db.db);
797-
bench_published_artifact(toolchain, pool, &mut rt, &target_triple, &benchmark_dir)?;
815+
bench_published_artifact(
816+
toolchain,
817+
pool,
818+
&mut rt,
819+
&target_triple,
820+
&compile_benchmark_dir,
821+
)?;
798822
Ok(0)
799823
}
800824

@@ -816,8 +840,8 @@ fn main_result() -> anyhow::Result<i32> {
816840
let profiles = &local.profiles.0;
817841
let scenarios = &local.scenarios.0;
818842

819-
let mut benchmarks = get_benchmarks(
820-
&benchmark_dir,
843+
let mut benchmarks = get_compile_benchmarks(
844+
&compile_benchmark_dir,
821845
local.include.as_deref(),
822846
local.exclude.as_deref(),
823847
)?;
@@ -833,32 +857,26 @@ fn main_result() -> anyhow::Result<i32> {
833857

834858
let mut get_toolchain_and_profile =
835859
|rustc: &str, suffix: &str| -> anyhow::Result<String> {
836-
let (rustc, rustdoc, cargo, id) = get_local_toolchain(
860+
let toolchain = get_local_toolchain(
837861
&profiles,
838862
&rustc,
839863
local.rustdoc.as_deref(),
840864
local.cargo.as_deref(),
841865
local.id.as_deref(),
842866
suffix,
843867
)?;
844-
let compiler = Compiler {
845-
rustc: &rustc,
846-
rustdoc: rustdoc.as_deref(),
847-
cargo: &cargo,
848-
triple: &target_triple,
849-
is_nightly: true,
850-
};
868+
let compiler = Compiler::from_toolchain(&toolchain, &target_triple);
851869
profile(
852870
compiler,
853-
&id,
871+
&toolchain.id,
854872
profiler,
855873
&out_dir,
856874
&benchmarks,
857875
&profiles,
858876
&scenarios,
859877
&mut errors,
860878
);
861-
Ok(id)
879+
Ok(toolchain.id)
862880
};
863881

864882
if let Some(rustc2) = rustc2 {
@@ -923,7 +941,7 @@ fn main_result() -> anyhow::Result<i32> {
923941
Ok(0)
924942
}
925943
Commands::Download(cmd) => {
926-
let target_dir = get_downloaded_crate_target(&benchmark_dir, &cmd);
944+
let target_dir = get_downloaded_crate_target(&compile_benchmark_dir, &cmd);
927945
check_target_dir(&target_dir, cmd.force)?;
928946

929947
match cmd.command {
@@ -985,7 +1003,7 @@ fn bench_published_artifact(
9851003
let cargo = which("cargo")?;
9861004

9871005
// Exclude benchmarks that don't work with a stable compiler.
988-
let mut benchmarks = get_benchmarks(&benchmark_dir, None, None)?;
1006+
let mut benchmarks = get_compile_benchmarks(&benchmark_dir, None, None)?;
9891007
benchmarks.retain(|b| b.category().is_stable());
9901008

9911009
let res = bench(

‎collector/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::process::{self, Command};
88
pub mod api;
99
pub mod benchmark;
1010
pub mod execute;
11+
pub mod runtime;
1112
pub mod toolchain;
1213
pub mod utils;
1314

‎collector/src/runtime.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::benchmark::profile::Profile;
2+
use crate::toolchain::{get_local_toolchain, LocalToolchain};
3+
use benchlib::messages::BenchmarkResult;
4+
use cargo_metadata::Message;
5+
use std::path::{Path, PathBuf};
6+
use std::process::Command;
7+
8+
#[derive(Debug)]
9+
struct BenchmarkBinary {
10+
path: PathBuf,
11+
}
12+
13+
pub fn bench_runtime(rustc: &str, id: Option<&str>, benchmark_dir: PathBuf) -> anyhow::Result<()> {
14+
let toolchain = get_local_toolchain(&[Profile::Opt], rustc, None, None, id, "")?;
15+
let output = compile_runtime_benchmarks(&toolchain, &benchmark_dir)?;
16+
let binaries = gather_binaries(&output)?;
17+
18+
for binary in binaries {
19+
let name = binary.path.file_name().and_then(|s| s.to_str()).unwrap();
20+
21+
let result = Command::new(&binary.path).arg("benchmark").output()?;
22+
if !result.status.success() {
23+
anyhow::bail!(
24+
"Failed to run runtime benchmark {name}\n{}\n{}",
25+
String::from_utf8_lossy(&result.stdout),
26+
String::from_utf8_lossy(&result.stderr)
27+
);
28+
} else {
29+
log::info!("Successfully ran runtime benchmark {name}",);
30+
31+
let data: Vec<BenchmarkResult> = serde_json::from_slice(&result.stdout)?;
32+
// TODO: do something with the result
33+
println!("{name}: {:?}", data);
34+
}
35+
}
36+
37+
Ok(())
38+
}
39+
40+
/// Compiles all runtime benchmarks and returns the stdout output of Cargo.
41+
fn compile_runtime_benchmarks(toolchain: &LocalToolchain, dir: &Path) -> anyhow::Result<Vec<u8>> {
42+
let result = Command::new(&toolchain.cargo)
43+
.env("RUSTC", &toolchain.rustc)
44+
.arg("build")
45+
.arg("--release")
46+
.arg("--message-format")
47+
.arg("json")
48+
.current_dir(dir)
49+
.output()?;
50+
51+
if !result.status.success() {
52+
anyhow::bail!(
53+
"Failed to compile runtime benchmarks\n{}\n{}",
54+
String::from_utf8_lossy(&result.stdout),
55+
String::from_utf8_lossy(&result.stderr)
56+
);
57+
} else {
58+
log::info!("Successfully compiled runtime benchmarks");
59+
return Ok(result.stdout);
60+
}
61+
}
62+
63+
/// Parse Cargo JSON output and find all compiled binaries.
64+
fn gather_binaries(cargo_stdout: &[u8]) -> anyhow::Result<Vec<BenchmarkBinary>> {
65+
let mut binaries = vec![];
66+
67+
for message in Message::parse_stream(cargo_stdout) {
68+
let message = message?;
69+
match message {
70+
Message::CompilerArtifact(artifact) => {
71+
if let Some(ref executable) = artifact.executable {
72+
if artifact.target.kind.iter().any(|k| k == "bin") {
73+
let path = executable.as_std_path().to_path_buf();
74+
binaries.push(BenchmarkBinary { path });
75+
}
76+
}
77+
}
78+
_ => {}
79+
}
80+
}
81+
82+
log::debug!("Found binaries: {:?}", binaries);
83+
84+
Ok(binaries)
85+
}

‎collector/src/toolchain.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,23 @@ impl<'a> Compiler<'a> {
233233
is_nightly: true,
234234
}
235235
}
236+
pub fn from_toolchain(toolchain: &'a LocalToolchain, target_triple: &'a str) -> Compiler<'a> {
237+
Compiler {
238+
rustc: &toolchain.rustc,
239+
rustdoc: toolchain.rustdoc.as_deref(),
240+
cargo: &toolchain.cargo,
241+
triple: target_triple,
242+
is_nightly: true,
243+
}
244+
}
245+
}
246+
247+
#[derive(Debug)]
248+
pub struct LocalToolchain {
249+
pub rustc: PathBuf,
250+
pub rustdoc: Option<PathBuf>,
251+
pub cargo: PathBuf,
252+
pub id: String,
236253
}
237254

238255
/// Get a toolchain from the input.
@@ -248,7 +265,7 @@ pub fn get_local_toolchain(
248265
cargo: Option<&Path>,
249266
id: Option<&str>,
250267
id_suffix: &str,
251-
) -> anyhow::Result<(PathBuf, Option<PathBuf>, PathBuf, String)> {
268+
) -> anyhow::Result<LocalToolchain> {
252269
// `+`-prefixed rustc is an indicator to fetch the rustc of the toolchain
253270
// specified. This follows the similar pattern used by rustup's binaries
254271
// (e.g., `rustc +stage1`).
@@ -371,5 +388,10 @@ pub fn get_local_toolchain(
371388
cargo
372389
};
373390

374-
Ok((rustc, rustdoc, cargo, id))
391+
Ok(LocalToolchain {
392+
rustc,
393+
rustdoc,
394+
cargo,
395+
id,
396+
})
375397
}

0 commit comments

Comments
 (0)
Please sign in to comment.