1- use crate :: cli:: { parse_cli, Args , BenchmarkArgs } ;
1+ use crate :: cli:: { parse_cli, Args , BenchmarkArgs , ProfileArgs } ;
22use crate :: comm:: messages:: { BenchmarkMessage , BenchmarkResult , BenchmarkStats } ;
33use crate :: comm:: output_message;
44use crate :: measure:: benchmark_function;
55use crate :: process:: raise_process_priority;
6+ use crate :: profile:: profile_function;
67use std:: collections:: HashMap ;
8+ use std:: rc:: Rc ;
79
810/// Create and run a new benchmark group. Use the closure argument to register
911/// the individual benchmarks.
@@ -18,12 +20,21 @@ where
1820 group. run ( ) . expect ( "Benchmark group execution has failed" ) ;
1921}
2022
21- /// Type-erased function that executes a single benchmark.
23+ /// Type-erased function that executes a single benchmark and measures counter and wall-time
24+ /// metrics.
2225type BenchmarkFn < ' a > = Box < dyn Fn ( ) -> anyhow:: Result < BenchmarkStats > + ' a > ;
2326
27+ /// Type-erased function that executes a single benchmark once.
28+ type ProfileFn < ' a > = Box < dyn Fn ( ) + ' a > ;
29+
30+ struct BenchmarkProfileFns < ' a > {
31+ benchmark_fn : BenchmarkFn < ' a > ,
32+ profile_fn : ProfileFn < ' a > ,
33+ }
34+
2435#[ derive( Default ) ]
2536pub struct BenchmarkGroup < ' a > {
26- benchmarks : HashMap < & ' static str , BenchmarkFn < ' a > > ,
37+ benchmarks : HashMap < & ' static str , BenchmarkProfileFns < ' a > > ,
2738}
2839
2940impl < ' a > BenchmarkGroup < ' a > {
@@ -40,8 +51,13 @@ impl<'a> BenchmarkGroup<'a> {
4051 Bench : FnOnce ( ) -> R ,
4152 {
4253 // We want to type-erase the target `func` by wrapping it in a Box.
43- let benchmark_fn = Box :: new ( move || benchmark_function ( & constructor) ) ;
44- if self . benchmarks . insert ( name, benchmark_fn) . is_some ( ) {
54+ let constructor = Rc :: new ( constructor) ;
55+ let constructor2 = constructor. clone ( ) ;
56+ let benchmark_fns = BenchmarkProfileFns {
57+ benchmark_fn : Box :: new ( move || benchmark_function ( constructor. as_ref ( ) ) ) ,
58+ profile_fn : Box :: new ( move || profile_function ( constructor2. as_ref ( ) ) ) ,
59+ } ;
60+ if self . benchmarks . insert ( name, benchmark_fns) . is_some ( ) {
4561 panic ! ( "Benchmark '{}' was registered twice" , name) ;
4662 }
4763 }
@@ -56,14 +72,15 @@ impl<'a> BenchmarkGroup<'a> {
5672 Args :: Run ( args) => {
5773 self . run_benchmarks ( args) ?;
5874 }
75+ Args :: Profile ( args) => self . profile_benchmark ( args) ?,
5976 Args :: List => self . list_benchmarks ( ) ?,
6077 }
6178
6279 Ok ( ( ) )
6380 }
6481
6582 fn run_benchmarks ( self , args : BenchmarkArgs ) -> anyhow:: Result < ( ) > {
66- let mut items: Vec < ( & ' static str , BenchmarkFn ) > = self
83+ let mut items: Vec < ( & ' static str , BenchmarkProfileFns ) > = self
6784 . benchmarks
6885 . into_iter ( )
6986 . filter ( |( name, _) | {
@@ -74,17 +91,17 @@ impl<'a> BenchmarkGroup<'a> {
7491
7592 let mut stdout = std:: io:: stdout ( ) . lock ( ) ;
7693
77- for ( name, benchmark_fn ) in items {
94+ for ( name, benchmark_fns ) in items {
7895 let mut stats: Vec < BenchmarkStats > = Vec :: with_capacity ( args. iterations as usize ) ;
7996 // Warm-up
8097 for _ in 0 ..3 {
81- let benchmark_stats = benchmark_fn ( ) ?;
98+ let benchmark_stats = ( benchmark_fns . benchmark_fn ) ( ) ?;
8299 black_box ( benchmark_stats) ;
83100 }
84101
85102 // Actual measurement
86103 for i in 0 ..args. iterations {
87- let benchmark_stats = benchmark_fn ( ) ?;
104+ let benchmark_stats = ( benchmark_fns . benchmark_fn ) ( ) ?;
88105 log:: info!( "Benchmark (run {i}) `{name}` completed: {benchmark_stats:?}" ) ;
89106 stats. push ( benchmark_stats) ;
90107 }
@@ -100,6 +117,16 @@ impl<'a> BenchmarkGroup<'a> {
100117 Ok ( ( ) )
101118 }
102119
120+ fn profile_benchmark ( self , args : ProfileArgs ) -> anyhow:: Result < ( ) > {
121+ let Some ( benchmark) = self . benchmarks . get ( args. benchmark . as_str ( ) ) else {
122+ return Err ( anyhow:: anyhow!( "Benchmark `{}` not found. Available benchmarks: {}" , args. benchmark,
123+ self . benchmarks. keys( ) . map( |s| s. to_string( ) ) . collect:: <Vec <_>>( ) . join( ", " ) ) ) ;
124+ } ;
125+ ( benchmark. profile_fn ) ( ) ;
126+
127+ Ok ( ( ) )
128+ }
129+
103130 fn list_benchmarks ( self ) -> anyhow:: Result < ( ) > {
104131 let benchmark_list: Vec < & str > = self . benchmarks . into_keys ( ) . collect ( ) ;
105132 serde_json:: to_writer ( std:: io:: stdout ( ) , & benchmark_list) ?;
0 commit comments