@@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
97
97
pub use measureme:: EventId ;
98
98
use measureme:: { EventIdBuilder , Profiler , SerializableString , StringId } ;
99
99
use parking_lot:: RwLock ;
100
+ use smallvec:: SmallVec ;
100
101
101
102
bitflags:: bitflags! {
102
103
struct EventFilter : u32 {
@@ -288,6 +289,66 @@ impl SelfProfilerRef {
288
289
} )
289
290
}
290
291
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
+
291
352
/// Record the size of an artifact that the compiler produces
292
353
///
293
354
/// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
@@ -443,6 +504,33 @@ impl SelfProfilerRef {
443
504
}
444
505
}
445
506
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
+
446
534
pub struct SelfProfiler {
447
535
profiler : Profiler ,
448
536
event_filter_mask : EventFilter ,
0 commit comments