-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Implement initial support for timing sections (--json=timings
)
#142123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ use std::error::Report; | |
use std::io::{self, Write}; | ||
use std::path::Path; | ||
use std::sync::{Arc, Mutex}; | ||
use std::time::SystemTime; | ||
use std::vec; | ||
|
||
use derive_setters::Setters; | ||
|
@@ -28,9 +29,10 @@ use termcolor::{ColorSpec, WriteColor}; | |
use crate::diagnostic::IsLint; | ||
use crate::emitter::{ | ||
ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme, | ||
should_show_source_code, | ||
TimingSectionKind, should_show_source_code, | ||
}; | ||
use crate::registry::Registry; | ||
use crate::timings::TimingSection; | ||
use crate::translation::{Translate, to_fluent_args}; | ||
use crate::{ | ||
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions, | ||
|
@@ -104,6 +106,7 @@ impl JsonEmitter { | |
enum EmitTyped<'a> { | ||
Diagnostic(Diagnostic), | ||
Artifact(ArtifactNotification<'a>), | ||
SectionTiming(SectionTimestamp<'a>), | ||
FutureIncompat(FutureIncompatReport<'a>), | ||
UnusedExtern(UnusedExterns<'a>), | ||
} | ||
|
@@ -135,6 +138,25 @@ impl Emitter for JsonEmitter { | |
} | ||
} | ||
|
||
fn emit_timing_section(&mut self, section: TimingSection, kind: TimingSectionKind) { | ||
let kind = match kind { | ||
TimingSectionKind::Start => "start", | ||
TimingSectionKind::End => "end", | ||
}; | ||
let name = match section { | ||
TimingSection::Linking => "link", | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto, for |
||
let timestamp = SystemTime::now() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should use Instant rather than SystemTime. Using the latter causes issues when changing the system time during a build, for example because your ntp daemon finally got an internet connection. And IMHO it should preferrably use CLOCK_MONOTONIC rather than CLOCK_BOOTTIME as it doesn't make sense to count time where the system is suspended in performance profiles. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already use system time for some incr dir names, I think, but you're right that for profiling Instant makes more sense. But then I have to count the duration from some origin time again. Before it was from the creation of the JSON emitter, but that had some issues w.r.t. multiple emitters existing. Should I just take a snapshot when rustc starts or something? 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right and |
||
.duration_since(SystemTime::UNIX_EPOCH) | ||
.expect("system time should always be greater than the unix epoch") | ||
.as_micros(); | ||
let data = SectionTimestamp { name, kind, timestamp }; | ||
let result = self.emit(EmitTyped::SectionTiming(data)); | ||
if let Err(e) = result { | ||
panic!("failed to print timing section: {e:?}"); | ||
} | ||
} | ||
|
||
fn emit_future_breakage_report(&mut self, diags: Vec<crate::DiagInner>, registry: &Registry) { | ||
let data: Vec<FutureBreakageItem<'_>> = diags | ||
.into_iter() | ||
|
@@ -263,6 +285,16 @@ struct ArtifactNotification<'a> { | |
emit: &'a str, | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct SectionTimestamp<'a> { | ||
/// Name of the section | ||
name: &'a str, | ||
/// Start/end of the section | ||
kind: &'a str, | ||
/// Microseconds elapsed since some predetermined point in time (~start of the rustc process). | ||
Kobzol marked this conversation as resolved.
Show resolved
Hide resolved
|
||
timestamp: u128, | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct FutureBreakageItem<'a> { | ||
// Always EmitTyped::Diagnostic, but we want to make sure it gets serialized | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use crate::DiagCtxtHandle; | ||
|
||
/// A high-level section of the compilation process. | ||
#[derive(Copy, Clone, Debug)] | ||
pub enum TimingSection { | ||
/// Time spent linking. | ||
Linking, | ||
} | ||
|
||
/// Manages emission of start/end section timings, enabled through `--json=timings`. | ||
pub struct TimingSectionHandler { | ||
enabled: bool, | ||
} | ||
|
||
impl TimingSectionHandler { | ||
pub fn new(enabled: bool) -> Self { | ||
Self { enabled } | ||
} | ||
|
||
/// Returns a RAII guard that will immediately emit a start the provided section, and then emit | ||
/// its end when it is dropped. | ||
pub fn start_section<'a>( | ||
&self, | ||
diag_ctxt: DiagCtxtHandle<'a>, | ||
section: TimingSection, | ||
) -> TimingSectionGuard<'a> { | ||
TimingSectionGuard::create(diag_ctxt, section, self.enabled) | ||
} | ||
} | ||
|
||
pub struct TimingSectionGuard<'a> { | ||
dcx: DiagCtxtHandle<'a>, | ||
section: TimingSection, | ||
enabled: bool, | ||
} | ||
|
||
impl<'a> TimingSectionGuard<'a> { | ||
fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, enabled: bool) -> Self { | ||
if enabled { | ||
dcx.emit_timing_section_start(section); | ||
} | ||
Self { dcx, section, enabled } | ||
} | ||
} | ||
|
||
impl<'a> Drop for TimingSectionGuard<'a> { | ||
fn drop(&mut self) { | ||
if self.enabled { | ||
self.dcx.emit_timing_section_end(self.section); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a method on
TimingSectionKind
.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, but the
TimingSectionKind
is a shared data structure for all emitters, and this form of output is specific for JSON. It should IMO live here, in theory we could emit the timings also in other formats. It also avoids having to go to a different file to see how the output format looks like.I'm fine with moving it to a function in the
json
module, but I don't think it belongs as a method on the section kind.