Skip to content
Draft
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
49 changes: 27 additions & 22 deletions src/cargo/core/compiler/timings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,31 +262,36 @@ impl<'gctx> Timings<'gctx> {
build_runner: &BuildRunner<'_, '_>,
error: &Option<anyhow::Error>,
) -> 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(())
}
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/core/compiler/timings/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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(())
}
Expand Down
6 changes: 6 additions & 0 deletions src/cargo/ops/cargo_report/timings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ where

let mut requested_units: HashSet<UnitIndex> = HashSet::new();

let mut cpu_usage: Vec<(f64, f64)> = Vec::new();

for msg in log {
match msg {
LogMessage::BuildStarted {
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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)
}
7 changes: 7 additions & 0 deletions src/cargo/util/log_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ pub enum LogMessage {
#[serde(default, skip_serializing_if = "Option::is_none")]
cause: Option<DirtyReason>,
},
/// 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.
Expand Down
6 changes: 4 additions & 2 deletions tests/testsuite/build_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ fn log_msg_timing_info() {
"reason": "unit-finished",
"run_id": "[..]T[..]Z-[..]",
"timestamp": "[..]T[..]Z"
}
},
"{...}"
]
"#]]
.is_json()
Expand Down Expand Up @@ -319,7 +320,8 @@ fn log_msg_timing_info_section_timings() {
"reason": "unit-finished",
"run_id": "[..]T[..]Z-[..]",
"timestamp": "[..]T[..]Z"
}
},
"{...}"
]
"#]]
.is_json()
Expand Down
Loading