mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Parse and store section timing events
This commit is contained in:
parent
62e40541fc
commit
dbd298a3cd
@ -7,6 +7,7 @@ use cargo_util::ProcessBuilder;
|
||||
use crate::CargoResult;
|
||||
use crate::core::compiler::build_runner::OutputFile;
|
||||
use crate::core::compiler::future_incompat::FutureBreakageItem;
|
||||
use crate::core::compiler::timings::SectionTiming;
|
||||
use crate::util::Queue;
|
||||
|
||||
use super::{Artifact, DiagDedupe, Job, JobId, Message};
|
||||
@ -143,6 +144,10 @@ impl<'a, 'gctx> JobState<'a, 'gctx> {
|
||||
.push(Message::Finish(self.id, Artifact::Metadata, Ok(())));
|
||||
}
|
||||
|
||||
pub fn on_section_timing_emitted(&self, section: SectionTiming) {
|
||||
self.messages.push(Message::SectionTiming(self.id, section));
|
||||
}
|
||||
|
||||
/// Drives a [`Job`] to finish. This ensures that a [`Message::Finish`] is
|
||||
/// sent even if our job panics.
|
||||
pub(super) fn run_to_finish(self, job: Job) {
|
||||
|
@ -133,7 +133,7 @@ pub use self::job::{Job, Work};
|
||||
pub use self::job_state::JobState;
|
||||
use super::build_runner::OutputFile;
|
||||
use super::custom_build::Severity;
|
||||
use super::timings::Timings;
|
||||
use super::timings::{SectionTiming, Timings};
|
||||
use super::{BuildContext, BuildPlan, BuildRunner, CompileMode, Unit};
|
||||
use crate::core::compiler::descriptive_pkg_name;
|
||||
use crate::core::compiler::future_incompat::{
|
||||
@ -374,6 +374,7 @@ enum Message {
|
||||
Token(io::Result<Acquired>),
|
||||
Finish(JobId, Artifact, CargoResult<()>),
|
||||
FutureIncompatReport(JobId, Vec<FutureBreakageItem>),
|
||||
SectionTiming(JobId, SectionTiming),
|
||||
}
|
||||
|
||||
impl<'gctx> JobQueue<'gctx> {
|
||||
@ -714,6 +715,9 @@ impl<'gctx> DrainState<'gctx> {
|
||||
let token = acquired_token.context("failed to acquire jobserver token")?;
|
||||
self.tokens.push(token);
|
||||
}
|
||||
Message::SectionTiming(id, section) => {
|
||||
self.timings.unit_section_timing(id, §ion);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -90,6 +90,7 @@ use self::output_depinfo::output_depinfo;
|
||||
use self::output_sbom::build_sbom;
|
||||
use self::unit_graph::UnitDep;
|
||||
use crate::core::compiler::future_incompat::FutureIncompatReport;
|
||||
use crate::core::compiler::timings::SectionTiming;
|
||||
pub use crate::core::compiler::unit::{Unit, UnitInterner};
|
||||
use crate::core::manifest::TargetSourcePath;
|
||||
use crate::core::profiles::{PanicStrategy, Profile, StripInner};
|
||||
@ -1968,6 +1969,12 @@ fn on_stderr_line_inner(
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let res = serde_json::from_str::<SectionTiming>(compiler_message.get());
|
||||
if let Ok(timing_record) = res {
|
||||
state.on_section_timing_emitted(timing_record);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Depending on what we're emitting from Cargo itself, we figure out what to
|
||||
// do with this JSON message.
|
||||
match options.format {
|
||||
|
@ -16,6 +16,7 @@ use std::collections::HashMap;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::thread::available_parallelism;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing::warn;
|
||||
|
||||
/// Tracking information for the entire build.
|
||||
///
|
||||
@ -63,6 +64,14 @@ pub struct Timings<'gctx> {
|
||||
cpu_usage: Vec<(f64, f64)>,
|
||||
}
|
||||
|
||||
/// Section of compilation.
|
||||
struct TimingSection {
|
||||
/// Start of the section, as an offset in seconds from `UnitTime::start`.
|
||||
start: f64,
|
||||
/// End of the section, as an offset in seconds from `UnitTime::start`.
|
||||
end: Option<f64>,
|
||||
}
|
||||
|
||||
/// Tracking information for an individual unit.
|
||||
struct UnitTime {
|
||||
unit: Unit,
|
||||
@ -79,6 +88,8 @@ struct UnitTime {
|
||||
unlocked_units: Vec<Unit>,
|
||||
/// Same as `unlocked_units`, but unlocked by rmeta.
|
||||
unlocked_rmeta_units: Vec<Unit>,
|
||||
/// Individual compilation section durations, gathered from `--json=timings`.
|
||||
sections: HashMap<String, TimingSection>,
|
||||
}
|
||||
|
||||
/// Periodic concurrency tracking information.
|
||||
@ -181,6 +192,7 @@ impl<'gctx> Timings<'gctx> {
|
||||
rmeta_time: None,
|
||||
unlocked_units: Vec::new(),
|
||||
unlocked_rmeta_units: Vec::new(),
|
||||
sections: Default::default(),
|
||||
};
|
||||
assert!(self.active.insert(id, unit_time).is_none());
|
||||
}
|
||||
@ -233,6 +245,26 @@ impl<'gctx> Timings<'gctx> {
|
||||
self.unit_times.push(unit_time);
|
||||
}
|
||||
|
||||
/// Handle the start/end of a compilation section.
|
||||
pub fn unit_section_timing(&mut self, id: JobId, section_timing: &SectionTiming) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
let Some(unit_time) = self.active.get_mut(&id) else {
|
||||
return;
|
||||
};
|
||||
let now = self.start.elapsed().as_secs_f64();
|
||||
|
||||
match section_timing.event {
|
||||
SectionTimingEvent::Start => {
|
||||
unit_time.start_section(§ion_timing.name, now);
|
||||
}
|
||||
SectionTimingEvent::End => {
|
||||
unit_time.end_section(§ion_timing.name, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is called periodically to mark the concurrency of internal structures.
|
||||
pub fn mark_concurrency(&mut self, active: usize, waiting: usize, inactive: usize) {
|
||||
if !self.enabled {
|
||||
@ -578,6 +610,46 @@ impl UnitTime {
|
||||
fn name_ver(&self) -> String {
|
||||
format!("{} v{}", self.unit.pkg.name(), self.unit.pkg.version())
|
||||
}
|
||||
|
||||
fn start_section(&mut self, name: &str, now: f64) {
|
||||
if self
|
||||
.sections
|
||||
.insert(
|
||||
name.to_string(),
|
||||
TimingSection {
|
||||
start: now - self.start,
|
||||
end: None,
|
||||
},
|
||||
)
|
||||
.is_some()
|
||||
{
|
||||
warn!("Compilation section {name} started more than once");
|
||||
}
|
||||
}
|
||||
|
||||
fn end_section(&mut self, name: &str, now: f64) {
|
||||
let Some(section) = self.sections.get_mut(name) else {
|
||||
warn!("Compilation section {name} ended, but it has no start recorded");
|
||||
return;
|
||||
};
|
||||
section.end = Some(now - self.start);
|
||||
}
|
||||
}
|
||||
|
||||
/// Start or end of a section timing.
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum SectionTimingEvent {
|
||||
Start,
|
||||
End,
|
||||
}
|
||||
|
||||
/// Represents a certain section (phase) of rustc compilation.
|
||||
/// It is emitted by rustc when the `--json=timings` flag is used.
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub struct SectionTiming {
|
||||
pub name: String,
|
||||
pub event: SectionTimingEvent,
|
||||
}
|
||||
|
||||
fn render_rustc_info(bcx: &BuildContext<'_, '_>) -> String {
|
||||
|
Loading…
x
Reference in New Issue
Block a user