Skip to main content

rustc_data_structures/
profiling.rs

1//! # Rust Compiler Self-Profiling
2//!
3//! This module implements the basic framework for the compiler's self-
4//! profiling support. It provides the `SelfProfiler` type which enables
5//! recording "events". An event is something that starts and ends at a given
6//! point in time and has an ID and a kind attached to it. This allows for
7//! tracing the compiler's activity.
8//!
9//! Internally this module uses the custom tailored [measureme][mm] crate for
10//! efficiently recording events to disk in a compact format that can be
11//! post-processed and analyzed by the suite of tools in the `measureme`
12//! project. The highest priority for the tracing framework is on incurring as
13//! little overhead as possible.
14//!
15//!
16//! ## Event Overview
17//!
18//! Events have a few properties:
19//!
20//! - The `event_kind` designates the broad category of an event (e.g. does it
21//!   correspond to the execution of a query provider or to loading something
22//!   from the incr. comp. on-disk cache, etc).
23//! - The `event_id` designates the query invocation or function call it
24//!   corresponds to, possibly including the query key or function arguments.
25//! - Each event stores the ID of the thread it was recorded on.
26//! - The timestamp stores beginning and end of the event, or the single point
27//!   in time it occurred at for "instant" events.
28//!
29//!
30//! ## Event Filtering
31//!
32//! Event generation can be filtered by event kind. Recording all possible
33//! events generates a lot of data, much of which is not needed for most kinds
34//! of analysis. So, in order to keep overhead as low as possible for a given
35//! use case, the `SelfProfiler` will only record the kinds of events that
36//! pass the filter specified as a command line argument to the compiler.
37//!
38//!
39//! ## `event_id` Assignment
40//!
41//! As far as `measureme` is concerned, `event_id`s are just strings. However,
42//! it would incur too much overhead to generate and persist each `event_id`
43//! string at the point where the event is recorded. In order to make this more
44//! efficient `measureme` has two features:
45//!
46//! - Strings can share their content, so that re-occurring parts don't have to
47//!   be copied over and over again. One allocates a string in `measureme` and
48//!   gets back a `StringId`. This `StringId` is then used to refer to that
49//!   string. `measureme` strings are actually DAGs of string components so that
50//!   arbitrary sharing of substrings can be done efficiently. This is useful
51//!   because `event_id`s contain lots of redundant text like query names or
52//!   def-path components.
53//!
54//! - `StringId`s can be "virtual" which means that the client picks a numeric
55//!   ID according to some application-specific scheme and can later make that
56//!   ID be mapped to an actual string. This is used to cheaply generate
57//!   `event_id`s while the events actually occur, causing little timing
58//!   distortion, and then later map those `StringId`s, in bulk, to actual
59//!   `event_id` strings. This way the largest part of the tracing overhead is
60//!   localized to one contiguous chunk of time.
61//!
62//! How are these `event_id`s generated in the compiler? For things that occur
63//! infrequently (e.g. "generic activities"), we just allocate the string the
64//! first time it is used and then keep the `StringId` in a hash table. This
65//! is implemented in `SelfProfiler::get_or_alloc_cached_string()`.
66//!
67//! For queries it gets more interesting: First we need a unique numeric ID for
68//! each query invocation (the `QueryInvocationId`). This ID is used as the
69//! virtual `StringId` we use as `event_id` for a given event. This ID has to
70//! be available both when the query is executed and later, together with the
71//! query key, when we allocate the actual `event_id` strings in bulk.
72//!
73//! We could make the compiler generate and keep track of such an ID for each
74//! query invocation but luckily we already have something that fits all the
75//! the requirements: the query's `DepNodeIndex`. So we use the numeric value
76//! of the `DepNodeIndex` as `event_id` when recording the event and then,
77//! just before the query context is dropped, we walk the entire query cache
78//! (which stores the `DepNodeIndex` along with the query key for each
79//! invocation) and allocate the corresponding strings together with a mapping
80//! for `DepNodeIndex as StringId`.
81//!
82//! [mm]: https://github.com/rust-lang/measureme/
83
84use std::borrow::Borrow;
85use std::collections::hash_map::Entry;
86use std::error::Error;
87use std::fmt::Display;
88use std::path::Path;
89use std::sync::Arc;
90use std::sync::atomic::Ordering;
91use std::time::{Duration, Instant};
92use std::{fs, hint, process};
93
94pub use measureme::EventId;
95use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
96use parking_lot::RwLock;
97use smallvec::SmallVec;
98use tracing::warn;
99
100use crate::fx::FxHashMap;
101use crate::outline;
102use crate::sync::AtomicU64;
103
104struct EventFilter(<EventFilter as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for EventFilter { }
#[automatically_derived]
impl ::core::clone::Clone for EventFilter {
    #[inline]
    fn clone(&self) -> Self {
        let _:
                ::core::clone::AssertParamIsClone<<EventFilter as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for EventFilter { }
impl EventFilter {
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GENERIC_ACTIVITIES: Self = Self::from_bits_retain(1 << 0);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_PROVIDERS: Self = Self::from_bits_retain(1 << 1);
    #[doc =
    r" Store detailed instant events, including timestamp and thread ID,"]
    #[doc = r" per each query cache hit. Note that this is quite expensive."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_CACHE_HITS: Self = Self::from_bits_retain(1 << 2);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_BLOCKED: Self = Self::from_bits_retain(1 << 3);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const INCR_CACHE_LOADS: Self = Self::from_bits_retain(1 << 4);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_KEYS: Self = Self::from_bits_retain(1 << 5);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FUNCTION_ARGS: Self = Self::from_bits_retain(1 << 6);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const LLVM: Self = Self::from_bits_retain(1 << 7);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const INCR_RESULT_HASHING: Self = Self::from_bits_retain(1 << 8);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ARTIFACT_SIZES: Self = Self::from_bits_retain(1 << 9);
    #[doc = r" Store aggregated counts of cache hits per query invocation."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_CACHE_HIT_COUNTS: Self = Self::from_bits_retain(1 << 10);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const DEFAULT: Self =
        Self::from_bits_retain(Self::GENERIC_ACTIVITIES.bits() |
                                    Self::QUERY_PROVIDERS.bits() | Self::QUERY_BLOCKED.bits() |
                            Self::INCR_CACHE_LOADS.bits() |
                        Self::INCR_RESULT_HASHING.bits() |
                    Self::ARTIFACT_SIZES.bits() |
                Self::QUERY_CACHE_HIT_COUNTS.bits());
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ARGS: Self =
        Self::from_bits_retain(Self::QUERY_KEYS.bits() |
                Self::FUNCTION_ARGS.bits());
    #[allow(deprecated, non_upper_case_globals,)]
    pub const QUERY_CACHE_HIT_COMBINED: Self =
        Self::from_bits_retain(Self::QUERY_CACHE_HITS.bits() |
                Self::QUERY_CACHE_HIT_COUNTS.bits());
}
impl ::bitflags::Flags for EventFilter {
    const FLAGS: &'static [::bitflags::Flag<EventFilter>] =
        &[{

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("GENERIC_ACTIVITIES",
                            EventFilter::GENERIC_ACTIVITIES)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_PROVIDERS",
                            EventFilter::QUERY_PROVIDERS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_CACHE_HITS",
                            EventFilter::QUERY_CACHE_HITS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_BLOCKED",
                            EventFilter::QUERY_BLOCKED)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("INCR_CACHE_LOADS",
                            EventFilter::INCR_CACHE_LOADS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_KEYS", EventFilter::QUERY_KEYS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("FUNCTION_ARGS",
                            EventFilter::FUNCTION_ARGS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("LLVM", EventFilter::LLVM)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("INCR_RESULT_HASHING",
                            EventFilter::INCR_RESULT_HASHING)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("ARTIFACT_SIZES",
                            EventFilter::ARTIFACT_SIZES)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_CACHE_HIT_COUNTS",
                            EventFilter::QUERY_CACHE_HIT_COUNTS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("DEFAULT", EventFilter::DEFAULT)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("ARGS", EventFilter::ARGS)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("QUERY_CACHE_HIT_COMBINED",
                            EventFilter::QUERY_CACHE_HIT_COMBINED)
                    }];
    type Bits = u16;
    fn bits(&self) -> u16 { EventFilter::bits(self) }
    fn from_bits_retain(bits: u16) -> EventFilter {
        EventFilter::from_bits_retain(bits)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        struct InternalBitFlags(u16);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> Self {
                let _: ::core::clone::AssertParamIsClone<u16>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u16>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &Self)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for EventFilter {
            type Primitive = u16;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u16 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&EventFilter(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<EventFilter>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u16> for
            InternalBitFlags {
            fn as_ref(&self) -> &u16 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u16> for
            InternalBitFlags {
            fn from(bits: u16) -> Self { Self::from_bits_retain(bits) }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u16 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                let mut truncated = <u16 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <EventFilter as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                let _ = i;
                Self(truncated)
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u16 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u16)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u16) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u16) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                {
                    if name == "GENERIC_ACTIVITIES" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::GENERIC_ACTIVITIES.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_PROVIDERS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_PROVIDERS.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_CACHE_HITS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_CACHE_HITS.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_BLOCKED" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_BLOCKED.bits()));
                    }
                };
                ;
                {
                    if name == "INCR_CACHE_LOADS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::INCR_CACHE_LOADS.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_KEYS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_KEYS.bits()));
                    }
                };
                ;
                {
                    if name == "FUNCTION_ARGS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::FUNCTION_ARGS.bits()));
                    }
                };
                ;
                {
                    if name == "LLVM" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::LLVM.bits()));
                    }
                };
                ;
                {
                    if name == "INCR_RESULT_HASHING" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::INCR_RESULT_HASHING.bits()));
                    }
                };
                ;
                {
                    if name == "ARTIFACT_SIZES" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::ARTIFACT_SIZES.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_CACHE_HIT_COUNTS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_CACHE_HIT_COUNTS.bits()));
                    }
                };
                ;
                {
                    if name == "DEFAULT" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::DEFAULT.bits()));
                    }
                };
                ;
                {
                    if name == "ARGS" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::ARGS.bits()));
                    }
                };
                ;
                {
                    if name == "QUERY_CACHE_HIT_COMBINED" {
                        return ::bitflags::__private::core::option::Option::Some(Self(EventFilter::QUERY_CACHE_HIT_COMBINED.bits()));
                    }
                };
                ;
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u16 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u16 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<EventFilter> {
                ::bitflags::iter::Iter::__private_const_new(<EventFilter as
                        ::bitflags::Flags>::FLAGS,
                    EventFilter::from_bits_retain(self.bits()),
                    EventFilter::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<EventFilter> {
                ::bitflags::iter::IterNames::__private_const_new(<EventFilter
                        as ::bitflags::Flags>::FLAGS,
                    EventFilter::from_bits_retain(self.bits()),
                    EventFilter::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = EventFilter;
            type IntoIter = ::bitflags::iter::Iter<EventFilter>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u16 { &mut self.0 }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl EventFilter {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u16 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u16)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u16) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u16) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for EventFilter {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for EventFilter {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for EventFilter {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for EventFilter {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for EventFilter {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: EventFilter) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for EventFilter {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for EventFilter {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for EventFilter {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for EventFilter {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for EventFilter {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for EventFilter {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for EventFilter {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for EventFilter {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<EventFilter> for
            EventFilter {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<EventFilter> for
            EventFilter {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl EventFilter {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<EventFilter> {
                ::bitflags::iter::Iter::__private_const_new(<EventFilter as
                        ::bitflags::Flags>::FLAGS,
                    EventFilter::from_bits_retain(self.bits()),
                    EventFilter::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<EventFilter> {
                ::bitflags::iter::IterNames::__private_const_new(<EventFilter
                        as ::bitflags::Flags>::FLAGS,
                    EventFilter::from_bits_retain(self.bits()),
                    EventFilter::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for EventFilter {
            type Item = EventFilter;
            type IntoIter = ::bitflags::iter::Iter<EventFilter>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags::bitflags! {
105    #[derive(Clone, Copy)]
106    struct EventFilter: u16 {
107        const GENERIC_ACTIVITIES  = 1 << 0;
108        const QUERY_PROVIDERS     = 1 << 1;
109        /// Store detailed instant events, including timestamp and thread ID,
110        /// per each query cache hit. Note that this is quite expensive.
111        const QUERY_CACHE_HITS    = 1 << 2;
112        const QUERY_BLOCKED       = 1 << 3;
113        const INCR_CACHE_LOADS    = 1 << 4;
114
115        const QUERY_KEYS          = 1 << 5;
116        const FUNCTION_ARGS       = 1 << 6;
117        const LLVM                = 1 << 7;
118        const INCR_RESULT_HASHING = 1 << 8;
119        const ARTIFACT_SIZES      = 1 << 9;
120        /// Store aggregated counts of cache hits per query invocation.
121        const QUERY_CACHE_HIT_COUNTS  = 1 << 10;
122
123        // keep this in sync with the `-Z self-profile-events` help message in rustc_session/src/options.rs
124        const DEFAULT = Self::GENERIC_ACTIVITIES.bits() |
125                        Self::QUERY_PROVIDERS.bits() |
126                        Self::QUERY_BLOCKED.bits() |
127                        Self::INCR_CACHE_LOADS.bits() |
128                        Self::INCR_RESULT_HASHING.bits() |
129                        Self::ARTIFACT_SIZES.bits() |
130                        Self::QUERY_CACHE_HIT_COUNTS.bits();
131
132        // keep this in sync with the `-Z self-profile-events` help message in rustc_session/src/options.rs
133        const ARGS = Self::QUERY_KEYS.bits() | Self::FUNCTION_ARGS.bits();
134        const QUERY_CACHE_HIT_COMBINED = Self::QUERY_CACHE_HITS.bits() | Self::QUERY_CACHE_HIT_COUNTS.bits();
135    }
136}
137
138// keep this in sync with the `-Z self-profile-events` help message in rustc_session/src/options.rs
139const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
140    ("none", EventFilter::empty()),
141    ("all", EventFilter::all()),
142    ("default", EventFilter::DEFAULT),
143    ("generic-activity", EventFilter::GENERIC_ACTIVITIES),
144    ("query-provider", EventFilter::QUERY_PROVIDERS),
145    ("query-cache-hit", EventFilter::QUERY_CACHE_HITS),
146    ("query-cache-hit-count", EventFilter::QUERY_CACHE_HIT_COUNTS),
147    ("query-blocked", EventFilter::QUERY_BLOCKED),
148    ("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
149    ("query-keys", EventFilter::QUERY_KEYS),
150    ("function-args", EventFilter::FUNCTION_ARGS),
151    ("args", EventFilter::ARGS),
152    ("llvm", EventFilter::LLVM),
153    ("incr-result-hashing", EventFilter::INCR_RESULT_HASHING),
154    ("artifact-sizes", EventFilter::ARTIFACT_SIZES),
155];
156
157/// Something that uniquely identifies a query invocation.
158pub struct QueryInvocationId(pub u32);
159
160/// Which format to use for `-Z time-passes`
161#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for TimePassesFormat { }
#[automatically_derived]
impl ::core::clone::Clone for TimePassesFormat {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for TimePassesFormat { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for TimePassesFormat { }
#[automatically_derived]
impl ::core::cmp::PartialEq for TimePassesFormat {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::hash::Hash for TimePassesFormat {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
            state)
    }
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for TimePassesFormat {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                TimePassesFormat::Text => "Text",
                TimePassesFormat::Json => "Json",
            })
    }
}Debug)]
162pub enum TimePassesFormat {
163    /// Emit human readable text
164    Text,
165    /// Emit structured JSON
166    Json,
167}
168
169/// A reference to the SelfProfiler. It can be cloned and sent across thread
170/// boundaries at will.
171#[derive(#[automatically_derived]
impl ::core::clone::Clone for SelfProfilerRef {
    #[inline]
    fn clone(&self) -> Self {
        Self {
            profiler: ::core::clone::Clone::clone(&self.profiler),
            event_filter_mask: ::core::clone::Clone::clone(&self.event_filter_mask),
            print_verbose_generic_activities: ::core::clone::Clone::clone(&self.print_verbose_generic_activities),
        }
    }
}Clone)]
172pub struct SelfProfilerRef {
173    // This field is `None` if self-profiling is disabled for the current
174    // compilation session.
175    profiler: Option<Arc<SelfProfiler>>,
176
177    // We store the filter mask directly in the reference because that doesn't
178    // cost anything and allows for filtering with checking if the profiler is
179    // actually enabled.
180    event_filter_mask: EventFilter,
181
182    // Print verbose generic activities to stderr.
183    print_verbose_generic_activities: Option<TimePassesFormat>,
184}
185
186impl SelfProfilerRef {
187    pub fn new(
188        profiler: Option<Arc<SelfProfiler>>,
189        print_verbose_generic_activities: Option<TimePassesFormat>,
190    ) -> SelfProfilerRef {
191        // If there is no SelfProfiler then the filter mask is set to NONE,
192        // ensuring that nothing ever tries to actually access it.
193        let event_filter_mask =
194            profiler.as_ref().map_or(EventFilter::empty(), |p| p.event_filter_mask);
195
196        SelfProfilerRef { profiler, event_filter_mask, print_verbose_generic_activities }
197    }
198
199    /// This shim makes sure that calls only get executed if the filter mask
200    /// lets them pass. It also contains some trickery to make sure that
201    /// code is optimized for non-profiling compilation sessions, i.e. anything
202    /// past the filter check is never inlined so it doesn't clutter the fast
203    /// path.
204    #[inline(always)]
205    fn exec<F>(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_>
206    where
207        F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
208    {
209        #[inline(never)]
210        #[cold]
211        fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
212        where
213            F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
214        {
215            let profiler = profiler_ref.profiler.as_ref().unwrap();
216            f(profiler)
217        }
218
219        if self.event_filter_mask.contains(event_filter) {
220            cold_call(self, f)
221        } else {
222            TimingGuard::none()
223        }
224    }
225
226    /// Start profiling a verbose generic activity. Profiling continues until the
227    /// VerboseTimingGuard returned from this call is dropped. In addition to recording
228    /// a measureme event, "verbose" generic activities also print a timing entry to
229    /// stderr if the compiler is invoked with -Ztime-passes.
230    pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
231        let message_and_format =
232            self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format));
233
234        VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label))
235    }
236
237    /// Like `verbose_generic_activity`, but with an extra arg.
238    pub fn verbose_generic_activity_with_arg<A>(
239        &self,
240        event_label: &'static str,
241        event_arg: A,
242    ) -> VerboseTimingGuard<'_>
243    where
244        A: Borrow<str> + Into<String>,
245    {
246        let message_and_format = self
247            .print_verbose_generic_activities
248            .map(|format| (::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}({1})", event_label,
                event_arg.borrow()))
    })format!("{}({})", event_label, event_arg.borrow()), format));
249
250        VerboseTimingGuard::start(
251            message_and_format,
252            self.generic_activity_with_arg(event_label, event_arg),
253        )
254    }
255
256    /// Start profiling a generic activity. Profiling continues until the
257    /// TimingGuard returned from this call is dropped.
258    #[inline(always)]
259    pub fn generic_activity(&self, event_label: &'static str) -> TimingGuard<'_> {
260        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
261            let event_label = profiler.get_or_alloc_cached_string(event_label);
262            let event_id = EventId::from_label(event_label);
263            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
264        })
265    }
266
267    /// Start profiling with some event filter for a given event. Profiling continues until the
268    /// TimingGuard returned from this call is dropped.
269    #[inline(always)]
270    pub fn generic_activity_with_event_id(&self, event_id: EventId) -> TimingGuard<'_> {
271        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
272            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
273        })
274    }
275
276    /// Start profiling a generic activity. Profiling continues until the
277    /// TimingGuard returned from this call is dropped.
278    #[inline(always)]
279    pub fn generic_activity_with_arg<A>(
280        &self,
281        event_label: &'static str,
282        event_arg: A,
283    ) -> TimingGuard<'_>
284    where
285        A: Borrow<str> + Into<String>,
286    {
287        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
288            let builder = EventIdBuilder::new(&profiler.profiler);
289            let event_label = profiler.get_or_alloc_cached_string(event_label);
290            let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) {
291                let event_arg = profiler.get_or_alloc_cached_string(event_arg);
292                builder.from_label_and_arg(event_label, event_arg)
293            } else {
294                builder.from_label(event_label)
295            };
296            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
297        })
298    }
299
300    /// Start profiling a generic activity, allowing costly arguments to be recorded. Profiling
301    /// continues until the `TimingGuard` returned from this call is dropped.
302    ///
303    /// If the arguments to a generic activity are cheap to create, use `generic_activity_with_arg`
304    /// or `generic_activity_with_args` for their simpler API. However, if they are costly or
305    /// require allocation in sufficiently hot contexts, then this allows for a closure to be called
306    /// only when arguments were asked to be recorded via `-Z self-profile-events=args`.
307    ///
308    /// In this case, the closure will be passed a `&mut EventArgRecorder`, to help with recording
309    /// one or many arguments within the generic activity being profiled, by calling its
310    /// `record_arg` method for example.
311    ///
312    /// This `EventArgRecorder` may implement more specific traits from other rustc crates, e.g. for
313    /// richer handling of rustc-specific argument types, while keeping this single entry-point API
314    /// for recording arguments.
315    ///
316    /// Note: recording at least one argument is *required* for the self-profiler to create the
317    /// `TimingGuard`. A panic will be triggered if that doesn't happen. This function exists
318    /// explicitly to record arguments, so it fails loudly when there are none to record.
319    ///
320    #[inline(always)]
321    pub fn generic_activity_with_arg_recorder<F>(
322        &self,
323        event_label: &'static str,
324        mut f: F,
325    ) -> TimingGuard<'_>
326    where
327        F: FnMut(&mut EventArgRecorder<'_>),
328    {
329        // Ensure this event will only be recorded when self-profiling is turned on.
330        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
331            let builder = EventIdBuilder::new(&profiler.profiler);
332            let event_label = profiler.get_or_alloc_cached_string(event_label);
333
334            // Ensure the closure to create event arguments will only be called when argument
335            // recording is turned on.
336            let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) {
337                // Set up the builder and call the user-provided closure to record potentially
338                // costly event arguments.
339                let mut recorder = EventArgRecorder { profiler, args: SmallVec::new() };
340                f(&mut recorder);
341
342                // It is expected that the closure will record at least one argument. If that
343                // doesn't happen, it's a bug: we've been explicitly called in order to record
344                // arguments, so we fail loudly when there are none to record.
345                if recorder.args.is_empty() {
346                    {
    ::core::panicking::panic_fmt(format_args!("The closure passed to `generic_activity_with_arg_recorder` needs to record at least one argument"));
};panic!(
347                        "The closure passed to `generic_activity_with_arg_recorder` needs to \
348                         record at least one argument"
349                    );
350                }
351
352                builder.from_label_and_args(event_label, &recorder.args)
353            } else {
354                builder.from_label(event_label)
355            };
356            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
357        })
358    }
359
360    /// Record the size of an artifact that the compiler produces
361    ///
362    /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
363    /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename)
364    #[inline(always)]
365    pub fn artifact_size<A>(&self, artifact_kind: &str, artifact_name: A, size: u64)
366    where
367        A: Borrow<str> + Into<String>,
368    {
369        drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| {
370            let builder = EventIdBuilder::new(&profiler.profiler);
371            let event_label = profiler.get_or_alloc_cached_string(artifact_kind);
372            let event_arg = profiler.get_or_alloc_cached_string(artifact_name);
373            let event_id = builder.from_label_and_arg(event_label, event_arg);
374            let thread_id = get_thread_id();
375
376            profiler.profiler.record_integer_event(
377                profiler.artifact_size_event_kind,
378                event_id,
379                thread_id,
380                size,
381            );
382
383            TimingGuard::none()
384        }))
385    }
386
387    #[inline(always)]
388    pub fn generic_activity_with_args(
389        &self,
390        event_label: &'static str,
391        event_args: &[String],
392    ) -> TimingGuard<'_> {
393        self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
394            let builder = EventIdBuilder::new(&profiler.profiler);
395            let event_label = profiler.get_or_alloc_cached_string(event_label);
396            let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) {
397                let event_args: Vec<_> = event_args
398                    .iter()
399                    .map(|s| profiler.get_or_alloc_cached_string(&s[..]))
400                    .collect();
401                builder.from_label_and_args(event_label, &event_args)
402            } else {
403                builder.from_label(event_label)
404            };
405            TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
406        })
407    }
408
409    /// Start profiling a query provider. Profiling continues until the
410    /// TimingGuard returned from this call is dropped.
411    #[inline(always)]
412    pub fn query_provider(&self) -> TimingGuard<'_> {
413        self.exec(EventFilter::QUERY_PROVIDERS, |profiler| {
414            TimingGuard::start(profiler, profiler.query_event_kind, EventId::INVALID)
415        })
416    }
417
418    /// Record a query in-memory cache hit.
419    #[inline(always)]
420    pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
421        #[inline(never)]
422        #[cold]
423        fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
424            if profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) {
425                profiler_ref
426                    .profiler
427                    .as_ref()
428                    .unwrap()
429                    .increment_query_cache_hit_counters(QueryInvocationId(query_invocation_id.0));
430            }
431            if profiler_ref.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) {
432                hint::cold_path();
433                profiler_ref.instant_query_event(
434                    |profiler| profiler.query_cache_hit_event_kind,
435                    query_invocation_id,
436                );
437            }
438        }
439
440        // We check both kinds of query cache hit events at once, to reduce overhead in the
441        // common case (with self-profile disabled).
442        if self.event_filter_mask.intersects(EventFilter::QUERY_CACHE_HIT_COMBINED) {
443            hint::cold_path();
444            cold_call(self, query_invocation_id);
445        }
446    }
447
448    /// Start profiling a query being blocked on a concurrent execution.
449    /// Profiling continues until the TimingGuard returned from this call is
450    /// dropped.
451    #[inline(always)]
452    pub fn query_blocked(&self) -> TimingGuard<'_> {
453        self.exec(EventFilter::QUERY_BLOCKED, |profiler| {
454            TimingGuard::start(profiler, profiler.query_blocked_event_kind, EventId::INVALID)
455        })
456    }
457
458    /// Start profiling how long it takes to load a query result from the
459    /// incremental compilation on-disk cache. Profiling continues until the
460    /// TimingGuard returned from this call is dropped.
461    #[inline(always)]
462    pub fn incr_cache_loading(&self) -> TimingGuard<'_> {
463        self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| {
464            TimingGuard::start(
465                profiler,
466                profiler.incremental_load_result_event_kind,
467                EventId::INVALID,
468            )
469        })
470    }
471
472    /// Start profiling how long it takes to hash query results for incremental compilation.
473    /// Profiling continues until the TimingGuard returned from this call is dropped.
474    #[inline(always)]
475    pub fn incr_result_hashing(&self) -> TimingGuard<'_> {
476        self.exec(EventFilter::INCR_RESULT_HASHING, |profiler| {
477            TimingGuard::start(
478                profiler,
479                profiler.incremental_result_hashing_event_kind,
480                EventId::INVALID,
481            )
482        })
483    }
484
485    #[inline(always)]
486    fn instant_query_event(
487        &self,
488        event_kind: fn(&SelfProfiler) -> StringId,
489        query_invocation_id: QueryInvocationId,
490    ) {
491        let event_id = StringId::new_virtual(query_invocation_id.0);
492        let thread_id = get_thread_id();
493        let profiler = self.profiler.as_ref().unwrap();
494        profiler.profiler.record_instant_event(
495            event_kind(profiler),
496            EventId::from_virtual(event_id),
497            thread_id,
498        );
499    }
500
501    pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
502        if let Some(profiler) = &self.profiler {
503            f(profiler)
504        }
505    }
506
507    /// Gets a `StringId` for the given string. This method makes sure that
508    /// any strings going through it will only be allocated once in the
509    /// profiling data.
510    /// Returns `None` if the self-profiling is not enabled.
511    pub fn get_or_alloc_cached_string(&self, s: &str) -> Option<StringId> {
512        self.profiler.as_ref().map(|p| p.get_or_alloc_cached_string(s))
513    }
514
515    /// Store query cache hits to the self-profile log.
516    /// Should be called once at the end of the compilation session.
517    ///
518    /// The cache hits are stored per **query invocation**, not **per query kind/type**.
519    /// `analyzeme` can later deduplicate individual query labels from the QueryInvocationId event
520    /// IDs.
521    pub fn store_query_cache_hits(&self) {
522        if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HIT_COUNTS) {
523            let profiler = self.profiler.as_ref().unwrap();
524            let query_hits = profiler.query_hits.read();
525            let builder = EventIdBuilder::new(&profiler.profiler);
526            let thread_id = get_thread_id();
527            for (query_invocation, hit_count) in query_hits.iter().enumerate() {
528                let hit_count = hit_count.load(Ordering::Relaxed);
529                // No need to record empty cache hit counts
530                if hit_count > 0 {
531                    let event_id =
532                        builder.from_label(StringId::new_virtual(query_invocation as u64));
533                    profiler.profiler.record_integer_event(
534                        profiler.query_cache_hit_count_event_kind,
535                        event_id,
536                        thread_id,
537                        hit_count,
538                    );
539                }
540            }
541        }
542    }
543
544    #[inline]
545    pub fn enabled(&self) -> bool {
546        self.profiler.is_some()
547    }
548
549    #[inline]
550    pub fn llvm_recording_enabled(&self) -> bool {
551        self.event_filter_mask.contains(EventFilter::LLVM)
552    }
553    #[inline]
554    pub fn get_self_profiler(&self) -> Option<Arc<SelfProfiler>> {
555        self.profiler.clone()
556    }
557
558    /// Is expensive recording of query keys and/or function arguments enabled?
559    pub fn is_args_recording_enabled(&self) -> bool {
560        self.enabled() && self.event_filter_mask.intersects(EventFilter::ARGS)
561    }
562}
563
564/// A helper for recording costly arguments to self-profiling events. Used with
565/// `SelfProfilerRef::generic_activity_with_arg_recorder`.
566pub struct EventArgRecorder<'p> {
567    /// The `SelfProfiler` used to intern the event arguments that users will ask to record.
568    profiler: &'p SelfProfiler,
569
570    /// The interned event arguments to be recorded in the generic activity event.
571    ///
572    /// The most common case, when actually recording event arguments, is to have one argument. Then
573    /// followed by recording two, in a couple places.
574    args: SmallVec<[StringId; 2]>,
575}
576
577impl EventArgRecorder<'_> {
578    /// Records a single argument within the current generic activity being profiled.
579    ///
580    /// Note: when self-profiling with costly event arguments, at least one argument
581    /// needs to be recorded. A panic will be triggered if that doesn't happen.
582    pub fn record_arg<A>(&mut self, event_arg: A)
583    where
584        A: Borrow<str> + Into<String>,
585    {
586        let event_arg = self.profiler.get_or_alloc_cached_string(event_arg);
587        self.args.push(event_arg);
588    }
589}
590
591pub struct SelfProfiler {
592    profiler: Profiler,
593    event_filter_mask: EventFilter,
594
595    string_cache: RwLock<FxHashMap<String, StringId>>,
596
597    /// Recording individual query cache hits as "instant" measureme events
598    /// is incredibly expensive. Instead of doing that, we simply aggregate
599    /// cache hit *counts* per query invocation, and then store the final count
600    /// of cache hits per invocation at the end of the compilation session.
601    ///
602    /// With this approach, we don't know the individual thread IDs and timestamps
603    /// of cache hits, but it has very little overhead on top of `-Zself-profile`.
604    /// Recording the cache hits as individual events made compilation 3-5x slower.
605    ///
606    /// Query invocation IDs should be monotonic integers, so we can store them in a vec,
607    /// rather than using a hashmap.
608    query_hits: RwLock<Vec<AtomicU64>>,
609
610    query_event_kind: StringId,
611    generic_activity_event_kind: StringId,
612    incremental_load_result_event_kind: StringId,
613    incremental_result_hashing_event_kind: StringId,
614    query_blocked_event_kind: StringId,
615    query_cache_hit_event_kind: StringId,
616    artifact_size_event_kind: StringId,
617    /// Total cache hits per query invocation
618    query_cache_hit_count_event_kind: StringId,
619}
620
621impl SelfProfiler {
622    pub fn new(
623        output_directory: &Path,
624        crate_name: Option<&str>,
625        event_filters: Option<&[String]>,
626        counter_name: &str,
627    ) -> Result<SelfProfiler, Box<dyn Error + Send + Sync>> {
628        fs::create_dir_all(output_directory)?;
629
630        let crate_name = crate_name.unwrap_or("unknown-crate");
631        // HACK(eddyb) we need to pad the PID, strange as it may seem, as its
632        // length can behave as a source of entropy for heap addresses, when
633        // ASLR is disabled and the heap is otherwise deterministic.
634        let pid: u32 = process::id();
635        let filename = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}-{1:07}.rustc_profile",
                crate_name, pid))
    })format!("{crate_name}-{pid:07}.rustc_profile");
636        let path = output_directory.join(filename);
637        let profiler =
638            Profiler::with_counter(&path, measureme::counters::Counter::by_name(counter_name)?)?;
639
640        let query_event_kind = profiler.alloc_string("Query");
641        let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
642        let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult");
643        let incremental_result_hashing_event_kind =
644            profiler.alloc_string("IncrementalResultHashing");
645        let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
646        let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
647        let artifact_size_event_kind = profiler.alloc_string("ArtifactSize");
648        let query_cache_hit_count_event_kind = profiler.alloc_string("QueryCacheHitCount");
649
650        let mut event_filter_mask = EventFilter::empty();
651
652        if let Some(event_filters) = event_filters {
653            let mut unknown_events = ::alloc::vec::Vec::new()vec![];
654            for item in event_filters {
655                if let Some(&(_, mask)) =
656                    EVENT_FILTERS_BY_NAME.iter().find(|&(name, _)| name == item)
657                {
658                    event_filter_mask |= mask;
659                } else {
660                    unknown_events.push(item.clone());
661                }
662            }
663
664            // Warn about any unknown event names
665            if !unknown_events.is_empty() {
666                unknown_events.sort();
667                unknown_events.dedup();
668
669                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_data_structures/src/profiling.rs:669",
                        "rustc_data_structures::profiling", ::tracing::Level::WARN,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_data_structures/src/profiling.rs"),
                        ::tracing_core::__macro_support::Option::Some(669u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_data_structures::profiling"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::WARN <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Unknown self-profiler events specified: {0}. Available options are: {1}.",
                                                    unknown_events.join(", "),
                                                    EVENT_FILTERS_BY_NAME.iter().map(|&(name, _)|
                                                                    name.to_string()).collect::<Vec<_>>().join(", ")) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};warn!(
670                    "Unknown self-profiler events specified: {}. Available options are: {}.",
671                    unknown_events.join(", "),
672                    EVENT_FILTERS_BY_NAME
673                        .iter()
674                        .map(|&(name, _)| name.to_string())
675                        .collect::<Vec<_>>()
676                        .join(", ")
677                );
678            }
679        } else {
680            event_filter_mask = EventFilter::DEFAULT;
681        }
682
683        Ok(SelfProfiler {
684            profiler,
685            event_filter_mask,
686            string_cache: RwLock::new(FxHashMap::default()),
687            query_event_kind,
688            generic_activity_event_kind,
689            incremental_load_result_event_kind,
690            incremental_result_hashing_event_kind,
691            query_blocked_event_kind,
692            query_cache_hit_event_kind,
693            artifact_size_event_kind,
694            query_cache_hit_count_event_kind,
695            query_hits: Default::default(),
696        })
697    }
698
699    /// Allocates a new string in the profiling data. Does not do any caching
700    /// or deduplication.
701    pub fn alloc_string<STR: SerializableString + ?Sized>(&self, s: &STR) -> StringId {
702        self.profiler.alloc_string(s)
703    }
704
705    /// Store a cache hit of a query invocation
706    pub fn increment_query_cache_hit_counters(&self, id: QueryInvocationId) {
707        // Fast path: assume that the query was already encountered before, and just record
708        // a cache hit.
709        let mut guard = self.query_hits.upgradable_read();
710        let query_hits = &guard;
711        let index = id.0 as usize;
712        if index < query_hits.len() {
713            // We only want to increment the count, no other synchronization is required
714            query_hits[index].fetch_add(1, Ordering::Relaxed);
715        } else {
716            // If not, we need to extend the query hit map to the highest observed ID
717            guard.with_upgraded(|vec| {
718                vec.resize_with(index + 1, || AtomicU64::new(0));
719                vec[index] = AtomicU64::from(1);
720            });
721        }
722    }
723
724    /// Gets a `StringId` for the given string. This method makes sure that
725    /// any strings going through it will only be allocated once in the
726    /// profiling data.
727    pub fn get_or_alloc_cached_string<A>(&self, s: A) -> StringId
728    where
729        A: Borrow<str> + Into<String>,
730    {
731        // Only acquire a read-lock first since we assume that the string is
732        // already present in the common case.
733        {
734            let string_cache = self.string_cache.read();
735
736            if let Some(&id) = string_cache.get(s.borrow()) {
737                return id;
738            }
739        }
740
741        let mut string_cache = self.string_cache.write();
742        // Check if the string has already been added in the small time window
743        // between dropping the read lock and acquiring the write lock.
744        match string_cache.entry(s.into()) {
745            Entry::Occupied(e) => *e.get(),
746            Entry::Vacant(e) => {
747                let string_id = self.profiler.alloc_string(&e.key()[..]);
748                *e.insert(string_id)
749            }
750        }
751    }
752
753    pub fn map_query_invocation_id_to_string(&self, from: QueryInvocationId, to: StringId) {
754        let from = StringId::new_virtual(from.0);
755        self.profiler.map_virtual_to_concrete_string(from, to);
756    }
757
758    pub fn bulk_map_query_invocation_id_to_single_string<I>(&self, from: I, to: StringId)
759    where
760        I: Iterator<Item = QueryInvocationId> + ExactSizeIterator,
761    {
762        let from = from.map(|qid| StringId::new_virtual(qid.0));
763        self.profiler.bulk_map_virtual_to_single_concrete_string(from, to);
764    }
765
766    pub fn query_key_recording_enabled(&self) -> bool {
767        self.event_filter_mask.contains(EventFilter::QUERY_KEYS)
768    }
769
770    pub fn event_id_builder(&self) -> EventIdBuilder<'_> {
771        EventIdBuilder::new(&self.profiler)
772    }
773}
774
775#[must_use]
776pub struct TimingGuard<'a>(Option<measureme::TimingGuard<'a>>);
777
778impl<'a> TimingGuard<'a> {
779    #[inline]
780    pub fn start(
781        profiler: &'a SelfProfiler,
782        event_kind: StringId,
783        event_id: EventId,
784    ) -> TimingGuard<'a> {
785        let thread_id = get_thread_id();
786        let raw_profiler = &profiler.profiler;
787        let timing_guard =
788            raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id);
789        TimingGuard(Some(timing_guard))
790    }
791
792    #[inline]
793    pub fn finish_with_query_invocation_id(self, query_invocation_id: QueryInvocationId) {
794        if let Some(guard) = self.0 {
795            outline(|| {
796                let event_id = StringId::new_virtual(query_invocation_id.0);
797                let event_id = EventId::from_virtual(event_id);
798                guard.finish_with_override_event_id(event_id);
799            });
800        }
801    }
802
803    #[inline]
804    pub fn none() -> TimingGuard<'a> {
805        TimingGuard(None)
806    }
807
808    #[inline(always)]
809    pub fn run<R>(self, f: impl FnOnce() -> R) -> R {
810        let _timer = self;
811        f()
812    }
813}
814
815struct VerboseInfo {
816    start_time: Instant,
817    start_rss: Option<usize>,
818    message: String,
819    format: TimePassesFormat,
820}
821
822#[must_use]
823pub struct VerboseTimingGuard<'a> {
824    info: Option<VerboseInfo>,
825    _guard: TimingGuard<'a>,
826}
827
828impl<'a> VerboseTimingGuard<'a> {
829    pub fn start(
830        message_and_format: Option<(String, TimePassesFormat)>,
831        _guard: TimingGuard<'a>,
832    ) -> Self {
833        VerboseTimingGuard {
834            _guard,
835            info: message_and_format.map(|(message, format)| VerboseInfo {
836                start_time: Instant::now(),
837                start_rss: get_resident_set_size(),
838                message,
839                format,
840            }),
841        }
842    }
843
844    #[inline(always)]
845    pub fn run<R>(self, f: impl FnOnce() -> R) -> R {
846        let _timer = self;
847        f()
848    }
849}
850
851impl Drop for VerboseTimingGuard<'_> {
852    fn drop(&mut self) {
853        if let Some(info) = &self.info {
854            let end_rss = get_resident_set_size();
855            let dur = info.start_time.elapsed();
856            print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format);
857        }
858    }
859}
860
861struct JsonTimePassesEntry<'a> {
862    pass: &'a str,
863    time: f64,
864    start_rss: Option<usize>,
865    end_rss: Option<usize>,
866}
867
868impl Display for JsonTimePassesEntry<'_> {
869    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
870        let Self { pass: what, time, start_rss, end_rss } = self;
871        f.write_fmt(format_args!("{{\"pass\":\"{0}\",\"time\":{1},\"rss_start\":",
        what, time))write!(f, r#"{{"pass":"{what}","time":{time},"rss_start":"#).unwrap();
872        match start_rss {
873            Some(rss) => f.write_fmt(format_args!("{0}", rss))write!(f, "{rss}")?,
874            None => f.write_fmt(format_args!("null"))write!(f, "null")?,
875        }
876        f.write_fmt(format_args!(",\"rss_end\":"))write!(f, r#","rss_end":"#)?;
877        match end_rss {
878            Some(rss) => f.write_fmt(format_args!("{0}", rss))write!(f, "{rss}")?,
879            None => f.write_fmt(format_args!("null"))write!(f, "null")?,
880        }
881        f.write_fmt(format_args!("}}"))write!(f, "}}")?;
882        Ok(())
883    }
884}
885
886pub fn print_time_passes_entry(
887    what: &str,
888    dur: Duration,
889    start_rss: Option<usize>,
890    end_rss: Option<usize>,
891    format: TimePassesFormat,
892) {
893    match format {
894        TimePassesFormat::Json => {
895            let entry =
896                JsonTimePassesEntry { pass: what, time: dur.as_secs_f64(), start_rss, end_rss };
897
898            { ::std::io::_eprint(format_args!("time: {0}\n", entry)); };eprintln!(r#"time: {entry}"#);
899            return;
900        }
901        TimePassesFormat::Text => (),
902    }
903
904    // Print the pass if its duration is greater than 5 ms, or it changed the
905    // measured RSS.
906    let is_notable = || {
907        if dur.as_millis() > 5 {
908            return true;
909        }
910
911        if let (Some(start_rss), Some(end_rss)) = (start_rss, end_rss) {
912            let change_rss = end_rss.abs_diff(start_rss);
913            if change_rss > 0 {
914                return true;
915            }
916        }
917
918        false
919    };
920    if !is_notable() {
921        return;
922    }
923
924    let rss_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as usize;
925    let rss_change_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as i128;
926
927    let mem_string = match (start_rss, end_rss) {
928        (Some(start_rss), Some(end_rss)) => {
929            let change_rss = end_rss as i128 - start_rss as i128;
930
931            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("; rss: {0:>4}MB -> {1:>4}MB ({2:>+5}MB)",
                rss_to_mb(start_rss), rss_to_mb(end_rss),
                rss_change_to_mb(change_rss)))
    })format!(
932                "; rss: {:>4}MB -> {:>4}MB ({:>+5}MB)",
933                rss_to_mb(start_rss),
934                rss_to_mb(end_rss),
935                rss_change_to_mb(change_rss),
936            )
937        }
938        (Some(start_rss), None) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("; rss start: {0:>4}MB",
                rss_to_mb(start_rss)))
    })format!("; rss start: {:>4}MB", rss_to_mb(start_rss)),
939        (None, Some(end_rss)) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("; rss end: {0:>4}MB",
                rss_to_mb(end_rss)))
    })format!("; rss end: {:>4}MB", rss_to_mb(end_rss)),
940        (None, None) => String::new(),
941    };
942
943    {
    ::std::io::_eprint(format_args!("time: {0:>7}{1}\t{2}\n",
            duration_to_secs_str(dur), mem_string, what));
};eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
944}
945
946// Hack up our own formatting for the duration to make it easier for scripts
947// to parse (always use the same number of decimal places and the same unit).
948pub fn duration_to_secs_str(dur: std::time::Duration) -> String {
949    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:.3}", dur.as_secs_f64()))
    })format!("{:.3}", dur.as_secs_f64())
950}
951
952fn get_thread_id() -> u32 {
953    std::thread::current().id().as_u64().get() as u32
954}
955
956// Memory reporting
957cfg_select! {
958    windows => {
959        pub fn get_resident_set_size() -> Option<usize> {
960            use windows::Win32::System::ProcessStatus::{
961                K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS,
962            };
963            use windows::Win32::System::Threading::GetCurrentProcess;
964
965            let mut pmc = PROCESS_MEMORY_COUNTERS::default();
966            let pmc_size = size_of_val(&pmc);
967            unsafe { K32GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc_size as u32) }
968                .ok()
969                .ok()?;
970
971            Some(pmc.WorkingSetSize)
972        }
973    }
974    target_os = "macos" => {
975        pub fn get_resident_set_size() -> Option<usize> {
976            use std::mem;
977
978            use libc::{PROC_PIDTASKINFO, c_int, c_void, getpid, proc_pidinfo, proc_taskinfo};
979            const PROC_TASKINFO_SIZE: c_int = size_of::<proc_taskinfo>() as c_int;
980
981            unsafe {
982                let mut info: proc_taskinfo = mem::zeroed();
983                let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void;
984                let pid = getpid() as c_int;
985                let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE);
986                if ret == PROC_TASKINFO_SIZE { Some(info.pti_resident_size as usize) } else { None }
987            }
988        }
989    }
990    unix => {
991        pub fn get_resident_set_size() -> Option<usize> {
992            use libc::{_SC_PAGESIZE, sysconf};
993            let field = 1;
994            let contents = fs::read("/proc/self/statm").ok()?;
995            let contents = String::from_utf8(contents).ok()?;
996            let s = contents.split_whitespace().nth(field)?;
997            let npages = s.parse::<usize>().ok()?;
998            // SAFETY: `sysconf(_SC_PAGESIZE)` has no side effects and is safe to call.
999            Some(npages * unsafe { sysconf(_SC_PAGESIZE) } as usize)
1000        }
1001    }
1002    _ => {
1003        pub fn get_resident_set_size() -> Option<usize> {
1004            None
1005        }
1006    }
1007}
1008
1009#[cfg(test)]
1010mod tests;