|  | use std::time::Instant; | 
|  |  | 
|  | use rustc_data_structures::fx::FxHashSet; | 
|  | use rustc_data_structures::sync::Lock; | 
|  |  | 
|  | use crate::DiagCtxtHandle; | 
|  |  | 
|  | /// A high-level section of the compilation process. | 
|  | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | 
|  | pub enum TimingSection { | 
|  | /// Time spent doing codegen. | 
|  | Codegen, | 
|  | /// Time spent linking. | 
|  | Linking, | 
|  | } | 
|  |  | 
|  | /// Section with attached timestamp | 
|  | #[derive(Copy, Clone, Debug)] | 
|  | pub struct TimingRecord { | 
|  | pub section: TimingSection, | 
|  | /// Microseconds elapsed since some predetermined point in time (~start of the rustc process). | 
|  | pub timestamp: u128, | 
|  | } | 
|  |  | 
|  | impl TimingRecord { | 
|  | fn from_origin(origin: Instant, section: TimingSection) -> Self { | 
|  | Self { section, timestamp: Instant::now().duration_since(origin).as_micros() } | 
|  | } | 
|  |  | 
|  | pub fn section(&self) -> TimingSection { | 
|  | self.section | 
|  | } | 
|  |  | 
|  | pub fn timestamp(&self) -> u128 { | 
|  | self.timestamp | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Manages emission of start/end section timings, enabled through `--json=timings`. | 
|  | pub struct TimingSectionHandler { | 
|  | /// Time when the compilation session started. | 
|  | /// If `None`, timing is disabled. | 
|  | origin: Option<Instant>, | 
|  | /// Sanity check to ensure that we open and close sections correctly. | 
|  | opened_sections: Lock<FxHashSet<TimingSection>>, | 
|  | } | 
|  |  | 
|  | impl TimingSectionHandler { | 
|  | pub fn new(enabled: bool) -> Self { | 
|  | let origin = if enabled { Some(Instant::now()) } else { None }; | 
|  | Self { origin, opened_sections: Lock::new(FxHashSet::default()) } | 
|  | } | 
|  |  | 
|  | /// Returns a RAII guard that will immediately emit a start the provided section, and then emit | 
|  | /// its end when it is dropped. | 
|  | pub fn section_guard<'a>( | 
|  | &self, | 
|  | diag_ctxt: DiagCtxtHandle<'a>, | 
|  | section: TimingSection, | 
|  | ) -> TimingSectionGuard<'a> { | 
|  | if self.is_enabled() && self.opened_sections.borrow().contains(§ion) { | 
|  | diag_ctxt | 
|  | .bug(format!("Section `{section:?}` was started again before it was finished")); | 
|  | } | 
|  |  | 
|  | TimingSectionGuard::create(diag_ctxt, section, self.origin) | 
|  | } | 
|  |  | 
|  | /// Start the provided section. | 
|  | pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { | 
|  | if let Some(origin) = self.origin { | 
|  | let mut opened = self.opened_sections.borrow_mut(); | 
|  | if !opened.insert(section) { | 
|  | diag_ctxt | 
|  | .bug(format!("Section `{section:?}` was started again before it was finished")); | 
|  | } | 
|  |  | 
|  | diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// End the provided section. | 
|  | pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { | 
|  | if let Some(origin) = self.origin { | 
|  | let mut opened = self.opened_sections.borrow_mut(); | 
|  | if !opened.remove(§ion) { | 
|  | diag_ctxt.bug(format!("Section `{section:?}` was ended before being started")); | 
|  | } | 
|  |  | 
|  | diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section)); | 
|  | } | 
|  | } | 
|  |  | 
|  | fn is_enabled(&self) -> bool { | 
|  | self.origin.is_some() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// RAII wrapper for starting and ending section timings. | 
|  | pub struct TimingSectionGuard<'a> { | 
|  | dcx: DiagCtxtHandle<'a>, | 
|  | section: TimingSection, | 
|  | origin: Option<Instant>, | 
|  | } | 
|  |  | 
|  | impl<'a> TimingSectionGuard<'a> { | 
|  | fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, origin: Option<Instant>) -> Self { | 
|  | if let Some(origin) = origin { | 
|  | dcx.emit_timing_section_start(TimingRecord::from_origin(origin, section)); | 
|  | } | 
|  | Self { dcx, section, origin } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<'a> Drop for TimingSectionGuard<'a> { | 
|  | fn drop(&mut self) { | 
|  | if let Some(origin) = self.origin { | 
|  | self.dcx.emit_timing_section_end(TimingRecord::from_origin(origin, self.section)); | 
|  | } | 
|  | } | 
|  | } |