@@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
9797pub use measureme:: EventId ;
9898use measureme:: { EventIdBuilder , Profiler , SerializableString , StringId } ;
9999use parking_lot:: RwLock ;
100+ use serde_json:: json;
100101use smallvec:: SmallVec ;
101102
102103bitflags:: bitflags! {
@@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
145146/// Something that uniquely identifies a query invocation.
146147pub struct QueryInvocationId ( pub u32 ) ;
147148
149+ /// Which format to use for `-Z time-passes`
150+ #[ derive( Clone , Copy , PartialEq , Hash , Debug ) ]
151+ pub enum TimePassesFormat {
152+ /// Emit human readable text
153+ Text ,
154+ /// Emit structured JSON
155+ Json ,
156+ }
157+
148158/// A reference to the SelfProfiler. It can be cloned and sent across thread
149159/// boundaries at will.
150160#[ derive( Clone ) ]
@@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
158168 // actually enabled.
159169 event_filter_mask : EventFilter ,
160170
161- // Print verbose generic activities to stderr?
162- print_verbose_generic_activities : bool ,
171+ // Print verbose generic activities to stderr.
172+ print_verbose_generic_activities : Option < TimePassesFormat > ,
163173}
164174
165175impl SelfProfilerRef {
166176 pub fn new (
167177 profiler : Option < Arc < SelfProfiler > > ,
168- print_verbose_generic_activities : bool ,
178+ print_verbose_generic_activities : Option < TimePassesFormat > ,
169179 ) -> SelfProfilerRef {
170180 // If there is no SelfProfiler then the filter mask is set to NONE,
171181 // ensuring that nothing ever tries to actually access it.
@@ -207,9 +217,10 @@ impl SelfProfilerRef {
207217 /// a measureme event, "verbose" generic activities also print a timing entry to
208218 /// stderr if the compiler is invoked with -Ztime-passes.
209219 pub fn verbose_generic_activity ( & self , event_label : & ' static str ) -> VerboseTimingGuard < ' _ > {
210- let message = self . print_verbose_generic_activities . then ( || event_label. to_owned ( ) ) ;
220+ let message_and_format =
221+ self . print_verbose_generic_activities . map ( |format| ( event_label. to_owned ( ) , format) ) ;
211222
212- VerboseTimingGuard :: start ( message , self . generic_activity ( event_label) )
223+ VerboseTimingGuard :: start ( message_and_format , self . generic_activity ( event_label) , false )
213224 }
214225
215226 /// Like `verbose_generic_activity`, but with an extra arg.
@@ -221,11 +232,26 @@ impl SelfProfilerRef {
221232 where
222233 A : Borrow < str > + Into < String > ,
223234 {
224- let message = self
235+ let message_and_format = self
225236 . print_verbose_generic_activities
226- . then ( || format ! ( "{}({})" , event_label, event_arg. borrow( ) ) ) ;
237+ . map ( |format| ( format ! ( "{}({})" , event_label, event_arg. borrow( ) ) , format ) ) ;
227238
228- VerboseTimingGuard :: start ( message, self . generic_activity_with_arg ( event_label, event_arg) )
239+ VerboseTimingGuard :: start (
240+ message_and_format,
241+ self . generic_activity_with_arg ( event_label, event_arg) ,
242+ false ,
243+ )
244+ }
245+
246+ /// Like `verbose_generic_activity`, but `event_label` must be unique for a rustc session.
247+ pub fn unique_verbose_generic_activity (
248+ & self ,
249+ event_label : & ' static str ,
250+ ) -> VerboseTimingGuard < ' _ > {
251+ let message_and_format =
252+ self . print_verbose_generic_activities . map ( |format| ( event_label. to_owned ( ) , format) ) ;
253+
254+ VerboseTimingGuard :: start ( message_and_format, self . generic_activity ( event_label) , true )
229255 }
230256
231257 /// Start profiling a generic activity. Profiling continues until the
@@ -705,15 +731,21 @@ impl<'a> TimingGuard<'a> {
705731
706732#[ must_use]
707733pub struct VerboseTimingGuard < ' a > {
708- start_and_message : Option < ( Instant , Option < usize > , String ) > ,
734+ start_and_message : Option < ( Instant , Option < usize > , String , TimePassesFormat , bool ) > ,
709735 _guard : TimingGuard < ' a > ,
710736}
711737
712738impl < ' a > VerboseTimingGuard < ' a > {
713- pub fn start ( message : Option < String > , _guard : TimingGuard < ' a > ) -> Self {
739+ pub fn start (
740+ message_and_format : Option < ( String , TimePassesFormat ) > ,
741+ _guard : TimingGuard < ' a > ,
742+ unique : bool ,
743+ ) -> Self {
714744 VerboseTimingGuard {
715745 _guard,
716- start_and_message : message. map ( |msg| ( Instant :: now ( ) , get_resident_set_size ( ) , msg) ) ,
746+ start_and_message : message_and_format. map ( |( msg, format) | {
747+ ( Instant :: now ( ) , get_resident_set_size ( ) , msg, format, unique)
748+ } ) ,
717749 }
718750 }
719751
@@ -726,10 +758,10 @@ impl<'a> VerboseTimingGuard<'a> {
726758
727759impl Drop for VerboseTimingGuard < ' _ > {
728760 fn drop ( & mut self ) {
729- if let Some ( ( start_time, start_rss, ref message) ) = self . start_and_message {
761+ if let Some ( ( start_time, start_rss, ref message, format , unique ) ) = self . start_and_message {
730762 let end_rss = get_resident_set_size ( ) ;
731763 let dur = start_time. elapsed ( ) ;
732- print_time_passes_entry ( message, dur, start_rss, end_rss) ;
764+ print_time_passes_entry ( message, dur, start_rss, end_rss, format , unique ) ;
733765 }
734766 }
735767}
@@ -739,7 +771,21 @@ pub fn print_time_passes_entry(
739771 dur : Duration ,
740772 start_rss : Option < usize > ,
741773 end_rss : Option < usize > ,
774+ format : TimePassesFormat ,
775+ unique : bool ,
742776) {
777+ if format == TimePassesFormat :: Json {
778+ let json = json ! ( {
779+ "pass" : what,
780+ "time" : dur. as_secs_f64( ) ,
781+ "rss_start" : start_rss,
782+ "rss_end" : end_rss,
783+ "unique" : unique,
784+ } ) ;
785+ eprintln ! ( "time: {}" , json. to_string( ) ) ;
786+ return ;
787+ }
788+
743789 // Print the pass if its duration is greater than 5 ms, or it changed the
744790 // measured RSS.
745791 let is_notable = || {
0 commit comments