diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 048fcc5c80145..66e14dae9b9ec 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1150,6 +1150,7 @@ impl<'a> Builder<'a> { /// compiler will run on, *not* the target it will build code for). Explicitly does not take /// `Compiler` since all `Compiler` instances are meant to be obtained through this function, /// since it ensures that they are valid (i.e., built and assembled). + #[track_caller] #[cfg_attr( feature = "tracing", instrument( @@ -1183,6 +1184,7 @@ impl<'a> Builder<'a> { /// /// However, without this optimization, we would also build stage 2 rustc for **target1**, /// which is completely wasteful. + #[track_caller] pub fn compiler_for_std(&self, stage: u32) -> Compiler { if compile::Std::should_be_uplifted_from_stage_1(self, stage) { self.compiler(1, self.host_target) @@ -1202,6 +1204,7 @@ impl<'a> Builder<'a> { /// sysroot. /// /// See `force_use_stage1` and `force_use_stage2` for documentation on what each argument is. + #[track_caller] #[cfg_attr( feature = "tracing", instrument( @@ -1249,6 +1252,7 @@ impl<'a> Builder<'a> { /// Prefer using this method rather than manually invoking `Std::new`. /// /// Returns an optional build stamp, if libstd was indeed built. + #[track_caller] #[cfg_attr( feature = "tracing", instrument( @@ -1297,17 +1301,20 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler } } + #[track_caller] pub fn sysroot(&self, compiler: Compiler) -> PathBuf { self.ensure(compile::Sysroot::new(compiler)) } /// Returns the bindir for a compiler's sysroot. + #[track_caller] pub fn sysroot_target_bindir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf { self.ensure(Libdir { compiler, target }).join(target).join("bin") } /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. + #[track_caller] pub fn sysroot_target_libdir(&self, compiler: Compiler, target: TargetSelection) -> PathBuf { self.ensure(Libdir { compiler, target }).join(target).join("lib") } @@ -1416,6 +1423,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler /// Returns a path to `Rustdoc` that "belongs" to the `target_compiler`. /// It can be either a stage0 rustdoc or a locally built rustdoc that *links* to /// `target_compiler`. + #[track_caller] pub fn rustdoc_for_compiler(&self, target_compiler: Compiler) -> PathBuf { self.ensure(tool::Rustdoc { target_compiler }) } @@ -1532,6 +1540,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler /// Ensure that a given step is built, returning its output. This will /// cache the step, so it is safe (and good!) to call this as often as /// needed to ensure that all dependencies are built. + #[track_caller] pub fn ensure(&'a self, step: S) -> S::Output { { let mut stack = self.stack.borrow_mut(); @@ -1589,7 +1598,8 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler // in the step_name field. "step", step_name = pretty_step_name::(), - args = step_debug_args(&step) + args = step_debug_args(&step), + location = crate::utils::tracing::format_location(*std::panic::Location::caller()) ); span.entered() }; diff --git a/src/bootstrap/src/utils/step_graph.rs b/src/bootstrap/src/utils/step_graph.rs index cffe0dbb3e3a5..d6a2d89482ee4 100644 --- a/src/bootstrap/src/utils/step_graph.rs +++ b/src/bootstrap/src/utils/step_graph.rs @@ -1,10 +1,12 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::fmt::Debug; use std::io::BufWriter; +use std::panic::Location; use std::path::Path; use crate::core::builder::{AnyDebug, Step, pretty_step_name}; use crate::t; +use crate::utils::tracing::format_location; /// Records the executed steps and their dependencies in a directed graph, /// which can then be rendered into a DOT file for visualization. @@ -20,6 +22,7 @@ pub struct StepGraph { } impl StepGraph { + #[track_caller] pub fn register_step_execution( &mut self, step: &S, @@ -57,6 +60,7 @@ impl StepGraph { } } + #[track_caller] pub fn register_cached_step( &mut self, step: &S, @@ -97,12 +101,18 @@ struct Node { struct NodeHandle(usize); /// Represents a dependency between two bootstrap steps. -#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)] -struct Edge { - src: NodeHandle, - dst: NodeHandle, +#[derive(Default)] +struct EdgeData { // Was the corresponding execution of a step cached, or was the step actually executed? cached: bool, + // Locations from where the step was called + locations: Vec>, +} + +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] +struct EdgeKey { + src: NodeHandle, + dst: NodeHandle, } // We could use a library for this, but they either: @@ -114,8 +124,8 @@ struct Edge { #[derive(Default)] struct DotGraph { nodes: Vec, + edges: HashMap, /// The `NodeHandle` represents an index within `self.nodes` - edges: HashSet, key_to_index: HashMap, } @@ -127,16 +137,19 @@ impl DotGraph { handle } + #[track_caller] fn add_edge(&mut self, src: NodeHandle, dst: NodeHandle) { - self.edges.insert(Edge { src, dst, cached: false }); + let key = EdgeKey { src, dst }; + let edge = self.edges.entry(key).or_default(); + edge.locations.push(*Location::caller()); } + #[track_caller] fn add_cached_edge(&mut self, src: NodeHandle, dst: NodeHandle) { - // There's no point in rendering both cached and uncached edge - let uncached = Edge { src, dst, cached: false }; - if !self.edges.contains(&uncached) { - self.edges.insert(Edge { src, dst, cached: true }); - } + let key = EdgeKey { src, dst }; + let edge = self.edges.entry(key).or_default(); + edge.cached = true; + edge.locations.push(*Location::caller()); } fn get_handle_by_key(&self, key: &str) -> Option { @@ -157,11 +170,23 @@ impl DotGraph { )?; } - let mut edges: Vec<&Edge> = self.edges.iter().collect(); - edges.sort(); - for edge in edges { - let style = if edge.cached { "dashed" } else { "solid" }; - writeln!(file, r#"{} -> {} [style="{style}"]"#, edge.src.0, edge.dst.0)?; + let mut edges: Vec<(&EdgeKey, &EdgeData)> = self.edges.iter().collect(); + edges.sort_by_key(|(key, _)| **key); + for (key, data) in edges { + let style = if data.cached { "dashed" } else { "solid" }; + let mut locations = data + .locations + .iter() + .map(|location| format_location(*location)) + .collect::>(); + locations.sort(); + locations.dedup(); + let locations = locations.join(", "); + writeln!( + file, + r#"{} -> {} [style="{style}", tooltip="{locations}"]"#, + key.src.0, key.dst.0, + )?; } writeln!(file, "}}") diff --git a/src/bootstrap/src/utils/tracing.rs b/src/bootstrap/src/utils/tracing.rs index b1226ed7de7be..4e75347f4cbae 100644 --- a/src/bootstrap/src/utils/tracing.rs +++ b/src/bootstrap/src/utils/tracing.rs @@ -351,7 +351,7 @@ mod inner { let field = &values.fields[0]; write!(writer, " {{{}}}", field.1)?; } - write_location(writer, span.metadata())?; + write_with_location(writer)?; } // Executed command COMMAND_SPAN_TARGET => {