1
1
use crate :: benchmark:: profile:: Profile ;
2
2
use crate :: toolchain:: { get_local_toolchain, LocalToolchain } ;
3
+ use benchlib:: benchmark:: passes_filter;
3
4
use benchlib:: messages:: BenchmarkResult ;
4
5
use cargo_metadata:: Message ;
5
6
use std:: path:: { Path , PathBuf } ;
@@ -8,6 +9,46 @@ use std::process::Command;
8
9
#[ derive( Debug ) ]
9
10
struct BenchmarkBinary {
10
11
path : PathBuf ,
12
+ benchmark_names : Vec < String > ,
13
+ }
14
+
15
+ #[ derive( Debug ) ]
16
+ struct BenchmarkDatabase {
17
+ binaries : Vec < BenchmarkBinary > ,
18
+ }
19
+
20
+ impl BenchmarkDatabase {
21
+ fn benchmark_names ( & self ) -> impl Iterator < Item = & str > {
22
+ self . binaries
23
+ . iter ( )
24
+ . flat_map ( |binary| binary. benchmark_names . iter ( ) . map ( |n| n. as_ref ( ) ) )
25
+ }
26
+
27
+ fn total_benchmark_count ( & self ) -> u64 {
28
+ self . benchmark_names ( ) . count ( ) as u64
29
+ }
30
+ fn filtered_benchmark_count ( & self , filter : & BenchmarkFilter ) -> u64 {
31
+ self . benchmark_names ( )
32
+ . filter ( |benchmark| {
33
+ passes_filter (
34
+ & benchmark,
35
+ filter. exclude . as_deref ( ) ,
36
+ filter. include . as_deref ( ) ,
37
+ )
38
+ } )
39
+ . count ( ) as u64
40
+ }
41
+ }
42
+
43
+ pub struct BenchmarkFilter {
44
+ exclude : Option < String > ,
45
+ include : Option < String > ,
46
+ }
47
+
48
+ impl BenchmarkFilter {
49
+ pub fn new ( exclude : Option < String > , include : Option < String > ) -> BenchmarkFilter {
50
+ Self { exclude, include }
51
+ }
11
52
}
12
53
13
54
/// Perform a series of runtime benchmarks using the provided `rustc` compiler.
@@ -17,19 +58,25 @@ struct BenchmarkBinary {
17
58
pub fn bench_runtime (
18
59
rustc : & str ,
19
60
id : Option < & str > ,
20
- exclude : Option < String > ,
21
- include : Option < String > ,
61
+ filter : BenchmarkFilter ,
22
62
benchmark_dir : PathBuf ,
23
63
) -> anyhow:: Result < ( ) > {
24
64
let toolchain = get_local_toolchain ( & [ Profile :: Opt ] , rustc, None , None , id, "" ) ?;
25
65
let output = compile_runtime_benchmarks ( & toolchain, & benchmark_dir) ?;
26
- let binaries = gather_binaries ( & output) ?;
66
+ let benchmark_db = discover_benchmarks ( & output) ?;
67
+
68
+ let total_benchmark_count = benchmark_db. total_benchmark_count ( ) ;
69
+ let filtered = benchmark_db. filtered_benchmark_count ( & filter) ;
70
+ println ! (
71
+ "Executing {} benchmarks ({} filtered out)" ,
72
+ filtered,
73
+ total_benchmark_count - filtered
74
+ ) ;
27
75
28
- for binary in binaries {
76
+ for binary in benchmark_db . binaries {
29
77
let name = binary. path . file_name ( ) . and_then ( |s| s. to_str ( ) ) . unwrap ( ) ;
30
78
31
- let data: Vec < BenchmarkResult > =
32
- execute_runtime_binary ( & binary. path , name, exclude. as_deref ( ) , include. as_deref ( ) ) ?;
79
+ let data: Vec < BenchmarkResult > = execute_runtime_binary ( & binary. path , name, & filter) ?;
33
80
// TODO: do something with the result
34
81
println ! ( "{name}: {:?}" , data) ;
35
82
}
@@ -43,8 +90,7 @@ pub fn bench_runtime(
43
90
fn execute_runtime_binary (
44
91
binary : & Path ,
45
92
name : & str ,
46
- exclude : Option < & str > ,
47
- include : Option < & str > ,
93
+ filter : & BenchmarkFilter ,
48
94
) -> anyhow:: Result < Vec < BenchmarkResult > > {
49
95
// Turn off ASLR
50
96
let mut command = Command :: new ( "setarch" ) ;
@@ -53,10 +99,10 @@ fn execute_runtime_binary(
53
99
command. arg ( binary) ;
54
100
command. arg ( "benchmark" ) ;
55
101
56
- if let Some ( exclude) = exclude {
102
+ if let Some ( ref exclude) = filter . exclude {
57
103
command. args ( & [ "--exclude" , exclude] ) ;
58
104
}
59
- if let Some ( include) = include {
105
+ if let Some ( ref include) = filter . include {
60
106
command. args ( & [ "--include" , include] ) ;
61
107
}
62
108
@@ -99,7 +145,8 @@ fn compile_runtime_benchmarks(toolchain: &LocalToolchain, dir: &Path) -> anyhow:
99
145
}
100
146
101
147
/// Parse Cargo JSON output and find all compiled binaries.
102
- fn gather_binaries ( cargo_stdout : & [ u8 ] ) -> anyhow:: Result < Vec < BenchmarkBinary > > {
148
+ /// Then execute each benchmark with the `list-benchmarks` command to find out its benchmark names.
149
+ fn discover_benchmarks ( cargo_stdout : & [ u8 ] ) -> anyhow:: Result < BenchmarkDatabase > {
103
150
let mut binaries = vec ! [ ] ;
104
151
105
152
for message in Message :: parse_stream ( cargo_stdout) {
@@ -109,7 +156,16 @@ fn gather_binaries(cargo_stdout: &[u8]) -> anyhow::Result<Vec<BenchmarkBinary>>
109
156
if let Some ( ref executable) = artifact. executable {
110
157
if artifact. target . kind . iter ( ) . any ( |k| k == "bin" ) {
111
158
let path = executable. as_std_path ( ) . to_path_buf ( ) ;
112
- binaries. push ( BenchmarkBinary { path } ) ;
159
+ let benchmarks = gather_benchmarks ( & path) . map_err ( |err| {
160
+ anyhow:: anyhow!(
161
+ "Cannot gather benchmarks from `{}`: {err:?}" ,
162
+ path. display( )
163
+ )
164
+ } ) ?;
165
+ binaries. push ( BenchmarkBinary {
166
+ path,
167
+ benchmark_names : benchmarks,
168
+ } ) ;
113
169
}
114
170
}
115
171
}
@@ -119,5 +175,12 @@ fn gather_binaries(cargo_stdout: &[u8]) -> anyhow::Result<Vec<BenchmarkBinary>>
119
175
120
176
log:: debug!( "Found binaries: {:?}" , binaries) ;
121
177
122
- Ok ( binaries)
178
+ Ok ( BenchmarkDatabase { binaries } )
179
+ }
180
+
181
+ /// Uses the `list-benchmarks` command from `benchlib` to find the benchmark names from the given
182
+ /// benchmark binary.
183
+ fn gather_benchmarks ( binary : & Path ) -> anyhow:: Result < Vec < String > > {
184
+ let output = Command :: new ( binary) . arg ( "list-benchmarks" ) . output ( ) ?;
185
+ Ok ( serde_json:: from_slice ( & output. stdout ) ?)
123
186
}
0 commit comments