@@ -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 smallvec:: SmallVec ;
100101
101102bitflags:: bitflags! {
102103 struct EventFilter : u32 {
@@ -288,6 +289,66 @@ impl SelfProfilerRef {
288289 } )
289290 }
290291
292+ /// Start profiling a generic activity, allowing costly arguments to be recorded. Profiling
293+ /// continues until the `TimingGuard` returned from this call is dropped.
294+ ///
295+ /// If the arguments to a generic activity are cheap to create, use `generic_activity_with_arg`
296+ /// or `generic_activity_with_args` for their simpler API. However, if they are costly or
297+ /// require allocation in sufficiently hot contexts, then this allows for a closure to be called
298+ /// only when arguments were asked to be recorded via `-Z self-profile-events=args`.
299+ ///
300+ /// In this case, the closure will be passed a `&mut EventArgRecorder`, to help with recording
301+ /// one or many arguments within the generic activity being profiled, by calling its
302+ /// `record_arg` method for example.
303+ ///
304+ /// This `EventArgRecorder` may implement more specific traits from other rustc crates, e.g. for
305+ /// richer handling of rustc-specific argument types, while keeping this single entry-point API
306+ /// for recording arguments.
307+ ///
308+ /// Note: recording at least one argument is *required* for the self-profiler to create the
309+ /// `TimingGuard`. A panic will be triggered if that doesn't happen. This function exists
310+ /// explicitly to record arguments, so it fails loudly when there are none to record.
311+ ///
312+ #[ inline( always) ]
313+ pub fn generic_activity_with_arg_recorder < F > (
314+ & self ,
315+ event_label : & ' static str ,
316+ mut f : F ,
317+ ) -> TimingGuard < ' _ >
318+ where
319+ F : FnMut ( & mut EventArgRecorder < ' _ > ) ,
320+ {
321+ // Ensure this event will only be recorded when self-profiling is turned on.
322+ self . exec ( EventFilter :: GENERIC_ACTIVITIES , |profiler| {
323+ let builder = EventIdBuilder :: new ( & profiler. profiler ) ;
324+ let event_label = profiler. get_or_alloc_cached_string ( event_label) ;
325+
326+ // Ensure the closure to create event arguments will only be called when argument
327+ // recording is turned on.
328+ let event_id = if profiler. event_filter_mask . contains ( EventFilter :: FUNCTION_ARGS ) {
329+ // Set up the builder and call the user-provided closure to record potentially
330+ // costly event arguments.
331+ let mut recorder = EventArgRecorder { profiler, args : SmallVec :: new ( ) } ;
332+ f ( & mut recorder) ;
333+
334+ // It is expected that the closure will record at least one argument. If that
335+ // doesn't happen, it's a bug: we've been explicitly called in order to record
336+ // arguments, so we fail loudly when there are none to record.
337+ if recorder. args . is_empty ( ) {
338+ panic ! (
339+ "The closure passed to `generic_activity_with_arg_recorder` needs to \
340+ record at least one argument"
341+ ) ;
342+ }
343+
344+ builder. from_label_and_args ( event_label, & recorder. args )
345+ } else {
346+ builder. from_label ( event_label)
347+ } ;
348+ TimingGuard :: start ( profiler, profiler. generic_activity_event_kind , event_id)
349+ } )
350+ }
351+
291352 /// Record the size of an artifact that the compiler produces
292353 ///
293354 /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
@@ -443,6 +504,33 @@ impl SelfProfilerRef {
443504 }
444505}
445506
507+ /// A helper for recording costly arguments to self-profiling events. Used with
508+ /// `SelfProfilerRef::generic_activity_with_arg_recorder`.
509+ pub struct EventArgRecorder < ' p > {
510+ /// The `SelfProfiler` used to intern the event arguments that users will ask to record.
511+ profiler : & ' p SelfProfiler ,
512+
513+ /// The interned event arguments to be recorded in the generic activity event.
514+ ///
515+ /// The most common case, when actually recording event arguments, is to have one argument. Then
516+ /// followed by recording two, in a couple places.
517+ args : SmallVec < [ StringId ; 2 ] > ,
518+ }
519+
520+ impl EventArgRecorder < ' _ > {
521+ /// Records a single argument within the current generic activity being profiled.
522+ ///
523+ /// Note: when self-profiling with costly event arguments, at least one argument
524+ /// needs to be recorded. A panic will be triggered if that doesn't happen.
525+ pub fn record_arg < A > ( & mut self , event_arg : A )
526+ where
527+ A : Borrow < str > + Into < String > ,
528+ {
529+ let event_arg = self . profiler . get_or_alloc_cached_string ( event_arg) ;
530+ self . args . push ( event_arg) ;
531+ }
532+ }
533+
446534pub struct SelfProfiler {
447535 profiler : Profiler ,
448536 event_filter_mask : EventFilter ,
0 commit comments