1use std::time::Instant;
2
3use rustc_data_structures::fx::FxHashSet;
4use rustc_data_structures::sync::Lock;
5
6use crate::DiagCtxtHandle;
7
8#[derive(#[automatically_derived]
impl ::core::marker::Copy for TimingSection { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TimingSection {
#[inline]
fn clone(&self) -> TimingSection { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for TimingSection {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
TimingSection::Codegen => "Codegen",
TimingSection::Linking => "Linking",
})
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for TimingSection {
#[inline]
fn eq(&self, other: &TimingSection) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TimingSection {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for TimingSection {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
let __self_discr = ::core::intrinsics::discriminant_value(self);
::core::hash::Hash::hash(&__self_discr, state)
}
}Hash)]
10pub enum TimingSection {
11 Codegen,
13 Linking,
15}
16
17#[derive(#[automatically_derived]
impl ::core::marker::Copy for TimingRecord { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TimingRecord {
#[inline]
fn clone(&self) -> TimingRecord {
let _: ::core::clone::AssertParamIsClone<TimingSection>;
let _: ::core::clone::AssertParamIsClone<u128>;
*self
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for TimingRecord {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "TimingRecord",
"section", &self.section, "timestamp", &&self.timestamp)
}
}Debug)]
19pub struct TimingRecord {
20 pub section: TimingSection,
21 pub timestamp: u128,
23}
24
25impl TimingRecord {
26 fn from_origin(origin: Instant, section: TimingSection) -> Self {
27 Self { section, timestamp: Instant::now().duration_since(origin).as_micros() }
28 }
29
30 pub fn section(&self) -> TimingSection {
31 self.section
32 }
33
34 pub fn timestamp(&self) -> u128 {
35 self.timestamp
36 }
37}
38
39pub struct TimingSectionHandler {
41 origin: Option<Instant>,
44 opened_sections: Lock<FxHashSet<TimingSection>>,
46}
47
48impl TimingSectionHandler {
49 pub fn new(enabled: bool) -> Self {
50 let origin = if enabled { Some(Instant::now()) } else { None };
51 Self { origin, opened_sections: Lock::new(FxHashSet::default()) }
52 }
53
54 pub fn section_guard<'a>(
57 &self,
58 diag_ctxt: DiagCtxtHandle<'a>,
59 section: TimingSection,
60 ) -> TimingSectionGuard<'a> {
61 if self.is_enabled() && self.opened_sections.borrow().contains(§ion) {
62 diag_ctxt
63 .bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Section `{0:?}` was started again before it was finished",
section))
})format!("Section `{section:?}` was started again before it was finished"));
64 }
65
66 TimingSectionGuard::create(diag_ctxt, section, self.origin)
67 }
68
69 pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) {
71 if let Some(origin) = self.origin {
72 let mut opened = self.opened_sections.borrow_mut();
73 if !opened.insert(section) {
74 diag_ctxt
75 .bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Section `{0:?}` was started again before it was finished",
section))
})format!("Section `{section:?}` was started again before it was finished"));
76 }
77
78 diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section));
79 }
80 }
81
82 pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) {
84 if let Some(origin) = self.origin {
85 let mut opened = self.opened_sections.borrow_mut();
86 if !opened.remove(§ion) {
87 diag_ctxt.bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Section `{0:?}` was ended before being started",
section))
})format!("Section `{section:?}` was ended before being started"));
88 }
89
90 diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section));
91 }
92 }
93
94 fn is_enabled(&self) -> bool {
95 self.origin.is_some()
96 }
97}
98
99pub struct TimingSectionGuard<'a> {
101 dcx: DiagCtxtHandle<'a>,
102 section: TimingSection,
103 origin: Option<Instant>,
104}
105
106impl<'a> TimingSectionGuard<'a> {
107 fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, origin: Option<Instant>) -> Self {
108 if let Some(origin) = origin {
109 dcx.emit_timing_section_start(TimingRecord::from_origin(origin, section));
110 }
111 Self { dcx, section, origin }
112 }
113}
114
115impl<'a> Drop for TimingSectionGuard<'a> {
116 fn drop(&mut self) {
117 if let Some(origin) = self.origin {
118 self.dcx.emit_timing_section_end(TimingRecord::from_origin(origin, self.section));
119 }
120 }
121}