diff options
Diffstat (limited to 'compiler/rustc_errors/src/timings.rs')
| -rw-r--r-- | compiler/rustc_errors/src/timings.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/compiler/rustc_errors/src/timings.rs b/compiler/rustc_errors/src/timings.rs new file mode 100644 index 00000000000..0d82f3e8db8 --- /dev/null +++ b/compiler/rustc_errors/src/timings.rs @@ -0,0 +1,121 @@ +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)); + } + } +} |
