From 0cabe7096b7094248197306b9fe2b33a67bfcdd6 Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sun, 30 Aug 2026 16:08:56 +0900 Subject: [PATCH 1/3] perf: Avoid skewing profile timings by not logging UnitGraph On large workspaces, the formatting `UnitGraph` can take a long time. Notably on Zed, it was taking over 300ms on my machine, meaningfully skewing the profiling results. This commit makes dumping the unit graph opt-in with `__CARGO_DUMP_UNIT_DEP_GRAPH` --- src/compiler/unit_dependencies.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/compiler/unit_dependencies.rs b/src/compiler/unit_dependencies.rs index 6002edfbfcc..d0fc3a40669 100644 --- a/src/compiler/unit_dependencies.rs +++ b/src/compiler/unit_dependencies.rs @@ -165,11 +165,29 @@ pub fn build_unit_dependencies<'a, 'gctx>( list.sort(); } } - trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies); + + log_unit_deps_graph(ws.gctx(), &state.unit_dependencies); Ok(state.unit_dependencies) } +fn log_unit_deps_graph(gctx: &GlobalContext, graph: &UnitGraph) { + // For workspaces with large dependency graphs, the act of logging graph can actually take + // hundreds of milliseconds, skewing the profiling timings. By default, we do not dump the + // entire graph to avoid skewing the timings. + let graph_to_log = if gctx.get_env("__CARGO_DUMP_UNIT_DEP_GRAPH").unwrap_or("0") == "1" { + Some(graph) + } else { + None + }; + + trace!( + count = graph.len(), + graph = format!("{graph_to_log:#?}"), + "ALL UNIT DEPENDENCIES", + ); +} + /// Compute all the dependencies for the standard library. fn calc_deps_of_std( state: &mut State<'_, '_>, From e1f5db41f09ffc4802b4b01520e4ec62ee570f7f Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sun, 30 Aug 2026 17:06:11 +0900 Subject: [PATCH 2/3] perf: Removed sbom trace! macro in hot loop This trace! was in a hot loop skewing the timings when cargo profiling is enabled. As a side note `build_sbom_graph` does appear to take up a meaninful amount of time in `prepare_rust` due to needing to walk the dependency graph. --- src/compiler/output_sbom.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/compiler/output_sbom.rs b/src/compiler/output_sbom.rs index 1047425ca7e..7e7023138cd 100644 --- a/src/compiler/output_sbom.rs +++ b/src/compiler/output_sbom.rs @@ -165,12 +165,6 @@ fn build_sbom_graph<'a>( true => SbomDependencyType::Build, }; dependencies.insert((dep, dep_type)); - tracing::trace!( - "adding sbom edge {} -> {} ({:?})", - parent.pkg.package_id(), - dep.pkg.package_id(), - dep_type, - ); (dep, false) }; if visited.insert(dep) { From 9163fb05221fd5f82ca2e5c47495cb44569bdb4c Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Sun, 30 Aug 2026 17:15:39 +0900 Subject: [PATCH 3/3] perf: Instrumented more compiler related functions Added profiling instrumentation on more profiler related functions to give more visiblity on where we spend time while preparing rustc jobs. --- src/compiler/fingerprint/mod.rs | 1 + src/compiler/mod.rs | 5 +++++ src/compiler/output_sbom.rs | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/compiler/fingerprint/mod.rs b/src/compiler/fingerprint/mod.rs index 65cd3aa01af..5a110be75b8 100644 --- a/src/compiler/fingerprint/mod.rs +++ b/src/compiler/fingerprint/mod.rs @@ -1539,6 +1539,7 @@ impl StaleItem { /// /// Information like file modification time is only calculated for path /// dependencies. +#[tracing::instrument(skip_all)] fn calculate(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult> { // This function is slammed quite a lot, so the result is memoized. if let Some(s) = build_runner.fingerprints.get(unit) { diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 0fd0fcf0cec..71c6c43b0d6 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -307,6 +307,7 @@ fn make_failed_scrape_diagnostic( } /// Creates a unit of work invoking `rustc` for building the `unit`. +#[tracing::instrument(skip_all)] fn rustc( build_runner: &mut BuildRunner<'_, '_>, unit: &Unit, @@ -818,6 +819,7 @@ where /// This builds a static view of the invocation. Flags depending on the /// completion of other units will be added later in runtime, such as flags /// from build scripts. +#[tracing::instrument(skip_all)] fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let gctx = build_runner.bcx.gctx; let is_primary = build_runner.is_primary_package(unit); @@ -894,6 +896,7 @@ fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult /// This builds a static view of the invocation. Flags depending on the /// completion of other units will be added later in runtime, such as flags /// from build scripts. +#[tracing::instrument(skip_all)] fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let bcx = build_runner.bcx; // script_metadata is not needed here, it is only for tests. @@ -1035,6 +1038,7 @@ fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResu } /// Creates a unit of work invoking `rustdoc` for documenting the `unit`. +#[tracing::instrument(skip_all)] fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult { let mut rustdoc = prepare_rustdoc(build_runner, unit)?; @@ -1803,6 +1807,7 @@ fn add_custom_flags( } /// Generate a list of `-L` arguments +#[tracing::instrument(skip_all)] pub fn lib_search_paths( build_runner: &BuildRunner<'_, '_>, unit: &Unit, diff --git a/src/compiler/output_sbom.rs b/src/compiler/output_sbom.rs index 7e7023138cd..be8fed4b467 100644 --- a/src/compiler/output_sbom.rs +++ b/src/compiler/output_sbom.rs @@ -97,6 +97,7 @@ pub struct Sbom { } /// Build an [`Sbom`] for the given [`Unit`]. +#[tracing::instrument(skip_all)] pub fn build_sbom(build_runner: &BuildRunner<'_, '_>, root: &Unit) -> CargoResult { let bcx = build_runner.bcx; let rustc: SbomRustc = bcx.rustc().into(); @@ -139,6 +140,7 @@ pub fn build_sbom(build_runner: &BuildRunner<'_, '_>, root: &Unit) -> CargoResul /// if it's using different settings, e.g. profile, features or crate versions. /// /// Returns a graph of dependencies. +#[tracing::instrument(skip_all)] fn build_sbom_graph<'a>( build_runner: &'a BuildRunner<'_, '_>, root: &'a Unit,