From 1b23b64be4bf9e827cbc9d7c4012da77e8f05a85 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 17 Jan 2025 23:23:56 +0200 Subject: Add `-Z hint-mostly-unused` to tell rustc that most of a crate will go unused This hint allows the compiler to optimize its operation based on this assumption, in order to compile faster. This is a hint, and does not guarantee any particular behavior. This option can substantially speed up compilation if applied to a large dependency where the majority of the dependency does not get used. This flag may slow down compilation in other cases. Currently, this option makes the compiler defer as much code generation as possible from functions in the crate, until later crates invoke those functions. Functions that never get invoked will never have code generated for them. For instance, if a crate provides thousands of functions, but only a few of them will get called, this flag will result in the compiler only doing code generation for the called functions. (This uses the same mechanisms as cross-crate inlining of functions.) This does not affect `extern` functions, or functions marked as `#[inline(never)]`. Some performance numbers, based on a crate with many dependencies having just *one* large dependency set to `-Z hint-mostly-unused` (using Cargo's `profile-rustflags` option): A release build went from 4m07s to 2m04s. A non-release build went from 2m26s to 1m28s. --- .../src/compiler-flags/hint-mostly-unused.md | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md (limited to 'src') diff --git a/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md b/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md new file mode 100644 index 00000000000..80f5b1c4450 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md @@ -0,0 +1,33 @@ +# `hint-mostly-unused` + +This flag hints to the compiler that most of the crate will probably go unused. +The compiler can optimize its operation based on this assumption, in order to +compile faster. This is a hint, and does not guarantee any particular behavior. + +This option can substantially speed up compilation if applied to a large +dependency where the majority of the dependency does not get used. This flag +may slow down compilation in other cases. + +Currently, this option makes the compiler defer as much code generation as +possible from functions in the crate, until later crates invoke those +functions. Functions that never get invoked will never have code generated for +them. For instance, if a crate provides thousands of functions, but only a few +of them will get called, this flag will result in the compiler only doing code +generation for the called functions. (This uses the same mechanisms as +cross-crate inlining of functions.) This does not affect `extern` functions, or +functions marked as `#[inline(never)]`. + +To try applying this flag to one dependency out of a dependency tree, use the +[`profile-rustflags`](https://doc.rust-lang.org/cargo/reference/unstable.html#profile-rustflags-option) +feature of nightly cargo: + +```toml +cargo-features = ["profile-rustflags"] + +# ... +[dependencies] +mostly-unused-dependency = "1.2.3" + +[profile.release.package.mostly-unused-dependency] +rustflags = ["-Zhint-mostly-unused"] +``` -- cgit 1.4.1-3-g733a5 From 268fbfed477a20cb7efa04b8c28982f46f16a4a4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 11 Jun 2025 18:37:48 +0200 Subject: Un-remap `rustc-dev` component paths --- compiler/rustc_metadata/src/rmeta/decoder.rs | 22 ++++++++++++++++ compiler/rustc_session/src/config.rs | 6 +++++ compiler/rustc_session/src/options.rs | 9 +++++++ src/doc/rustc-dev-guide/src/tests/ui.md | 2 ++ src/tools/compiletest/src/runtest.rs | 6 +++++ .../ui-fulldeps/rustc-dev-remap.only-remap.stderr | 15 +++++++++++ .../rustc-dev-remap.remap-unremap.stderr | 18 +++++++++++++ tests/ui-fulldeps/rustc-dev-remap.rs | 30 ++++++++++++++++++++++ 8 files changed, 108 insertions(+) create mode 100644 tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr create mode 100644 tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr create mode 100644 tests/ui-fulldeps/rustc-dev-remap.rs (limited to 'src') diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 23f68a4833c..0bc980b4d9f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1759,6 +1759,17 @@ impl<'a> CrateMetadataRef<'a> { &mut name, ); + // If this file is under $sysroot/lib/rustlib/rustc-src/ + // and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base, + // then we change `name` to a similar state as if the rust was bootstrapped + // with `remap-debuginfo = true`. + try_to_translate_real_to_virtual( + option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"), + &sess.opts.real_rustc_dev_source_base_dir, + "compiler", + &mut name, + ); + // If this file's path has been remapped to `/rustc/$hash`, // we might be able to reverse that. // @@ -1770,6 +1781,17 @@ impl<'a> CrateMetadataRef<'a> { &mut name, ); + // If this file's path has been remapped to `/rustc-dev/$hash`, + // we might be able to reverse that. + // + // NOTE: if you update this, you might need to also update bootstrap's code for generating + // the `rustc-dev` component in `Src::run` in `src/bootstrap/dist.rs`. + try_to_translate_virtual_to_real( + option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"), + &sess.opts.real_rustc_dev_source_base_dir, + &mut name, + ); + let local_version = sess.source_map().new_imported_source_file( name, src_hash, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c53ab47328c..cb6034c0bf2 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1364,6 +1364,7 @@ impl Default for Options { cli_forced_local_thinlto_off: false, remap_path_prefix: Vec::new(), real_rust_source_base_dir: None, + real_rustc_dev_source_base_dir: None, edition: DEFAULT_EDITION, json_artifact_notifications: false, json_unused_externs: JsonUnusedExterns::No, @@ -2713,6 +2714,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // This is the location used by the `rust-src` `rustup` component. real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs"); + let real_rustc_dev_source_base_dir = + // This is the location used by the `rustc-dev` `rustup` component. + real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs"); + let mut search_paths = vec![]; for s in &matches.opt_strs("L") { search_paths.push(SearchPath::from_cli_opt( @@ -2766,6 +2771,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M cli_forced_local_thinlto_off: disable_local_thinlto, remap_path_prefix, real_rust_source_base_dir, + real_rustc_dev_source_base_dir, edition, json_artifact_notifications, json_unused_externs, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ecf9ef25278..8d8340e60c3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -397,6 +397,15 @@ top_level_options!( /// (the `rust.remap-debuginfo` option in `bootstrap.toml`). real_rust_source_base_dir: Option [TRACKED_NO_CRATE_HASH], + /// Base directory containing the `compiler/` directory for the rustc sources. + /// Right now it's always `$sysroot/lib/rustlib/rustc-src/rust` + /// (i.e. the `rustup` `rustc-dev` component). + /// + /// This directory is what the virtual `/rustc-dev/$hash` is translated back to, + /// if Rust was built with path remapping to `/rustc/$hash` enabled + /// (the `rust.remap-debuginfo` option in `bootstrap.toml`). + real_rustc_dev_source_base_dir: Option [TRACKED_NO_CRATE_HASH], + edition: Edition [TRACKED], /// `true` if we're emitting JSON blobs about each artifact produced diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 25d3efdbb82..9e4a11044e8 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -113,6 +113,8 @@ Compiletest makes the following replacements on the compiler output: - The base directory where the test's output goes is replaced with `$TEST_BUILD_DIR`. This only comes up in a few rare circumstances. Example: `/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui` +- The real directory to the standard library source is replaced with `$SRC_DIR_REAL`. +- The real directory to the compiler source is replaced with `$COMPILER_DIR_REAL`. - Tabs are replaced with `\t`. - Backslashes (`\`) are converted to forward slashes (`/`) within paths (using a heuristic). This helps normalize differences with Windows-style paths. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 75f24adb70f..9edcba5d460 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2371,6 +2371,12 @@ impl<'test> TestCx<'test> { let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); + // Real paths into the compiler + let rustc_src_dir = &self.config.sysroot_base.join("lib/rustlib/rustc-src/rust"); + rustc_src_dir.try_exists().expect(&*format!("{} should exists", rustc_src_dir)); + let rustc_src_dir = rustc_src_dir.read_link_utf8().unwrap_or(rustc_src_dir.to_path_buf()); + normalize_path(&rustc_src_dir.join("compiler"), "$COMPILER_DIR_REAL"); + // eg. // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/ normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr new file mode 100644 index 00000000000..f54b6803b34 --- /dev/null +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied + --> $DIR/rustc-dev-remap.rs:LL:COL + | +LL | type Result = NotAValidResultType; + | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType` + | + = help: the following other types implement trait `VisitorResult`: + () + ControlFlow +note: required by a bound in `rustc_ast::visit::Visitor::Result` + --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr new file mode 100644 index 00000000000..438c23458e2 --- /dev/null +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied + --> $DIR/rustc-dev-remap.rs:LL:COL + | +LL | type Result = NotAValidResultType; + | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType` + | + = help: the following other types implement trait `VisitorResult`: + () + ControlFlow +note: required by a bound in `rustc_ast::visit::Visitor::Result` + --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL + | +LL | type Result: VisitorResult = (); + | ^^^^^^^^^^^^^ required by this bound in `Visitor::Result` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui-fulldeps/rustc-dev-remap.rs b/tests/ui-fulldeps/rustc-dev-remap.rs new file mode 100644 index 00000000000..aae7d4c0c90 --- /dev/null +++ b/tests/ui-fulldeps/rustc-dev-remap.rs @@ -0,0 +1,30 @@ +//@ check-fail +// +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +// +//@ revisions: only-remap remap-unremap +//@ compile-flags: -Z simulate-remapped-rust-src-base=/rustc-dev/xyz +//@ [remap-unremap]compile-flags: -Ztranslate-remapped-path-to-local-path=yes + +// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically +// as the remapped revision will begin with $COMPILER_DIR_REAL, +// so we have to do it ourselves. +//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:COL" + +#![feature(rustc_private)] + +extern crate rustc_ast; + +use rustc_ast::visit::Visitor; + +struct MyStruct; +struct NotAValidResultType; + +impl Visitor<'_> for MyStruct { + type Result = NotAValidResultType; + //~^ ERROR the trait bound `NotAValidResultType: VisitorResult` is not satisfied +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From c9d305952e0a74a5d0428fed79b62487aefa41e4 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 6 Jun 2025 17:12:55 +0200 Subject: Add infrastructure for emitting timing sections --- compiler/rustc_errors/src/emitter.rs | 12 ++++- compiler/rustc_errors/src/json.rs | 29 ++++++++++- compiler/rustc_errors/src/lib.rs | 11 ++++ compiler/rustc_errors/src/timings.rs | 80 +++++++++++++++++++++++++++++ compiler/rustc_session/src/config.rs | 16 +++--- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 7 +++ src/doc/rustc/src/command-line-arguments.md | 3 ++ src/doc/rustc/src/json.md | 25 +++++++++ 9 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_errors/src/timings.rs (limited to 'src') diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index fe01e289334..6ab6f96079e 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -34,6 +34,7 @@ use crate::snippet::{ Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString, }; use crate::styled_buffer::StyledBuffer; +use crate::timings::TimingRecord; use crate::translation::{Translate, to_fluent_args}; use crate::{ CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, @@ -164,11 +165,16 @@ impl Margin { } } +pub enum TimingEvent { + Start, + End, +} + const ANONYMIZED_LINE_NUM: &str = "LL"; pub type DynEmitter = dyn Emitter + DynSend; -/// Emitter trait for emitting errors. +/// Emitter trait for emitting errors and other structured information. pub trait Emitter: Translate { /// Emit a structured diagnostic. fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry); @@ -177,6 +183,10 @@ pub trait Emitter: Translate { /// Currently only supported for the JSON format. fn emit_artifact_notification(&mut self, _path: &Path, _artifact_type: &str) {} + /// Emit a timestamp with start/end of a timing section. + /// Currently only supported for the JSON format. + fn emit_timing_section(&mut self, _record: TimingRecord, _event: TimingEvent) {} + /// Emit a report about future breakage. /// Currently only supported for the JSON format. fn emit_future_breakage_report(&mut self, _diags: Vec, _registry: &Registry) {} diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index a6583407b7e..d67e2ba2d60 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -28,9 +28,10 @@ use termcolor::{ColorSpec, WriteColor}; use crate::diagnostic::IsLint; use crate::emitter::{ ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme, - should_show_source_code, + TimingEvent, should_show_source_code, }; use crate::registry::Registry; +use crate::timings::{TimingRecord, TimingSection}; use crate::translation::{Translate, to_fluent_args}; use crate::{ CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions, @@ -104,6 +105,7 @@ impl JsonEmitter { enum EmitTyped<'a> { Diagnostic(Diagnostic), Artifact(ArtifactNotification<'a>), + SectionTiming(SectionTimestamp<'a>), FutureIncompat(FutureIncompatReport<'a>), UnusedExtern(UnusedExterns<'a>), } @@ -135,6 +137,21 @@ impl Emitter for JsonEmitter { } } + fn emit_timing_section(&mut self, record: TimingRecord, event: TimingEvent) { + let event = match event { + TimingEvent::Start => "start", + TimingEvent::End => "end", + }; + let name = match record.section { + TimingSection::Linking => "link", + }; + let data = SectionTimestamp { name, event, timestamp: record.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, registry: &Registry) { let data: Vec> = diags .into_iter() @@ -263,6 +280,16 @@ struct ArtifactNotification<'a> { emit: &'a str, } +#[derive(Serialize)] +struct SectionTimestamp<'a> { + /// Name of the section + name: &'a str, + /// Start/end of the section + event: &'a str, + /// Opaque timestamp. + timestamp: u128, +} + #[derive(Serialize)] struct FutureBreakageItem<'a> { // Always EmitTyped::Diagnostic, but we want to make sure it gets serialized diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9f72fc4705a..b520eb353d6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -74,7 +74,9 @@ pub use snippet::Style; pub use termcolor::{Color, ColorSpec, WriteColor}; use tracing::debug; +use crate::emitter::TimingEvent; use crate::registry::Registry; +use crate::timings::TimingRecord; pub mod annotate_snippet_emitter_writer; pub mod codes; @@ -90,6 +92,7 @@ mod snippet; mod styled_buffer; #[cfg(test)] mod tests; +pub mod timings; pub mod translation; pub type PResult<'a, T> = Result>; @@ -1156,6 +1159,14 @@ impl<'a> DiagCtxtHandle<'a> { self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } + pub fn emit_timing_section_start(&self, record: TimingRecord) { + self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::Start); + } + + pub fn emit_timing_section_end(&self, record: TimingRecord) { + self.inner.borrow_mut().emitter.emit_timing_section(record, TimingEvent::End); + } + pub fn emit_future_breakage_report(&self) { let inner = &mut *self.inner.borrow_mut(); let diags = std::mem::take(&mut inner.future_breakage_diagnostics); diff --git a/compiler/rustc_errors/src/timings.rs b/compiler/rustc_errors/src/timings.rs new file mode 100644 index 00000000000..27fc9df8d79 --- /dev/null +++ b/compiler/rustc_errors/src/timings.rs @@ -0,0 +1,80 @@ +use std::time::Instant; + +use crate::DiagCtxtHandle; + +/// A high-level section of the compilation process. +#[derive(Copy, Clone, Debug)] +pub enum TimingSection { + /// 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, +} + +impl TimingSectionHandler { + pub fn new(enabled: bool) -> Self { + let origin = if enabled { Some(Instant::now()) } else { None }; + Self { origin } + } + + /// 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.origin) + } +} + +/// RAII wrapper for starting and ending section timings. +pub struct TimingSectionGuard<'a> { + dcx: DiagCtxtHandle<'a>, + section: TimingSection, + origin: Option, +} + +impl<'a> TimingSectionGuard<'a> { + fn create(dcx: DiagCtxtHandle<'a>, section: TimingSection, origin: Option) -> 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)); + } + } +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 14068cec4d3..1a5571f8a22 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1366,7 +1366,7 @@ impl Default for Options { real_rust_source_base_dir: None, edition: DEFAULT_EDITION, json_artifact_notifications: false, - json_section_timings: false, + json_timings: false, json_unused_externs: JsonUnusedExterns::No, json_future_incompat: false, pretty: None, @@ -1883,7 +1883,7 @@ pub struct JsonConfig { json_artifact_notifications: bool, /// Output start and end timestamps of several high-level compilation sections /// (frontend, backend, linker). - json_section_timings: bool, + json_timings: bool, pub json_unused_externs: JsonUnusedExterns, json_future_incompat: bool, } @@ -1925,7 +1925,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json let mut json_artifact_notifications = false; let mut json_unused_externs = JsonUnusedExterns::No; let mut json_future_incompat = false; - let mut json_section_timings = false; + let mut json_timings = false; for option in matches.opt_strs("json") { // For now conservatively forbid `--color` with `--json` since `--json` // 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 } "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, - "timings" => json_section_timings = true, + "timings" => json_timings = true, "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, "future-incompat" => json_future_incompat = true, @@ -1955,7 +1955,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json json_rendered, json_color, json_artifact_notifications, - json_section_timings, + json_timings, json_unused_externs, json_future_incompat, } @@ -2483,7 +2483,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M json_rendered, json_color, json_artifact_notifications, - json_section_timings, + json_timings, json_unused_externs, json_future_incompat, } = parse_json(early_dcx, matches); @@ -2505,7 +2505,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); - if !unstable_opts.unstable_options && json_section_timings { + if !unstable_opts.unstable_options && json_timings { early_dcx.early_fatal("--json=timings is unstable and requires using `-Zunstable-options`"); } @@ -2786,7 +2786,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M real_rust_source_base_dir, edition, json_artifact_notifications, - json_section_timings, + json_timings, json_unused_externs, json_future_incompat, pretty, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4daa3631fd6..78f79f6484a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -412,7 +412,7 @@ top_level_options!( /// `true` if we're emitting JSON timings with the start and end of /// high-level compilation sections - json_section_timings: bool [UNTRACKED], + json_timings: bool [UNTRACKED], /// `true` if we're emitting a JSON blob containing the unused externs json_unused_externs: JsonUnusedExterns [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b8b4518b14e..ca42c5a4256 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -18,6 +18,7 @@ use rustc_errors::emitter::{ DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination, }; use rustc_errors::json::JsonEmitter; +use rustc_errors::timings::TimingSectionHandler; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl, fallback_fluent_bundle, @@ -156,6 +157,9 @@ pub struct Session { /// Used by `-Z self-profile`. pub prof: SelfProfilerRef, + /// Used to emit section timings events (enabled by `--json=timings`). + pub timings: TimingSectionHandler, + /// Data about code being compiled, gathered during compilation. pub code_stats: CodeStats, @@ -1126,6 +1130,8 @@ pub fn build_session( .as_ref() .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string()); + let timings = TimingSectionHandler::new(sopts.json_timings); + let sess = Session { target, host, @@ -1136,6 +1142,7 @@ pub fn build_session( io, incr_comp_session: RwLock::new(IncrCompSession::NotInitialized), prof, + timings, code_stats: Default::default(), lint_store: None, driver_lint_caps, diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index b704cee705b..d45ad1be27b 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -471,6 +471,9 @@ to customize the output: - `future-incompat` - includes a JSON message that contains a report if the crate contains any code that may fail to compile in the future. +- `timings` - output a JSON message when a certain compilation "section" + (such as frontend analysis, code generation, linking) begins or ends. + Note that it is invalid to combine the `--json` argument with the [`--color`](#option-color) argument, and it is required to combine `--json` with `--error-format=json`. diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md index c853f34ee03..8839a1a78c3 100644 --- a/src/doc/rustc/src/json.md +++ b/src/doc/rustc/src/json.md @@ -298,6 +298,31 @@ appropriately. (This is needed by Cargo which shares the same dependencies across multiple build targets, so it should only report an unused dependency if its not used by any of the targets.) +## Timings + +**This setting is currently unstable and requires usage of `-Zunstable-options`.** + +The `--timings` option will tell `rustc` to emit messages when a certain compilation +section (such as code generation or linking) begins or ends. The messages will have +the following format: + +```json +{ + "$message_type": "section_timing", /* Type of this message */ + "event": "start", /* Marks the "start" or "end" of the compilation section */ + "name": "link", /* The name of the compilation section */ + "time": 12345 /* Opaque timestamp when the message was emitted, in microseconds */ +} +``` + +Compilation sections can be nested; for example, if you encounter the start of "foo", +then the start of "bar", then the end of "bar" and then the end of "bar", it means that the +"bar" section happened as a part of the "foo" section. + +The timestamp should only be used for computing the duration of each section. + +We currently do not guarantee any specific section names to be emitted. + [option-emit]: command-line-arguments.md#option-emit [option-error-format]: command-line-arguments.md#option-error-format [option-json]: command-line-arguments.md#option-json -- cgit 1.4.1-3-g733a5 From 7e423201e69d8650738b2454ff2286a7339145fa Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Wed, 18 Jun 2025 09:44:41 +0200 Subject: Clarify documentation --- src/doc/rustc/src/json.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md index 8839a1a78c3..7421dd62108 100644 --- a/src/doc/rustc/src/json.md +++ b/src/doc/rustc/src/json.md @@ -303,7 +303,7 @@ its not used by any of the targets.) **This setting is currently unstable and requires usage of `-Zunstable-options`.** The `--timings` option will tell `rustc` to emit messages when a certain compilation -section (such as code generation or linking) begins or ends. The messages will have +section (such as code generation or linking) begins or ends. The messages currently have the following format: ```json @@ -311,10 +311,14 @@ the following format: "$message_type": "section_timing", /* Type of this message */ "event": "start", /* Marks the "start" or "end" of the compilation section */ "name": "link", /* The name of the compilation section */ - "time": 12345 /* Opaque timestamp when the message was emitted, in microseconds */ + // Opaque timestamp when the message was emitted, in microseconds + // The timestamp is currently relative to the beginning of the compilation session + "time": 12345 } ``` +Note that the JSON format of the `timings` messages is unstable and subject to change. + Compilation sections can be nested; for example, if you encounter the start of "foo", then the start of "bar", then the end of "bar" and then the end of "bar", it means that the "bar" section happened as a part of the "foo" section. -- cgit 1.4.1-3-g733a5