Skip to content

Commit a0cdd32

Browse files
authored
Merge pull request #2206 from Kobzol/benchmark-set
Add basic benchmark set implementation
2 parents bf1b41f + c935f7c commit a0cdd32

File tree

7 files changed

+272
-7
lines changed

7 files changed

+272
-7
lines changed

collector/compile-benchmarks/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ Rust code being written today.
203203
applies correctly, e.g. `target/release/collector bench_local +nightly
204204
--id Test --profiles=Check --scenarios=IncrPatched
205205
--include=$NEW_BENCHMARK`
206+
- Add the new entry to `collector/src/benchmark_set/compile_benchmarks.rs`.
206207
- Add the new entry to `collector/compile-benchmarks/README.md`.
207208
- Add a new licensing entry to `collector/compile-benchmarks/REUSE.toml` (see existing entries
208209
for inspiration).
@@ -245,6 +246,7 @@ Rust code being written today.
245246
- In the first commit just remove the old code.
246247
- Do this with `git rm -r` on the directory.
247248
- In the second commit do everything else.
249+
- Remove the entry from `collector/src/benchmark_set/compile_benchmarks.rs`.
248250
- Remove the entry from `collector/compile-benchmarks/README.md`.
249251
- Remove the entry from `collector/compile-benchmarks/REUSE.toml`.
250252
- `git grep` for occurrences of the old benchmark name (e.g. in
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! This file contains an exhaustive list of all **non-stable** compile-time benchmarks
2+
//! located in the `collector/compile-benchmarks` directory that are benchmarked in production.
3+
//! If new benchmarks are added/removed, they have to also be added/removed here, and in
4+
//! the [super::expand_benchmark_set] function.
5+
6+
pub(super) const AWAIT_CALL_TREE: &str = "await-call-tree";
7+
pub(super) const BITMAPS_3_2_1: &str = "bitmaps-3.2.1";
8+
pub(super) const BITMAPS_3_2_1_NEW_SOLVER: &str = "bitmaps-3.2.1-new-solver";
9+
pub(super) const CARGO_0_87_1: &str = "cargo-0.87.1";
10+
pub(super) const CLAP_DERIVE_4_5_32: &str = "clap_derive-4.5.32";
11+
pub(super) const COERCIONS: &str = "coercions";
12+
pub(super) const CRANELIFT_CODEGEN_0_119_0: &str = "cranelift-codegen-0.119.0";
13+
pub(super) const CTFE_STRESS_5: &str = "ctfe-stress-5";
14+
pub(super) const DEEP_VECTOR: &str = "deep-vector";
15+
pub(super) const DEEPLY_NESTED_MULTI: &str = "deeply-nested-multi";
16+
pub(super) const DERIVE: &str = "derive";
17+
pub(super) const DIESEL_2_2_10: &str = "diesel-2.2.10";
18+
pub(super) const EXTERNS: &str = "externs";
19+
pub(super) const EZA_0_21_2: &str = "eza-0.21.2";
20+
pub(super) const HELLOWORLD: &str = "helloworld";
21+
pub(super) const HELLOWORLD_TINY: &str = "helloworld-tiny";
22+
pub(super) const HTML5EVER_0_31_0: &str = "html5ever-0.31.0";
23+
pub(super) const HTML5EVER_0_31_0_NEW_SOLVER: &str = "html5ever-0.31.0-new-solver";
24+
pub(super) const HYPER_1_6_0: &str = "hyper-1.6.0";
25+
pub(super) const IMAGE_0_25_6: &str = "image-0.25.6";
26+
pub(super) const INCLUDE_BLOB: &str = "include-blob";
27+
pub(super) const ISSUE_46449: &str = "issue-46449";
28+
pub(super) const ISSUE_58319: &str = "issue-58319";
29+
pub(super) const ISSUE_88862: &str = "issue-88862";
30+
pub(super) const LARGE_WORKSPACE: &str = "large-workspace";
31+
pub(super) const LIBC_0_2_172: &str = "libc-0.2.172";
32+
pub(super) const MANY_ASSOC_ITEMS: &str = "many-assoc-items";
33+
pub(super) const MATCH_STRESS: &str = "match-stress";
34+
pub(super) const NALGEBRA_0_33_0: &str = "nalgebra-0.33.0";
35+
pub(super) const NALGEBRA_0_33_0_NEW_SOLVER: &str = "nalgebra-0.33.0-new-solver";
36+
pub(super) const PROJECTION_CACHING: &str = "projection-caching";
37+
pub(super) const REGEX_AUTOMATA_0_4_8: &str = "regex-automata-0.4.8";
38+
pub(super) const REGRESSION_31157: &str = "regression-31157";
39+
pub(super) const RIPGREP_14_1_1: &str = "ripgrep-14.1.1";
40+
pub(super) const RIPGREP_14_1_1_TINY: &str = "ripgrep-14.1.1-tiny";
41+
pub(super) const SERDE_1_0_219: &str = "serde-1.0.219";
42+
pub(super) const SERDE_1_0_219_NEW_SOLVER: &str = "serde-1.0.219-new-solver";
43+
pub(super) const SERDE_1_0_219_THREADS4: &str = "serde-1.0.219-threads4";
44+
pub(super) const SERDE_DERIVE_1_0_219: &str = "serde_derive-1.0.219";
45+
pub(super) const STM32F4_0_15_1: &str = "stm32f4-0.15.1";
46+
pub(super) const SYN_2_0_101: &str = "syn-2.0.101";
47+
pub(super) const SYN_2_0_101_NEW_SOLVER: &str = "syn-2.0.101-new-solver";
48+
pub(super) const TOKEN_STREAM_STRESS: &str = "token-stream-stress";
49+
pub(super) const TT_MUNCHER: &str = "tt-muncher";
50+
pub(super) const TUPLE_STRESS: &str = "tuple-stress";
51+
pub(super) const TYPENUM_1_18_0: &str = "typenum-1.18.0";
52+
pub(super) const UCD: &str = "ucd";
53+
pub(super) const UNICODE_NORMALIZATION_0_1_24: &str = "unicode-normalization-0.1.24";
54+
pub(super) const UNIFY_LINEARLY: &str = "unify-linearly";
55+
pub(super) const UNUSED_WARNINGS: &str = "unused-warnings";
56+
pub(super) const WF_PROJECTION_STRESS_65510: &str = "wf-projection-stress-65510";
57+
pub(super) const WG_GRAMMAR: &str = "wg-grammar";

collector/src/benchmark_set/mod.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
//! This module serves for defining the benchmark sets that are used by individual collectors.
2+
//! Each benchmark set is identified by a pair (target, ID); each target has a specific number
3+
//! of IDs.
4+
//! The union of all benchmark sets for a given target should represent all the benchmarks that
5+
//! should be executed on a master/try artifact.
6+
//! Release artifacts do not participate in the benchmark set splitting and are always executed
7+
//! on a single collector per target.
8+
9+
mod compile_benchmarks;
10+
11+
use crate::compile::benchmark::target::Target;
12+
use crate::compile::benchmark::BenchmarkName;
13+
14+
/// Represents a single set of master/try benchmarks.
15+
#[derive(Debug)]
16+
pub struct BenchmarkSetId {
17+
target: Target,
18+
index: u32,
19+
}
20+
21+
impl BenchmarkSetId {
22+
pub fn new(target: Target, index: u32) -> Self {
23+
Self { target, index }
24+
}
25+
}
26+
27+
/// Represents a subset of benchmarks that should be benchmarked by a single collector.
28+
#[derive(Debug, PartialEq, Eq, Hash)]
29+
pub enum BenchmarkSetMember {
30+
/// Benchmark a specific compile-time benchmark
31+
CompileBenchmark(BenchmarkName),
32+
/// Benchmark *all* the runtime benchmarks.
33+
/// For simplicity, we currently always benchmark all of them on a single collector.
34+
RuntimeBenchmarks,
35+
/// Benchmark the rustc bootstrap
36+
Rustc,
37+
}
38+
39+
/// Return the number of benchmark sets for the given target.
40+
pub fn benchmark_set_count(target: Target) -> usize {
41+
match target {
42+
Target::X86_64UnknownLinuxGnu => 1,
43+
}
44+
}
45+
46+
/// Expand all the benchmarks that should be performed by a single collector.
47+
pub fn expand_benchmark_set(id: BenchmarkSetId) -> Vec<BenchmarkSetMember> {
48+
use compile_benchmarks::*;
49+
50+
match (id.target, id.index) {
51+
(Target::X86_64UnknownLinuxGnu, 0) => {
52+
vec![
53+
compile(AWAIT_CALL_TREE),
54+
compile(BITMAPS_3_2_1),
55+
compile(BITMAPS_3_2_1_NEW_SOLVER),
56+
compile(CARGO_0_87_1),
57+
compile(CLAP_DERIVE_4_5_32),
58+
compile(COERCIONS),
59+
compile(CRANELIFT_CODEGEN_0_119_0),
60+
compile(CTFE_STRESS_5),
61+
compile(DEEP_VECTOR),
62+
compile(DEEPLY_NESTED_MULTI),
63+
compile(DERIVE),
64+
compile(DIESEL_2_2_10),
65+
compile(EXTERNS),
66+
compile(EZA_0_21_2),
67+
compile(HELLOWORLD),
68+
compile(HELLOWORLD_TINY),
69+
compile(HTML5EVER_0_31_0),
70+
compile(HTML5EVER_0_31_0_NEW_SOLVER),
71+
compile(HYPER_1_6_0),
72+
compile(IMAGE_0_25_6),
73+
compile(INCLUDE_BLOB),
74+
compile(ISSUE_46449),
75+
compile(ISSUE_58319),
76+
compile(ISSUE_88862),
77+
compile(LARGE_WORKSPACE),
78+
compile(LIBC_0_2_172),
79+
compile(MANY_ASSOC_ITEMS),
80+
compile(MATCH_STRESS),
81+
compile(NALGEBRA_0_33_0),
82+
compile(NALGEBRA_0_33_0_NEW_SOLVER),
83+
compile(PROJECTION_CACHING),
84+
compile(REGEX_AUTOMATA_0_4_8),
85+
compile(REGRESSION_31157),
86+
compile(RIPGREP_14_1_1),
87+
compile(RIPGREP_14_1_1_TINY),
88+
compile(SERDE_1_0_219),
89+
compile(SERDE_1_0_219_NEW_SOLVER),
90+
compile(SERDE_1_0_219_THREADS4),
91+
compile(SERDE_DERIVE_1_0_219),
92+
compile(STM32F4_0_15_1),
93+
compile(SYN_2_0_101),
94+
compile(SYN_2_0_101_NEW_SOLVER),
95+
compile(TOKEN_STREAM_STRESS),
96+
compile(TT_MUNCHER),
97+
compile(TUPLE_STRESS),
98+
compile(TYPENUM_1_18_0),
99+
compile(UCD),
100+
compile(UNICODE_NORMALIZATION_0_1_24),
101+
compile(UNIFY_LINEARLY),
102+
compile(UNUSED_WARNINGS),
103+
compile(WF_PROJECTION_STRESS_65510),
104+
compile(WG_GRAMMAR),
105+
BenchmarkSetMember::Rustc,
106+
BenchmarkSetMember::RuntimeBenchmarks,
107+
]
108+
}
109+
(Target::X86_64UnknownLinuxGnu, 1..) => {
110+
panic!("Unknown benchmark set id {id:?}");
111+
}
112+
}
113+
}
114+
115+
/// Helper function for creating compile-time benchmark member sets.
116+
fn compile(name: &str) -> BenchmarkSetMember {
117+
BenchmarkSetMember::CompileBenchmark(BenchmarkName::from(name))
118+
}
119+
120+
#[cfg(test)]
121+
mod tests {
122+
use crate::benchmark_set::{
123+
benchmark_set_count, expand_benchmark_set, BenchmarkSetId, BenchmarkSetMember,
124+
};
125+
use crate::compile::benchmark::target::Target;
126+
use crate::compile::benchmark::{
127+
get_compile_benchmarks, BenchmarkName, CompileBenchmarkFilter,
128+
};
129+
use std::collections::HashSet;
130+
use std::path::Path;
131+
132+
/// Sanity check for making sure that the expanded benchmark sets are non-overlapping and
133+
/// complete, i.e. they don't miss any benchmarks.
134+
#[test]
135+
fn check_benchmark_set_x64() {
136+
let target = Target::X86_64UnknownLinuxGnu;
137+
let sets = (0..benchmark_set_count(target))
138+
.map(|index| {
139+
expand_benchmark_set(BenchmarkSetId {
140+
target,
141+
index: index as u32,
142+
})
143+
})
144+
.collect::<Vec<Vec<BenchmarkSetMember>>>();
145+
146+
// Assert set is unique
147+
for set in &sets {
148+
let hashset = set.iter().collect::<HashSet<_>>();
149+
assert_eq!(
150+
set.len(),
151+
hashset.len(),
152+
"Benchmark set {set:?} contains duplicates"
153+
);
154+
}
155+
156+
// Go through all unique pairs of sets and assert that they don't overlap
157+
for i in 0..sets.len() {
158+
for j in i + 1..sets.len() {
159+
let set_a = &sets[i];
160+
let set_b = &sets[j];
161+
let hashset_a = set_a.iter().collect::<HashSet<_>>();
162+
let hashset_b = set_b.iter().collect::<HashSet<_>>();
163+
assert!(
164+
hashset_a.is_disjoint(&hashset_b),
165+
"Benchmark sets {set_a:?} and {set_b:?} overlap"
166+
);
167+
}
168+
}
169+
170+
// Check that the union of all sets contains all the required benchmarks
171+
let all_members = sets.iter().flatten().collect::<HashSet<_>>();
172+
assert!(all_members.contains(&BenchmarkSetMember::Rustc));
173+
assert!(all_members.contains(&BenchmarkSetMember::RuntimeBenchmarks));
174+
175+
const BENCHMARK_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/compile-benchmarks");
176+
let all_compile_benchmarks =
177+
get_compile_benchmarks(Path::new(BENCHMARK_DIR), CompileBenchmarkFilter::All)
178+
.unwrap()
179+
.into_iter()
180+
.filter(|b| !b.category().is_stable())
181+
.map(|b| b.name)
182+
.collect::<Vec<BenchmarkName>>();
183+
for benchmark in &all_compile_benchmarks {
184+
assert!(
185+
all_members.contains(&BenchmarkSetMember::CompileBenchmark(benchmark.clone())),
186+
"Compile-time benchmark `{benchmark}` is missing in the union of all sets"
187+
);
188+
}
189+
for benchmark in &all_members {
190+
if let BenchmarkSetMember::CompileBenchmark(name) = benchmark {
191+
assert!(
192+
all_compile_benchmarks.contains(name),
193+
"Compile-time benchmark {name} does not exist on disk or is a stable benchmark"
194+
);
195+
}
196+
}
197+
assert_eq!(all_members.len(), all_compile_benchmarks.len() + 2);
198+
}
199+
}

collector/src/bin/collector.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,12 +1042,7 @@ fn main_result() -> anyhow::Result<i32> {
10421042

10431043
let compile_config = CompileBenchmarkConfig {
10441044
benchmarks,
1045-
profiles: vec![
1046-
Profile::Check,
1047-
Profile::Debug,
1048-
Profile::Doc,
1049-
Profile::Opt,
1050-
],
1045+
profiles: Profile::default_profiles(),
10511046
scenarios: Scenario::all(),
10521047
backends,
10531048
iterations: runs.map(|v| v as usize),

collector/src/compile/benchmark/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,15 @@ impl BenchmarkConfig {
9898
}
9999
}
100100

101-
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
101+
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Debug)]
102102
pub struct BenchmarkName(pub String);
103103

104+
impl<'a> From<&'a str> for BenchmarkName {
105+
fn from(value: &'a str) -> Self {
106+
Self(value.to_string())
107+
}
108+
}
109+
104110
impl std::fmt::Display for BenchmarkName {
105111
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106112
write!(f, "{}", self.0)

collector/src/compile/benchmark/profile.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ impl Profile {
3434
]
3535
}
3636

37+
/// Set of default profiles that should be benchmarked for a master/try artifact.
38+
pub fn default_profiles() -> Vec<Self> {
39+
vec![Profile::Check, Profile::Debug, Profile::Doc, Profile::Opt]
40+
}
41+
3742
pub fn is_doc(&self) -> bool {
3843
match self {
3944
Profile::Doc | Profile::DocJson => true,

collector/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::process::{self, Command};
77

88
pub mod api;
99
pub mod artifact_stats;
10+
pub mod benchmark_set;
1011
pub mod cargo;
1112
pub mod codegen;
1213
pub mod compare;

0 commit comments

Comments
 (0)