@@ -82,6 +82,7 @@ struct Scope {
8282 name : & ' static str ,
8383 num_calls : usize ,
8484 duration_sum : Duration ,
85+ first_call : Instant ,
8586}
8687
8788impl Scope {
@@ -90,13 +91,17 @@ impl Scope {
9091 name,
9192 num_calls : 0 ,
9293 duration_sum : Default :: default ( ) ,
94+ first_call : Instant :: now ( ) ,
9395 }
9496 }
9597
9698 fn merge ( & mut self , other : & Self ) {
9799 if other. name == self . name {
98100 self . num_calls += other. num_calls ;
99101 self . duration_sum += other. duration_sum ;
102+ if other. first_call < self . first_call {
103+ self . first_call = other. first_call ;
104+ }
100105 }
101106 }
102107}
@@ -180,39 +185,40 @@ impl Profiler {
180185
181186fn write_recursively < W : io:: Write > (
182187 out : & mut W ,
183- scopes : & HashMap < ScopeId , Scope > ,
184- id : & ScopeId ,
188+ sorted_scopes : & [ ( ScopeId , Scope ) ] ,
189+ current : & ( ScopeId , Scope ) ,
185190 total_duration : Option < Duration > ,
186191 depth : usize ,
187192) -> io:: Result < ( ) > {
188- if let Some ( scope) = scopes. get ( id) {
189- let current_hash = ScopeId :: get_hash ( Some ( id) ) ;
193+ let ( id, scope) = current;
190194
191- for _ in 0 ..depth {
192- write ! ( out, " " ) ?;
193- }
195+ for _ in 0 ..depth {
196+ write ! ( out, " " ) ?;
197+ }
194198
195- let duration_sum_secs = scope. duration_sum . as_secs_f64 ( ) ;
196- let total_duration_secs = total_duration. map_or ( duration_sum_secs, |t| t. as_secs_f64 ( ) ) ;
197- let percent = duration_sum_secs / total_duration_secs * 100.0 ;
198-
199- writeln ! (
200- out,
201- "{}: {:3.2}%, {:>4.2}ms avg @ {:.2}Hz ({} {})" ,
202- scope. name,
203- percent,
204- duration_sum_secs * 1000.0 / ( scope. num_calls as f64 ) ,
205- scope. num_calls as f64 / total_duration_secs,
206- scope. num_calls,
207- if scope. num_calls > 1 { "calls" } else { "call" }
208- ) ?;
209-
210- // TODO: Prevent infinite recursion for recursive functions, maybe remove current scope from map?
211- // Maybe we don't have this problem, instead it will be a huge chain which is as long as the recursion depth...
212- for child_id in scopes. keys ( ) {
213- if child_id. parent_hash == current_hash {
214- write_recursively ( out, scopes, child_id, Some ( scope. duration_sum ) , depth + 1 ) ?;
215- }
199+ let duration_sum_secs = scope. duration_sum . as_secs_f64 ( ) ;
200+ let total_duration_secs = total_duration. map_or ( duration_sum_secs, |t| t. as_secs_f64 ( ) ) ;
201+ let percent = duration_sum_secs / total_duration_secs * 100.0 ;
202+
203+ writeln ! (
204+ out,
205+ "{}: {:3.2}%, {:>4.2}ms avg @ {:.2}Hz ({} {})" ,
206+ scope. name,
207+ percent,
208+ duration_sum_secs * 1000.0 / ( scope. num_calls as f64 ) ,
209+ scope. num_calls as f64 / total_duration_secs,
210+ scope. num_calls,
211+ if scope. num_calls > 1 { "calls" } else { "call" }
212+ ) ?;
213+
214+ // Process children in sorted order
215+ let current_hash = ScopeId :: get_hash ( Some ( id) ) ;
216+ for s in sorted_scopes {
217+ let ( child_id, _) = s;
218+ if child_id. parent_hash == current_hash {
219+ // TODO: Prevent infinite recursion for recursive functions, maybe remove current scope from map?
220+ // Maybe we don't have this problem, instead it will be a huge chain which is as long as the recursion depth...
221+ write_recursively ( out, sorted_scopes, s, Some ( scope. duration_sum ) , depth + 1 ) ?;
216222 }
217223 }
218224
@@ -238,15 +244,31 @@ pub fn write<W: io::Write>(out: &mut W) -> io::Result<()> {
238244 }
239245 }
240246
241- // Remove roots that are not actual roots (happens if their parent was set manually)
242- {
247+ // Sort and filter root scopes
248+ let sorted_roots = {
243249 let root_hash = ScopeId :: get_hash ( None ) ;
244- roots. retain ( |id| id. parent_hash == root_hash) ;
245- }
250+ let mut roots = roots
251+ . into_iter ( )
252+ // Remove roots that are not actual roots (happens if their parent was set manually)
253+ . filter ( |id| id. parent_hash == root_hash)
254+ // Get (id, scope) tuple
255+ . flat_map ( |id| merged_scopes. get ( & id) . cloned ( ) . map ( |s| ( id, s) ) )
256+ . collect :: < Vec < _ > > ( ) ;
257+
258+ roots. sort_unstable_by_key ( |( _, s) | s. first_call ) ;
259+ roots
260+ } ;
261+
262+ // Sort all scopes by first call time
263+ let sorted_scopes = {
264+ let mut scopes = merged_scopes. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
265+ scopes. sort_unstable_by_key ( |( _, s) | s. first_call ) ;
266+ scopes
267+ } ;
246268
247269 // Print the stats
248- for root_id in & roots {
249- write_recursively ( out, & merged_scopes , root_id , None , 0 ) ?;
270+ for root in & sorted_roots {
271+ write_recursively ( out, sorted_scopes . as_slice ( ) , root , None , 0 ) ?;
250272 }
251273
252274 Ok ( ( ) )
0 commit comments