@@ -9,6 +9,7 @@ use std::{
99} ;
1010
1111use once_cell:: sync:: Lazy ;
12+ use itertools:: Itertools ;
1213
1314/// Set profiling filter. It specifies descriptions allowed to profile.
1415/// This is helpful when call stack has too many nested profiling scopes.
@@ -179,8 +180,9 @@ impl Drop for Profiler {
179180 stack. messages . push ( Message { level, duration, message } ) ;
180181 if level == 0 {
181182 let stdout = stderr ( ) ;
182- if duration >= stack. filter_data . longer_than {
183- print ( 0 , & stack. messages , & mut stdout. lock ( ) ) ;
183+ let longer_than = stack. filter_data . longer_than ;
184+ if duration >= longer_than {
185+ print ( 0 , & stack. messages , & mut stdout. lock ( ) , longer_than) ;
184186 }
185187 stack. messages . clear ( ) ;
186188 }
@@ -191,20 +193,37 @@ impl Drop for Profiler {
191193 }
192194}
193195
194- fn print ( lvl : usize , msgs : & [ Message ] , out : & mut impl Write ) {
196+ fn print ( lvl : usize , msgs : & [ Message ] , out : & mut impl Write , longer_than : Duration ) {
195197 let mut last = 0 ;
196198 let indent = repeat ( " " ) . take ( lvl + 1 ) . collect :: < String > ( ) ;
197- for ( i, & Message { level : l, duration : dur, message : ref msg } ) in msgs. iter ( ) . enumerate ( ) {
198- if l != lvl {
199+ // We output hierarchy for long calls, but sum up all short calls
200+ let mut short = Vec :: new ( ) ;
201+ for ( i, & Message { level, duration, message : ref msg } ) in msgs. iter ( ) . enumerate ( ) {
202+ if level != lvl {
199203 continue ;
200204 }
205+ if duration >= longer_than {
206+ writeln ! ( out, "{} {:6}ms - {}" , indent, duration. as_millis( ) , msg)
207+ . expect ( "printing profiling info to stdout" ) ;
201208
202- writeln ! ( out, "{} {:6}ms - {}" , indent, dur. as_millis( ) , msg)
203- . expect ( "printing profiling info to stdout" ) ;
209+ print ( lvl + 1 , & msgs[ last..i] , out, longer_than) ;
210+ } else {
211+ short. push ( ( msg, duration) )
212+ }
204213
205- print ( lvl + 1 , & msgs[ last..i] , out) ;
206214 last = i;
207215 }
216+ short. sort_by_key ( |( msg, _time) | * msg) ;
217+ for ( msg, entires) in short. iter ( ) . group_by ( |( msg, _time) | msg) . into_iter ( ) {
218+ let mut count = 0 ;
219+ let mut total_duration = Duration :: default ( ) ;
220+ entires. for_each ( |( _msg, time) | {
221+ count += 1 ;
222+ total_duration += * time;
223+ } ) ;
224+ writeln ! ( out, "{} {:6}ms - {} ({} calls)" , indent, total_duration. as_millis( ) , msg, count)
225+ . expect ( "printing profiling info to stdout" ) ;
226+ }
208227}
209228
210229#[ cfg( test) ]
0 commit comments