@@ -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) )
213224 }
214225
215226 /// Like `verbose_generic_activity`, but with an extra arg.
@@ -221,11 +232,14 @@ 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+ )
229243 }
230244
231245 /// Start profiling a generic activity. Profiling continues until the
@@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
703717 }
704718}
705719
720+ struct VerboseInfo {
721+ start_time : Instant ,
722+ start_rss : Option < usize > ,
723+ message : String ,
724+ format : TimePassesFormat ,
725+ }
726+
706727#[ must_use]
707728pub struct VerboseTimingGuard < ' a > {
708- start_and_message : Option < ( Instant , Option < usize > , String ) > ,
729+ info : Option < VerboseInfo > ,
709730 _guard : TimingGuard < ' a > ,
710731}
711732
712733impl < ' a > VerboseTimingGuard < ' a > {
713- pub fn start ( message : Option < String > , _guard : TimingGuard < ' a > ) -> Self {
734+ pub fn start (
735+ message_and_format : Option < ( String , TimePassesFormat ) > ,
736+ _guard : TimingGuard < ' a > ,
737+ ) -> Self {
714738 VerboseTimingGuard {
715739 _guard,
716- start_and_message : message. map ( |msg| ( Instant :: now ( ) , get_resident_set_size ( ) , msg) ) ,
740+ info : message_and_format. map ( |( message, format) | VerboseInfo {
741+ start_time : Instant :: now ( ) ,
742+ start_rss : get_resident_set_size ( ) ,
743+ message,
744+ format,
745+ } ) ,
717746 }
718747 }
719748
@@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> {
726755
727756impl Drop for VerboseTimingGuard < ' _ > {
728757 fn drop ( & mut self ) {
729- if let Some ( ( start_time , start_rss , ref message ) ) = self . start_and_message {
758+ if let Some ( info ) = & self . info {
730759 let end_rss = get_resident_set_size ( ) ;
731- let dur = start_time. elapsed ( ) ;
732- print_time_passes_entry ( message, dur, start_rss, end_rss) ;
760+ let dur = info . start_time . elapsed ( ) ;
761+ print_time_passes_entry ( & info . message , dur, info . start_rss , end_rss, info . format ) ;
733762 }
734763 }
735764}
@@ -739,7 +768,22 @@ pub fn print_time_passes_entry(
739768 dur : Duration ,
740769 start_rss : Option < usize > ,
741770 end_rss : Option < usize > ,
771+ format : TimePassesFormat ,
742772) {
773+ match format {
774+ TimePassesFormat :: Json => {
775+ let json = json ! ( {
776+ "pass" : what,
777+ "time" : dur. as_secs_f64( ) ,
778+ "rss_start" : start_rss,
779+ "rss_end" : end_rss,
780+ } ) ;
781+ eprintln ! ( "time: {}" , json. to_string( ) ) ;
782+ return ;
783+ }
784+ TimePassesFormat :: Text => ( ) ,
785+ }
786+
743787 // Print the pass if its duration is greater than 5 ms, or it changed the
744788 // measured RSS.
745789 let is_notable = || {
0 commit comments