Skip to content

Commit e704596

Browse files
committed
fixup! Add infrastructure for emitting timing sections
1 parent 3826bf8 commit e704596

File tree

9 files changed

+97
-50
lines changed

9 files changed

+97
-50
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +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;
37+
use crate::timings::TimingRecord;
3838
use crate::translation::{Translate, to_fluent_args};
3939
use crate::{
4040
CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level,
@@ -165,7 +165,7 @@ impl Margin {
165165
}
166166
}
167167

168-
pub enum TimingSectionKind {
168+
pub enum TimingEvent {
169169
Start,
170170
End,
171171
}
@@ -185,7 +185,7 @@ pub trait Emitter: Translate {
185185

186186
/// Emit a timestamp with start/end of a timing section.
187187
/// Currently only supported for the JSON format.
188-
fn emit_timing_section(&mut self, _section: TimingSection, _kind: TimingSectionKind) {}
188+
fn emit_timing_section(&mut self, _record: TimingRecord, _event: TimingEvent) {}
189189

190190
/// Emit a report about future breakage.
191191
/// Currently only supported for the JSON format.

compiler/rustc_errors/src/json.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ 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;
1716
use std::vec;
1817

1918
use derive_setters::Setters;
@@ -29,10 +28,10 @@ use termcolor::{ColorSpec, WriteColor};
2928
use crate::diagnostic::IsLint;
3029
use crate::emitter::{
3130
ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme,
32-
TimingSectionKind, should_show_source_code,
31+
TimingEvent, should_show_source_code,
3332
};
3433
use crate::registry::Registry;
35-
use crate::timings::TimingSection;
34+
use crate::timings::{TimingRecord, TimingSection};
3635
use crate::translation::{Translate, to_fluent_args};
3736
use crate::{
3837
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions,
@@ -62,8 +61,6 @@ pub struct JsonEmitter {
6261
macro_backtrace: bool,
6362
track_diagnostics: bool,
6463
terminal_url: TerminalUrl,
65-
#[setters(skip)]
66-
start_timestamp: Instant,
6764
}
6865

6966
impl JsonEmitter {
@@ -89,7 +86,6 @@ impl JsonEmitter {
8986
macro_backtrace: false,
9087
track_diagnostics: false,
9188
terminal_url: TerminalUrl::No,
92-
start_timestamp: Instant::now(),
9389
}
9490
}
9591

@@ -109,7 +105,7 @@ impl JsonEmitter {
109105
enum EmitTyped<'a> {
110106
Diagnostic(Diagnostic),
111107
Artifact(ArtifactNotification<'a>),
112-
SectionTimestamp(SectionTimestamp<'a>),
108+
SectionTiming(SectionTimestamp<'a>),
113109
FutureIncompat(FutureIncompatReport<'a>),
114110
UnusedExtern(UnusedExterns<'a>),
115111
}
@@ -141,21 +137,16 @@ impl Emitter for JsonEmitter {
141137
}
142138
}
143139

144-
fn emit_timing_section(&mut self, section: TimingSection, kind: TimingSectionKind) {
145-
let kind = match kind {
146-
TimingSectionKind::Start => "start",
147-
TimingSectionKind::End => "end",
140+
fn emit_timing_section(&mut self, record: TimingRecord, event: TimingEvent) {
141+
let event = match event {
142+
TimingEvent::Start => "start",
143+
TimingEvent::End => "end",
148144
};
149-
let name = match section {
145+
let name = match record.section {
150146
TimingSection::Linking => "link",
151147
};
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));
148+
let data = SectionTimestamp { name, event, timestamp: record.timestamp };
149+
let result = self.emit(EmitTyped::SectionTiming(data));
159150
if let Err(e) = result {
160151
panic!("failed to print timing section: {e:?}");
161152
}
@@ -294,8 +285,8 @@ struct SectionTimestamp<'a> {
294285
/// Name of the section
295286
name: &'a str,
296287
/// Start/end of the section
297-
kind: &'a str,
298-
/// Microseconds elapsed since some predetermined point in time (~start of the rustc process).
288+
event: &'a str,
289+
/// Opaque timestamp.
299290
timestamp: u128,
300291
}
301292

compiler/rustc_errors/src/lib.rs

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

77-
use crate::emitter::TimingSectionKind;
77+
use crate::emitter::TimingEvent;
7878
use crate::registry::Registry;
79-
use crate::timings::TimingSection;
79+
use crate::timings::TimingRecord;
8080

8181
pub mod annotate_snippet_emitter_writer;
8282
pub mod codes;
@@ -1159,12 +1159,12 @@ impl<'a> DiagCtxtHandle<'a> {
11591159
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
11601160
}
11611161

1162-
pub fn emit_timing_section_start(&self, section: TimingSection) {
1163-
self.inner.borrow_mut().emitter.emit_timing_section(section, TimingSectionKind::Start);
1162+
pub fn emit_timing_section_start(&self, record: TimingRecord) {
1163+
self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start);
11641164
}
11651165

1166-
pub fn emit_timing_section_end(&self, section: TimingSection) {
1167-
self.inner.borrow_mut().emitter.emit_timing_section(section, TimingSectionKind::End);
1166+
pub fn emit_timing_section_end(&self, record: TimingRecord) {
1167+
self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End);
11681168
}
11691169

11701170
pub fn emit_future_breakage_report(&self) {

compiler/rustc_errors/src/timings.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::time::Instant;
2+
13
use crate::DiagCtxtHandle;
24

35
/// A high-level section of the compilation process.
@@ -7,14 +9,39 @@ pub enum TimingSection {
79
Linking,
810
}
911

12+
/// Section with attached timestamp
13+
#[derive(Copy, Clone, Debug)]
14+
pub struct TimingRecord {
15+
pub section: TimingSection,
16+
/// Microseconds elapsed since some predetermined point in time (~start of the rustc process).
17+
pub timestamp: u128,
18+
}
19+
20+
impl TimingRecord {
21+
fn from_origin(origin: Instant, section: TimingSection) -> Self {
22+
Self { section, timestamp: Instant::now().duration_since(origin).as_micros() }
23+
}
24+
25+
pub fn section(&self) -> TimingSection {
26+
self.section
27+
}
28+
29+
pub fn timestamp(&self) -> u128 {
30+
self.timestamp
31+
}
32+
}
33+
1034
/// Manages emission of start/end section timings, enabled through `--json=timings`.
1135
pub struct TimingSectionHandler {
12-
enabled: bool,
36+
/// Time when the compilation session started.
37+
/// If `None`, timing is disabled.
38+
origin: Option<Instant>,
1339
}
1440

1541
impl TimingSectionHandler {
1642
pub fn new(enabled: bool) -> Self {
17-
Self { enabled }
43+
let origin = if enabled { Some(Instant::now()) } else { None };
44+
Self { origin }
1845
}
1946

2047
/// Returns a RAII guard that will immediately emit a start the provided section, and then emit
@@ -24,29 +51,30 @@ impl TimingSectionHandler {
2451
diag_ctxt: DiagCtxtHandle<'a>,
2552
section: TimingSection,
2653
) -> TimingSectionGuard<'a> {
27-
TimingSectionGuard::create(diag_ctxt, section, self.enabled)
54+
TimingSectionGuard::create(diag_ctxt, section, self.origin)
2855
}
2956
}
3057

58+
/// RAII wrapper for starting and ending section timings.
3159
pub struct TimingSectionGuard<'a> {
3260
dcx: DiagCtxtHandle<'a>,
3361
section: TimingSection,
34-
enabled: bool,
62+
origin: Option<Instant>,
3563
}
3664

3765
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);
66+
fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, origin: Option<Instant>) -> Self {
67+
if let Some(origin) = origin {
68+
dcx.emit_timing_section_start(TimingRecord::from_origin(origin, section));
4169
}
42-
Self { dcx, section, enabled }
70+
Self { dcx, section, origin }
4371
}
4472
}
4573

4674
impl<'a> Drop for TimingSectionGuard<'a> {
4775
fn drop(&mut self) {
48-
if self.enabled {
49-
self.dcx.emit_timing_section_end(self.section);
76+
if let Some(origin) = self.origin {
77+
self.dcx.emit_timing_section_end(TimingRecord::from_origin(origin, self.section));
5078
}
5179
}
5280
}

compiler/rustc_session/src/config.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ impl Default for Options {
13661366
real_rust_source_base_dir: None,
13671367
edition: DEFAULT_EDITION,
13681368
json_artifact_notifications: false,
1369-
json_section_timings: false,
1369+
json_timings: false,
13701370
json_unused_externs: JsonUnusedExterns::No,
13711371
json_future_incompat: false,
13721372
pretty: None,
@@ -1883,7 +1883,7 @@ pub struct JsonConfig {
18831883
json_artifact_notifications: bool,
18841884
/// Output start and end timestamps of several high-level compilation sections
18851885
/// (frontend, backend, linker).
1886-
json_section_timings: bool,
1886+
json_timings: bool,
18871887
pub json_unused_externs: JsonUnusedExterns,
18881888
json_future_incompat: bool,
18891889
}
@@ -1925,7 +1925,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
19251925
let mut json_artifact_notifications = false;
19261926
let mut json_unused_externs = JsonUnusedExterns::No;
19271927
let mut json_future_incompat = false;
1928-
let mut json_section_timings = false;
1928+
let mut json_timings = false;
19291929
for option in matches.opt_strs("json") {
19301930
// For now conservatively forbid `--color` with `--json` since `--json`
19311931
// won't actually be emitting any colors and anything colorized is
@@ -1942,7 +1942,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
19421942
}
19431943
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
19441944
"artifacts" => json_artifact_notifications = true,
1945-
"timings" => json_section_timings = true,
1945+
"timings" => json_timings = true,
19461946
"unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
19471947
"unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
19481948
"future-incompat" => json_future_incompat = true,
@@ -1955,7 +1955,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
19551955
json_rendered,
19561956
json_color,
19571957
json_artifact_notifications,
1958-
json_section_timings,
1958+
json_timings,
19591959
json_unused_externs,
19601960
json_future_incompat,
19611961
}
@@ -2483,7 +2483,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
24832483
json_rendered,
24842484
json_color,
24852485
json_artifact_notifications,
2486-
json_section_timings,
2486+
json_timings,
24872487
json_unused_externs,
24882488
json_future_incompat,
24892489
} = parse_json(early_dcx, matches);
@@ -2505,7 +2505,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
25052505
let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers);
25062506
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
25072507

2508-
if !unstable_opts.unstable_options && json_section_timings {
2508+
if !unstable_opts.unstable_options && json_timings {
25092509
early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`");
25102510
}
25112511

@@ -2786,7 +2786,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
27862786
real_rust_source_base_dir,
27872787
edition,
27882788
json_artifact_notifications,
2789-
json_section_timings,
2789+
json_timings,
27902790
json_unused_externs,
27912791
json_future_incompat,
27922792
pretty,

compiler/rustc_session/src/options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ top_level_options!(
412412

413413
/// `true` if we're emitting JSON timings with the start and end of
414414
/// high-level compilation sections
415-
json_section_timings: bool [UNTRACKED],
415+
json_timings: bool [UNTRACKED],
416416

417417
/// `true` if we're emitting a JSON blob containing the unused externs
418418
json_unused_externs: JsonUnusedExterns [UNTRACKED],

compiler/rustc_session/src/session.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,7 @@ pub fn build_session(
11301130
.as_ref()
11311131
.map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string());
11321132

1133-
let timings = TimingSectionHandler::new(sopts.json_section_timings);
1133+
let timings = TimingSectionHandler::new(sopts.json_timings);
11341134

11351135
let sess = Session {
11361136
target,

src/doc/rustc/src/command-line-arguments.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ to customize the output:
471471
- `future-incompat` - includes a JSON message that contains a report if the
472472
crate contains any code that may fail to compile in the future.
473473

474+
- `timings` - output a JSON message when a certain compilation "section"
475+
(such as frontend analysis, code generation, linking) begins or ends.
476+
474477
Note that it is invalid to combine the `--json` argument with the
475478
[`--color`](#option-color) argument, and it is required to combine `--json`
476479
with `--error-format=json`.

src/doc/rustc/src/json.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,31 @@ appropriately. (This is needed by Cargo which shares the same dependencies
298298
across multiple build targets, so it should only report an unused dependency if
299299
its not used by any of the targets.)
300300

301+
## Timings
302+
303+
**This setting is currently unstable and requires usage of `-Zunstable-options`.**
304+
305+
The `--timings` option will tell `rustc` to emit messages when a certain compilation
306+
section (such as code generation or linking) begins or ends. The messages will have
307+
the following format:
308+
309+
```json
310+
{
311+
"$message_type": "section_timing", /* Type of this message */
312+
"event": "start", /* Marks the "start" or "end" of the compilation section */
313+
"name": "link", /* The name of the compilation section */
314+
"time": 12345 /* Opaque timestamp when the message was emitted, in microseconds */
315+
}
316+
```
317+
318+
Compilation sections can be nested; for example, if you encounter the start of "foo",
319+
then the start of "bar", then the end of "bar" and then the end of "bar", it means that the
320+
"bar" section happened as a part of the "foo" section.
321+
322+
The timestamp should only be used for computing the duration of each section.
323+
324+
We currently do not guarantee any specific section names to be emitted.
325+
301326
[option-emit]: command-line-arguments.md#option-emit
302327
[option-error-format]: command-line-arguments.md#option-error-format
303328
[option-json]: command-line-arguments.md#option-json

0 commit comments

Comments
 (0)