@@ -16,6 +16,7 @@ use std::collections::HashMap;
1616use std:: io:: { BufWriter , Write } ;
1717use std:: thread:: available_parallelism;
1818use std:: time:: { Duration , Instant } ;
19+ use tracing:: warn;
1920
2021/// Tracking information for the entire build.
2122///
@@ -63,6 +64,14 @@ pub struct Timings<'gctx> {
6364 cpu_usage : Vec < ( f64 , f64 ) > ,
6465}
6566
67+ /// Section of compilation.
68+ struct TimingSection {
69+ /// Start of the section, as an offset in seconds from `UnitTime::start`.
70+ start : f64 ,
71+ /// End of the section, as an offset in seconds from `UnitTime::start`.
72+ end : Option < f64 > ,
73+ }
74+
6675/// Tracking information for an individual unit.
6776struct UnitTime {
6877 unit : Unit ,
@@ -79,6 +88,8 @@ struct UnitTime {
7988 unlocked_units : Vec < Unit > ,
8089 /// Same as `unlocked_units`, but unlocked by rmeta.
8190 unlocked_rmeta_units : Vec < Unit > ,
91+ /// Individual compilation section durations, gathered from `--json=timings`.
92+ sections : HashMap < String , TimingSection > ,
8293}
8394
8495/// Periodic concurrency tracking information.
@@ -181,6 +192,7 @@ impl<'gctx> Timings<'gctx> {
181192 rmeta_time : None ,
182193 unlocked_units : Vec :: new ( ) ,
183194 unlocked_rmeta_units : Vec :: new ( ) ,
195+ sections : Default :: default ( ) ,
184196 } ;
185197 assert ! ( self . active. insert( id, unit_time) . is_none( ) ) ;
186198 }
@@ -233,6 +245,26 @@ impl<'gctx> Timings<'gctx> {
233245 self . unit_times . push ( unit_time) ;
234246 }
235247
248+ /// Handle the start/end of a compilation section.
249+ pub fn unit_section_timing ( & mut self , id : JobId , section_timing : & SectionTiming ) {
250+ if !self . enabled {
251+ return ;
252+ }
253+ let Some ( unit_time) = self . active . get_mut ( & id) else {
254+ return ;
255+ } ;
256+ let now = self . start . elapsed ( ) . as_secs_f64 ( ) ;
257+
258+ match section_timing. event {
259+ SectionTimingEvent :: Start => {
260+ unit_time. start_section ( & section_timing. name , now) ;
261+ }
262+ SectionTimingEvent :: End => {
263+ unit_time. end_section ( & section_timing. name , now) ;
264+ }
265+ }
266+ }
267+
236268 /// This is called periodically to mark the concurrency of internal structures.
237269 pub fn mark_concurrency ( & mut self , active : usize , waiting : usize , inactive : usize ) {
238270 if !self . enabled {
@@ -578,6 +610,46 @@ impl UnitTime {
578610 fn name_ver ( & self ) -> String {
579611 format ! ( "{} v{}" , self . unit. pkg. name( ) , self . unit. pkg. version( ) )
580612 }
613+
614+ fn start_section ( & mut self , name : & str , now : f64 ) {
615+ if self
616+ . sections
617+ . insert (
618+ name. to_string ( ) ,
619+ TimingSection {
620+ start : now - self . start ,
621+ end : None ,
622+ } ,
623+ )
624+ . is_some ( )
625+ {
626+ warn ! ( "Compilation section {name} started more than once" ) ;
627+ }
628+ }
629+
630+ fn end_section ( & mut self , name : & str , now : f64 ) {
631+ let Some ( section) = self . sections . get_mut ( name) else {
632+ warn ! ( "Compilation section {name} ended, but it has no start recorded" ) ;
633+ return ;
634+ } ;
635+ section. end = Some ( now - self . start ) ;
636+ }
637+ }
638+
639+ /// Start or end of a section timing.
640+ #[ derive( serde:: Deserialize , Debug ) ]
641+ #[ serde( rename_all = "kebab-case" ) ]
642+ pub enum SectionTimingEvent {
643+ Start ,
644+ End ,
645+ }
646+
647+ /// Represents a certain section (phase) of rustc compilation.
648+ /// It is emitted by rustc when the `--json=timings` flag is used.
649+ #[ derive( serde:: Deserialize , Debug ) ]
650+ pub struct SectionTiming {
651+ pub name : String ,
652+ pub event : SectionTimingEvent ,
581653}
582654
583655fn render_rustc_info ( bcx : & BuildContext < ' _ , ' _ > ) -> String {
0 commit comments