11use crate :: benchmark:: profile:: Profile ;
22use crate :: toolchain:: { get_local_toolchain, LocalToolchain } ;
3+ use benchlib:: benchmark:: passes_filter;
34use benchlib:: messages:: BenchmarkResult ;
45use cargo_metadata:: Message ;
56use std:: path:: { Path , PathBuf } ;
@@ -8,6 +9,46 @@ use std::process::Command;
89#[ derive( Debug ) ]
910struct BenchmarkBinary {
1011 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+ }
1152}
1253
1354/// Perform a series of runtime benchmarks using the provided `rustc` compiler.
@@ -17,19 +58,25 @@ struct BenchmarkBinary {
1758pub fn bench_runtime (
1859 rustc : & str ,
1960 id : Option < & str > ,
20- exclude : Option < String > ,
21- include : Option < String > ,
61+ filter : BenchmarkFilter ,
2262 benchmark_dir : PathBuf ,
2363) -> anyhow:: Result < ( ) > {
2464 let toolchain = get_local_toolchain ( & [ Profile :: Opt ] , rustc, None , None , id, "" ) ?;
2565 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+ ) ;
2775
28- for binary in binaries {
76+ for binary in benchmark_db . binaries {
2977 let name = binary. path . file_name ( ) . and_then ( |s| s. to_str ( ) ) . unwrap ( ) ;
3078
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) ?;
3380 // TODO: do something with the result
3481 println ! ( "{name}: {:?}" , data) ;
3582 }
@@ -43,8 +90,7 @@ pub fn bench_runtime(
4390fn execute_runtime_binary (
4491 binary : & Path ,
4592 name : & str ,
46- exclude : Option < & str > ,
47- include : Option < & str > ,
93+ filter : & BenchmarkFilter ,
4894) -> anyhow:: Result < Vec < BenchmarkResult > > {
4995 // Turn off ASLR
5096 let mut command = Command :: new ( "setarch" ) ;
@@ -53,10 +99,10 @@ fn execute_runtime_binary(
5399 command. arg ( binary) ;
54100 command. arg ( "benchmark" ) ;
55101
56- if let Some ( exclude) = exclude {
102+ if let Some ( ref exclude) = filter . exclude {
57103 command. args ( & [ "--exclude" , exclude] ) ;
58104 }
59- if let Some ( include) = include {
105+ if let Some ( ref include) = filter . include {
60106 command. args ( & [ "--include" , include] ) ;
61107 }
62108
@@ -99,7 +145,8 @@ fn compile_runtime_benchmarks(toolchain: &LocalToolchain, dir: &Path) -> anyhow:
99145}
100146
101147/// 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 > {
103150 let mut binaries = vec ! [ ] ;
104151
105152 for message in Message :: parse_stream ( cargo_stdout) {
@@ -109,7 +156,16 @@ fn gather_binaries(cargo_stdout: &[u8]) -> anyhow::Result<Vec<BenchmarkBinary>>
109156 if let Some ( ref executable) = artifact. executable {
110157 if artifact. target . kind . iter ( ) . any ( |k| k == "bin" ) {
111158 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+ } ) ;
113169 }
114170 }
115171 }
@@ -119,5 +175,12 @@ fn gather_binaries(cargo_stdout: &[u8]) -> anyhow::Result<Vec<BenchmarkBinary>>
119175
120176 log:: debug!( "Found binaries: {:?}" , binaries) ;
121177
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 ) ?)
123186}
0 commit comments