diff options
| author | Jakub Beránek <berykubik@gmail.com> | 2025-03-04 12:29:51 +0100 |
|---|---|---|
| committer | Jakub Beránek <berykubik@gmail.com> | 2025-03-04 12:30:41 +0100 |
| commit | ead58ea6f8bf860459fe5351a83717a8e591b0af (patch) | |
| tree | f0a96ba960edb285fe6e86a55accb3cfa4d5ca15 | |
| parent | 2e5ab4e6a07a9ebdb6e593ca19112148250e6906 (diff) | |
| download | rust-ead58ea6f8bf860459fe5351a83717a8e591b0af.tar.gz rust-ead58ea6f8bf860459fe5351a83717a8e591b0af.zip | |
Move `BuildStep` and metric logging into `build_helper`
| -rw-r--r-- | src/build_helper/src/metrics.rs | 80 | ||||
| -rw-r--r-- | src/tools/opt-dist/src/metrics.rs | 73 |
2 files changed, 83 insertions, 70 deletions
diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index c9be63ed534..4b585c15182 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] @@ -100,3 +102,81 @@ fn null_as_f64_nan<'de, D: serde::Deserializer<'de>>(d: D) -> Result<f64, D::Err use serde::Deserialize as _; Option::<f64>::deserialize(d).map(|f| f.unwrap_or(f64::NAN)) } + +/// Represents a single bootstrap step, with the accumulated duration of all its children. +#[derive(Clone, Debug)] +pub struct BuildStep { + pub r#type: String, + pub children: Vec<BuildStep>, + pub duration: Duration, +} + +impl BuildStep { + /// Create a `BuildStep` representing a single invocation of bootstrap. + /// The most important thing is that the build step aggregates the + /// durations of all children, so that it can be easily accessed. + pub fn from_invocation(invocation: &JsonInvocation) -> Self { + fn parse(node: &JsonNode) -> Option<BuildStep> { + match node { + JsonNode::RustbuildStep { + type_: kind, + children, + duration_excluding_children_sec, + .. + } => { + let children: Vec<_> = children.into_iter().filter_map(parse).collect(); + let children_duration = children.iter().map(|c| c.duration).sum::<Duration>(); + Some(BuildStep { + r#type: kind.to_string(), + children, + duration: children_duration + + Duration::from_secs_f64(*duration_excluding_children_sec), + }) + } + JsonNode::TestSuite(_) => None, + } + } + + let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); + let children: Vec<_> = invocation.children.iter().filter_map(parse).collect(); + Self { r#type: "total".to_string(), children, duration } + } + + pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> { + let mut result = Vec::new(); + self.find_by_type(r#type, &mut result); + result + } + + fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a Self>) { + if self.r#type == r#type { + result.push(self); + } + for child in &self.children { + child.find_by_type(r#type, result); + } + } +} + +/// Writes build steps into a nice indented table. +pub fn format_build_steps(root: &BuildStep) -> String { + use std::fmt::Write; + + let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); + + fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { + substeps.push((level, step)); + for child in &step.children { + visit(child, level + 1, substeps); + } + } + + visit(root, 0, &mut substeps); + + let mut output = String::new(); + for (level, step) in substeps { + let label = format!("{}{}", ".".repeat(level as usize), step.r#type); + writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); + } + output +} diff --git a/src/tools/opt-dist/src/metrics.rs b/src/tools/opt-dist/src/metrics.rs index 89c4cb12d4c..0a745566eb5 100644 --- a/src/tools/opt-dist/src/metrics.rs +++ b/src/tools/opt-dist/src/metrics.rs @@ -1,33 +1,10 @@ use std::time::Duration; -use build_helper::metrics::{JsonNode, JsonRoot}; +use build_helper::metrics::{BuildStep, JsonRoot, format_build_steps}; use camino::Utf8Path; use crate::timer::TimerSection; -#[derive(Clone, Debug)] -pub struct BuildStep { - r#type: String, - children: Vec<BuildStep>, - duration: Duration, -} - -impl BuildStep { - pub fn find_all_by_type(&self, r#type: &str) -> Vec<&BuildStep> { - let mut result = Vec::new(); - self.find_by_type(r#type, &mut result); - result - } - fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a BuildStep>) { - if self.r#type == r#type { - result.push(self); - } - for child in &self.children { - child.find_by_type(r#type, result); - } - } -} - /// Loads the metrics of the most recent bootstrap execution from a metrics.json file. pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> { let content = std::fs::read(path.as_std_path())?; @@ -37,30 +14,7 @@ pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> { .pop() .ok_or_else(|| anyhow::anyhow!("No bootstrap invocation found in metrics file"))?; - fn parse(node: JsonNode) -> Option<BuildStep> { - match node { - JsonNode::RustbuildStep { - type_: kind, - children, - duration_excluding_children_sec, - .. - } => { - let children: Vec<_> = children.into_iter().filter_map(parse).collect(); - let children_duration = children.iter().map(|c| c.duration).sum::<Duration>(); - Some(BuildStep { - r#type: kind.to_string(), - children, - duration: children_duration - + Duration::from_secs_f64(duration_excluding_children_sec), - }) - } - JsonNode::TestSuite(_) => None, - } - } - - let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); - let children: Vec<_> = invocation.children.into_iter().filter_map(parse).collect(); - Ok(BuildStep { r#type: "root".to_string(), children, duration }) + Ok(BuildStep::from_invocation(&invocation)) } /// Logs the individual metrics in a table and add Rustc and LLVM durations to the passed @@ -82,27 +36,6 @@ pub fn record_metrics(metrics: &BuildStep, timer: &mut TimerSection) { timer.add_duration("Rustc", rustc_duration); } - log_metrics(metrics); -} - -fn log_metrics(metrics: &BuildStep) { - use std::fmt::Write; - - let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); - - fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { - substeps.push((level, step)); - for child in &step.children { - visit(child, level + 1, substeps); - } - } - - visit(metrics, 0, &mut substeps); - - let mut output = String::new(); - for (level, step) in substeps { - let label = format!("{}{}", ".".repeat(level as usize), step.r#type); - writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); - } + let output = format_build_steps(metrics); log::info!("Build step durations\n{output}"); } |
