|
1 | 1 | use std::time::Instant;
|
2 | 2 |
|
| 3 | +use rustc_data_structures::fx::FxHashSet; |
| 4 | +use rustc_data_structures::sync::Lock; |
| 5 | + |
3 | 6 | use crate::DiagCtxtHandle;
|
4 | 7 |
|
5 | 8 | /// A high-level section of the compilation process.
|
6 |
| -#[derive(Copy, Clone, Debug)] |
| 9 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
7 | 10 | pub enum TimingSection {
|
| 11 | + /// Time spent doing codegen. |
| 12 | + Codegen, |
8 | 13 | /// Time spent linking.
|
9 | 14 | Linking,
|
10 | 15 | }
|
@@ -36,23 +41,62 @@ pub struct TimingSectionHandler {
|
36 | 41 | /// Time when the compilation session started.
|
37 | 42 | /// If `None`, timing is disabled.
|
38 | 43 | origin: Option<Instant>,
|
| 44 | + /// Debug map to make sure that we open and close sections correctly. |
| 45 | + /// Rc<RefCell> also ensures that we won't emit sections in parallel. |
| 46 | + opened_sections: Lock<FxHashSet<TimingSection>>, |
39 | 47 | }
|
40 | 48 |
|
41 | 49 | impl TimingSectionHandler {
|
42 | 50 | pub fn new(enabled: bool) -> Self {
|
43 | 51 | let origin = if enabled { Some(Instant::now()) } else { None };
|
44 |
| - Self { origin } |
| 52 | + Self { origin, opened_sections: Lock::new(FxHashSet::default()) } |
45 | 53 | }
|
46 | 54 |
|
47 | 55 | /// Returns a RAII guard that will immediately emit a start the provided section, and then emit
|
48 | 56 | /// its end when it is dropped.
|
49 |
| - pub fn start_section<'a>( |
| 57 | + pub fn section_guard<'a>( |
50 | 58 | &self,
|
51 | 59 | diag_ctxt: DiagCtxtHandle<'a>,
|
52 | 60 | section: TimingSection,
|
53 | 61 | ) -> TimingSectionGuard<'a> {
|
| 62 | + if self.is_enabled() && self.opened_sections.borrow().contains(§ion) { |
| 63 | + diag_ctxt |
| 64 | + .bug(format!("Section `{section:?}` was started again before it was finished")); |
| 65 | + } |
| 66 | + |
54 | 67 | TimingSectionGuard::create(diag_ctxt, section, self.origin)
|
55 | 68 | }
|
| 69 | + |
| 70 | + /// Start the provided section. |
| 71 | + pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { |
| 72 | + if let Some(origin) = self.origin { |
| 73 | + let mut opened = self.opened_sections.borrow_mut(); |
| 74 | + if opened.contains(§ion) { |
| 75 | + diag_ctxt |
| 76 | + .bug(format!("Section `{section:?}` was started again before it was finished")); |
| 77 | + } else { |
| 78 | + opened.insert(section); |
| 79 | + } |
| 80 | + |
| 81 | + diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section)); |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + /// End the provided section. |
| 86 | + pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { |
| 87 | + if let Some(origin) = self.origin { |
| 88 | + let mut opened = self.opened_sections.borrow_mut(); |
| 89 | + if !opened.remove(§ion) { |
| 90 | + diag_ctxt.bug(format!("Section `{section:?}` was ended before being started")); |
| 91 | + } |
| 92 | + |
| 93 | + diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section)); |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + fn is_enabled(&self) -> bool { |
| 98 | + self.origin.is_some() |
| 99 | + } |
56 | 100 | }
|
57 | 101 |
|
58 | 102 | /// RAII wrapper for starting and ending section timings.
|
|
0 commit comments