From c108950b507e85beae18e091c8b507c77eb7000a Mon Sep 17 00:00:00 2001 From: Suryansh Dey Date: Thu, 19 Feb 2026 23:08:19 +0530 Subject: [PATCH 1/2] Adding cpu usage in cargo log --- src/cargo/core/compiler/timings/mod.rs | 49 +++++++++++++---------- src/cargo/core/compiler/timings/report.rs | 4 +- src/cargo/ops/cargo_report/timings.rs | 6 +++ src/cargo/util/log_message.rs | 7 ++++ 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/cargo/core/compiler/timings/mod.rs b/src/cargo/core/compiler/timings/mod.rs index 0022625ee56..2a7ce43cafe 100644 --- a/src/cargo/core/compiler/timings/mod.rs +++ b/src/cargo/core/compiler/timings/mod.rs @@ -262,31 +262,36 @@ impl<'gctx> Timings<'gctx> { build_runner: &BuildRunner<'_, '_>, error: &Option, ) -> CargoResult<()> { - if let Some(logger) = build_runner.bcx.logger - && let Some(logs) = logger.get_logs() - { - let timings_path = build_runner - .files() - .timings_dir() - .expect("artifact-dir was not locked"); - paths::create_dir_all(&timings_path)?; - let run_id = logger.run_id(); - let filename = timings_path.join(format!("cargo-timing-{run_id}.html")); - let mut f = BufWriter::new(paths::create(&filename)?); + if let Some(logger) = build_runner.bcx.logger { + // Log CPU usage data so it can be reconstructed by `cargo report timings`. + for &(elapsed, usage) in &self.cpu_usage { + logger.log(LogMessage::CpuUsage { elapsed, usage }); + } - let mut ctx = prepare_context(logs.into_iter(), run_id)?; - ctx.error = error; - ctx.cpu_usage = &self.cpu_usage; - report::write_html(ctx, &mut f)?; + if let Some(logs) = logger.get_logs() { + let timings_path = build_runner + .files() + .timings_dir() + .expect("artifact-dir was not locked"); + paths::create_dir_all(&timings_path)?; + let run_id = logger.run_id(); + let filename = timings_path.join(format!("cargo-timing-{run_id}.html")); + let mut f = BufWriter::new(paths::create(&filename)?); - let unstamped_filename = timings_path.join("cargo-timing.html"); - paths::link_or_copy(&filename, &unstamped_filename)?; + let mut ctx = prepare_context(logs.into_iter(), run_id)?; + ctx.error = error; + ctx.cpu_usage = std::borrow::Cow::Borrowed(&self.cpu_usage); + report::write_html(ctx, &mut f)?; - let mut shell = self.gctx.shell(); - let timing_path = std::env::current_dir().unwrap_or_default().join(&filename); - let link = shell.err_file_hyperlink(&timing_path); - let msg = format!("report saved to {link}{}{link:#}", timing_path.display(),); - shell.status_with_color("Timing", msg, &style::NOTE)?; + let unstamped_filename = timings_path.join("cargo-timing.html"); + paths::link_or_copy(&filename, &unstamped_filename)?; + + let mut shell = self.gctx.shell(); + let timing_path = std::env::current_dir().unwrap_or_default().join(&filename); + let link = shell.err_file_hyperlink(&timing_path); + let msg = format!("report saved to {link}{}{link:#}", timing_path.display(),); + shell.status_with_color("Timing", msg, &style::NOTE)?; + } } Ok(()) } diff --git a/src/cargo/core/compiler/timings/report.rs b/src/cargo/core/compiler/timings/report.rs index 9cd7d96ad3f..edd0dc8292e 100644 --- a/src/cargo/core/compiler/timings/report.rs +++ b/src/cargo/core/compiler/timings/report.rs @@ -108,7 +108,7 @@ pub struct RenderContext<'a> { /// Recorded CPU states, stored as tuples. First element is when the /// recording was taken and second element is percentage usage of the /// system. - pub cpu_usage: &'a [(f64, f64)], + pub cpu_usage: Cow<'a, [(f64, f64)]>, /// Compiler version info, i.e., `rustc 1.92.0-beta.2 (0a411606e 2025-10-31)`. pub rustc_version: String, /// The host triple (arch-platform-OS). @@ -257,7 +257,7 @@ fn write_js_data(ctx: &RenderContext<'_>, f: &mut impl Write) -> CargoResult<()> writeln!( f, "const CPU_USAGE = {};", - serde_json::to_string_pretty(&ctx.cpu_usage)? + serde_json::to_string_pretty(ctx.cpu_usage.as_ref())? )?; Ok(()) } diff --git a/src/cargo/ops/cargo_report/timings.rs b/src/cargo/ops/cargo_report/timings.rs index 60832d5c5c1..9c6a9bd0c06 100644 --- a/src/cargo/ops/cargo_report/timings.rs +++ b/src/cargo/ops/cargo_report/timings.rs @@ -156,6 +156,8 @@ where let mut requested_units: HashSet = HashSet::new(); + let mut cpu_usage: Vec<(f64, f64)> = Vec::new(); + for msg in log { match msg { LogMessage::BuildStarted { @@ -327,6 +329,9 @@ where tracing::warn!("unit {index} ended, but it has no start recorded"); } }, + LogMessage::CpuUsage { elapsed, usage } => { + cpu_usage.push((elapsed, usage)); + } _ => {} // skip non-timing logs } } @@ -382,6 +387,7 @@ where ctx.unit_data = unit_data; ctx.concurrency = compute_concurrency(&ctx.unit_data); ctx.requested_targets = platform_targets.into_iter().sorted_unstable().collect(); + ctx.cpu_usage = std::borrow::Cow::Owned(cpu_usage); Ok(ctx) } diff --git a/src/cargo/util/log_message.rs b/src/cargo/util/log_message.rs index 34b1bbc8a79..5fb5d52a811 100644 --- a/src/cargo/util/log_message.rs +++ b/src/cargo/util/log_message.rs @@ -152,6 +152,13 @@ pub enum LogMessage { #[serde(default, skip_serializing_if = "Option::is_none")] cause: Option, }, + /// Emitted periodically with CPU usage samples. + CpuUsage { + /// Seconds elapsed from build start. + elapsed: f64, + /// CPU usage percentage (0.0 to 100.0). + usage: f64, + }, } /// Cargo target information. From 15c374cb4c3b41e08dc9fa5a5737785b98419270 Mon Sep 17 00:00:00 2001 From: Suryansh Dey Date: Thu, 19 Feb 2026 23:38:45 +0530 Subject: [PATCH 2/2] Updating tests --- tests/testsuite/build_analysis.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/testsuite/build_analysis.rs b/tests/testsuite/build_analysis.rs index 458461bf726..11ebd434d28 100644 --- a/tests/testsuite/build_analysis.rs +++ b/tests/testsuite/build_analysis.rs @@ -173,7 +173,8 @@ fn log_msg_timing_info() { "reason": "unit-finished", "run_id": "[..]T[..]Z-[..]", "timestamp": "[..]T[..]Z" - } + }, + "{...}" ] "#]] .is_json() @@ -319,7 +320,8 @@ fn log_msg_timing_info_section_timings() { "reason": "unit-finished", "run_id": "[..]T[..]Z-[..]", "timestamp": "[..]T[..]Z" - } + }, + "{...}" ] "#]] .is_json()