Skip to content

Commit 8312381

Browse files
committed
Add infrastructure for emitting timing sections
1 parent 7ad5248 commit 8312381

File tree

5 files changed

+118
-2
lines changed

5 files changed

+118
-2
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::snippet::{
3434
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
3535
};
3636
use crate::styled_buffer::StyledBuffer;
37+
use crate::timings::TimingSection;
3738
use crate::translation::{Translate, to_fluent_args};
3839
use crate::{
3940
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
@@ -164,11 +165,16 @@ impl Margin {
164165
}
165166
}
166167

168+
pub enum TimingSectionKind {
169+
Start,
170+
End,
171+
}
172+
167173
const ANONYMIZED_LINE_NUM: &str = "LL";
168174

169175
pub type DynEmitter = dyn Emitter + DynSend;
170176

171-
/// Emitter trait for emitting errors.
177+
/// Emitter trait for emitting errors and other structured information.
172178
pub trait Emitter: Translate {
173179
/// Emit a structured diagnostic.
174180
fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry);
@@ -177,6 +183,10 @@ pub trait Emitter: Translate {
177183
/// Currently only supported for the JSON format.
178184
fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {}
179185

186+
/// Emit a timestamp with start/end of a timing section.
187+
/// Currently only supported for the JSON format.
188+
fn emit_timing_section(&mut self, _section: TimingSection, _kind: TimingSectionKind) {}
189+
180190
/// Emit a report about future breakage.
181191
/// Currently only supported for the JSON format.
182192
fn emit_future_breakage_report(&mut self, _diags: Vec<DiagInner>, _registry: &Registry) {}

compiler/rustc_errors/src/json.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::error::Report;
1313
use std::io::{self, Write};
1414
use std::path::Path;
1515
use std::sync::{Arc, Mutex};
16+
use std::time::Instant;
1617
use std::vec;
1718

1819
use derive_setters::Setters;
@@ -28,9 +29,10 @@ use termcolor::{ColorSpec, WriteColor};
2829
use crate::diagnostic::IsLint;
2930
use crate::emitter::{
3031
ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme,
31-
should_show_source_code,
32+
TimingSectionKind, should_show_source_code,
3233
};
3334
use crate::registry::Registry;
35+
use crate::timings::TimingSection;
3436
use crate::translation::{Translate, to_fluent_args};
3537
use crate::{
3638
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions,
@@ -60,6 +62,8 @@ pub struct JsonEmitter {
6062
macro_backtrace: bool,
6163
track_diagnostics: bool,
6264
terminal_url: TerminalUrl,
65+
#[setters(skip)]
66+
start_timestamp: Instant,
6367
}
6468

6569
impl JsonEmitter {
@@ -85,6 +89,7 @@ impl JsonEmitter {
8589
macro_backtrace: false,
8690
track_diagnostics: false,
8791
terminal_url: TerminalUrl::No,
92+
start_timestamp: Instant::now(),
8893
}
8994
}
9095

@@ -104,6 +109,7 @@ impl JsonEmitter {
104109
enum EmitTyped<'a> {
105110
Diagnostic(Diagnostic),
106111
Artifact(ArtifactNotification<'a>),
112+
SectionTimestamp(SectionTimestamp<'a>),
107113
FutureIncompat(FutureIncompatReport<'a>),
108114
UnusedExtern(UnusedExterns<'a>),
109115
}
@@ -135,6 +141,26 @@ impl Emitter for JsonEmitter {
135141
}
136142
}
137143

144+
fn emit_timing_section(&mut self, section: TimingSection, kind: TimingSectionKind) {
145+
let kind = match kind {
146+
TimingSectionKind::Start => "start",
147+
TimingSectionKind::End => "end",
148+
};
149+
let name = match section {
150+
TimingSection::Linking => "link",
151+
};
152+
let time = Instant::now();
153+
let data = SectionTimestamp {
154+
name,
155+
kind,
156+
timestamp: time.duration_since(self.start_timestamp).as_micros(),
157+
};
158+
let result = self.emit(EmitTyped::SectionTimestamp(data));
159+
if let Err(e) = result {
160+
panic!("failed to print timing section: {e:?}");
161+
}
162+
}
163+
138164
fn emit_future_breakage_report(&mut self, diags: Vec<crate::DiagInner>, registry: &Registry) {
139165
let data: Vec<FutureBreakageItem<'_>> = diags
140166
.into_iter()
@@ -263,6 +289,16 @@ struct ArtifactNotification<'a> {
263289
emit: &'a str,
264290
}
265291

292+
#[derive(Serialize)]
293+
struct SectionTimestamp<'a> {
294+
/// Name of the section
295+
name: &'a str,
296+
/// Start/end of the section
297+
kind: &'a str,
298+
/// Microseconds elapsed since some predetermined point in time (~start of the rustc process).
299+
timestamp: u128,
300+
}
301+
266302
#[derive(Serialize)]
267303
struct FutureBreakageItem<'a> {
268304
// Always EmitTyped::Diagnostic, but we want to make sure it gets serialized

compiler/rustc_errors/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ pub use snippet::Style;
7474
pub use termcolor::{Color, ColorSpec, WriteColor};
7575
use tracing::debug;
7676

77+
use crate::emitter::TimingSectionKind;
7778
use crate::registry::Registry;
79+
use crate::timings::TimingSection;
7880

7981
pub mod annotate_snippet_emitter_writer;
8082
pub mod codes;
@@ -90,6 +92,7 @@ mod snippet;
9092
mod styled_buffer;
9193
#[cfg(test)]
9294
mod tests;
95+
pub mod timings;
9396
pub mod translation;
9497

9598
pub type PResult<'a, T> = Result<T, Diag<'a>>;
@@ -1156,6 +1159,14 @@ impl<'a> DiagCtxtHandle<'a> {
11561159
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
11571160
}
11581161

1162+
pub fn emit_timing_section_start(&self, section: TimingSection) {
1163+
self.inner.borrow_mut().emitter.emit_timing_section(section, TimingSectionKind::Start);
1164+
}
1165+
1166+
pub fn emit_timing_section_end(&self, section: TimingSection) {
1167+
self.inner.borrow_mut().emitter.emit_timing_section(section, TimingSectionKind::End);
1168+
}
1169+
11591170
pub fn emit_future_breakage_report(&self) {
11601171
let inner = &mut *self.inner.borrow_mut();
11611172
let diags = std::mem::take(&mut inner.future_breakage_diagnostics);

compiler/rustc_errors/src/timings.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::DiagCtxtHandle;
2+
3+
/// A high-level section of the compilation process.
4+
#[derive(Copy, Clone, Debug)]
5+
pub enum TimingSection {
6+
/// Time spent linking.
7+
Linking,
8+
}
9+
10+
/// Manages emission of start/end section timings, enabled through `--json=timings`.
11+
pub struct TimingSectionHandler {
12+
enabled: bool,
13+
}
14+
15+
impl TimingSectionHandler {
16+
pub fn new(enabled: bool) -> Self {
17+
Self { enabled }
18+
}
19+
20+
/// Returns a RAII guard that will immediately emit a start the provided section, and then emit
21+
/// its end when it is dropped.
22+
pub fn start_section<'a>(
23+
&self,
24+
diag_ctxt: DiagCtxtHandle<'a>,
25+
section: TimingSection,
26+
) -> TimingSectionGuard<'a> {
27+
TimingSectionGuard::create(diag_ctxt, section, self.enabled)
28+
}
29+
}
30+
31+
pub struct TimingSectionGuard<'a> {
32+
dcx: DiagCtxtHandle<'a>,
33+
section: TimingSection,
34+
enabled: bool,
35+
}
36+
37+
impl<'a> TimingSectionGuard<'a> {
38+
fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, enabled: bool) -> Self {
39+
if enabled {
40+
dcx.emit_timing_section_start(section);
41+
}
42+
Self { dcx, section, enabled }
43+
}
44+
}
45+
46+
impl<'a> Drop for TimingSectionGuard<'a> {
47+
fn drop(&mut self) {
48+
if self.enabled {
49+
self.dcx.emit_timing_section_end(self.section);
50+
}
51+
}
52+
}

compiler/rustc_session/src/session.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_errors::emitter::{
1818
DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
1919
};
2020
use rustc_errors::json::JsonEmitter;
21+
use rustc_errors::timings::TimingSectionHandler;
2122
use rustc_errors::{
2223
Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort,
2324
FluentBundle, LazyFallbackBundle, TerminalUrl, fallback_fluent_bundle,
@@ -156,6 +157,9 @@ pub struct Session {
156157
/// Used by `-Z self-profile`.
157158
pub prof: SelfProfilerRef,
158159

160+
/// Used to emit section timings events (enabled by `--json=timings`).
161+
pub timings: TimingSectionHandler,
162+
159163
/// Data about code being compiled, gathered during compilation.
160164
pub code_stats: CodeStats,
161165

@@ -1126,6 +1130,8 @@ pub fn build_session(
11261130
.as_ref()
11271131
.map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string());
11281132

1133+
let timings = TimingSectionHandler::new(sopts.json_section_timings);
1134+
11291135
let sess = Session {
11301136
target,
11311137
host,
@@ -1136,6 +1142,7 @@ pub fn build_session(
11361142
io,
11371143
incr_comp_session: RwLock::new(IncrCompSession::NotInitialized),
11381144
prof,
1145+
timings,
11391146
code_stats: Default::default(),
11401147
lint_store: None,
11411148
driver_lint_caps,

0 commit comments

Comments
 (0)