@@ -16,6 +16,7 @@ use std::collections::HashMap;
16
16
use std:: io:: { BufWriter , Write } ;
17
17
use std:: thread:: available_parallelism;
18
18
use std:: time:: { Duration , Instant } ;
19
+ use tracing:: warn;
19
20
20
21
/// Tracking information for the entire build.
21
22
///
@@ -63,6 +64,14 @@ pub struct Timings<'gctx> {
63
64
cpu_usage : Vec < ( f64 , f64 ) > ,
64
65
}
65
66
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
+
66
75
/// Tracking information for an individual unit.
67
76
struct UnitTime {
68
77
unit : Unit ,
@@ -79,6 +88,8 @@ struct UnitTime {
79
88
unlocked_units : Vec < Unit > ,
80
89
/// Same as `unlocked_units`, but unlocked by rmeta.
81
90
unlocked_rmeta_units : Vec < Unit > ,
91
+ /// Individual compilation section durations, gathered from `--json=timings`.
92
+ sections : HashMap < String , TimingSection > ,
82
93
}
83
94
84
95
/// Periodic concurrency tracking information.
@@ -181,6 +192,7 @@ impl<'gctx> Timings<'gctx> {
181
192
rmeta_time : None ,
182
193
unlocked_units : Vec :: new ( ) ,
183
194
unlocked_rmeta_units : Vec :: new ( ) ,
195
+ sections : Default :: default ( ) ,
184
196
} ;
185
197
assert ! ( self . active. insert( id, unit_time) . is_none( ) ) ;
186
198
}
@@ -233,6 +245,26 @@ impl<'gctx> Timings<'gctx> {
233
245
self . unit_times . push ( unit_time) ;
234
246
}
235
247
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
+
236
268
/// This is called periodically to mark the concurrency of internal structures.
237
269
pub fn mark_concurrency ( & mut self , active : usize , waiting : usize , inactive : usize ) {
238
270
if !self . enabled {
@@ -578,6 +610,46 @@ impl UnitTime {
578
610
fn name_ver ( & self ) -> String {
579
611
format ! ( "{} v{}" , self . unit. pkg. name( ) , self . unit. pkg. version( ) )
580
612
}
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 ,
581
653
}
582
654
583
655
fn render_rustc_info ( bcx : & BuildContext < ' _ , ' _ > ) -> String {
0 commit comments