Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)
Expand All @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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 })
}
Expand Down Expand Up @@ -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<S: Step>(&'a self, step: S) -> S::Output {
{
let mut stack = self.stack.borrow_mut();
Expand Down Expand Up @@ -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::<S>(),
args = step_debug_args(&step)
args = step_debug_args(&step),
location = crate::utils::tracing::format_location(*std::panic::Location::caller())
);
span.entered()
};
Expand Down
59 changes: 42 additions & 17 deletions src/bootstrap/src/utils/step_graph.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -20,6 +22,7 @@ pub struct StepGraph {
}

impl StepGraph {
#[track_caller]
pub fn register_step_execution<S: Step>(
&mut self,
step: &S,
Expand Down Expand Up @@ -57,6 +60,7 @@ impl StepGraph {
}
}

#[track_caller]
pub fn register_cached_step<S: Step>(
&mut self,
step: &S,
Expand Down Expand Up @@ -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<Location<'static>>,
}

#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
struct EdgeKey {
src: NodeHandle,
dst: NodeHandle,
}

// We could use a library for this, but they either:
Expand All @@ -114,8 +124,8 @@ struct Edge {
#[derive(Default)]
struct DotGraph {
nodes: Vec<Node>,
edges: HashMap<EdgeKey, EdgeData>,
/// The `NodeHandle` represents an index within `self.nodes`
edges: HashSet<Edge>,
key_to_index: HashMap<String, NodeHandle>,
}

Expand All @@ -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<NodeHandle> {
Expand All @@ -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::<Vec<_>>();
locations.sort();
locations.dedup();
let locations = locations.join(", ");
writeln!(
file,
r#"{} -> {} [style="{style}", tooltip="{locations}"]"#,
key.src.0, key.dst.0,
)?;
}

writeln!(file, "}}")
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/utils/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
Loading