Skip to content

Commit ead58ea

Browse files
committed
Move BuildStep and metric logging into build_helper
1 parent 2e5ab4e commit ead58ea

File tree

2 files changed

+83
-70
lines changed

2 files changed

+83
-70
lines changed

Diff for: src/build_helper/src/metrics.rs

+80
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::time::Duration;
2+
13
use serde_derive::{Deserialize, Serialize};
24

35
#[derive(Serialize, Deserialize)]
@@ -100,3 +102,81 @@ fn null_as_f64_nan<'de, D: serde::Deserializer<'de>>(d: D) -> Result<f64, D::Err
100102
use serde::Deserialize as _;
101103
Option::<f64>::deserialize(d).map(|f| f.unwrap_or(f64::NAN))
102104
}
105+
106+
/// Represents a single bootstrap step, with the accumulated duration of all its children.
107+
#[derive(Clone, Debug)]
108+
pub struct BuildStep {
109+
pub r#type: String,
110+
pub children: Vec<BuildStep>,
111+
pub duration: Duration,
112+
}
113+
114+
impl BuildStep {
115+
/// Create a `BuildStep` representing a single invocation of bootstrap.
116+
/// The most important thing is that the build step aggregates the
117+
/// durations of all children, so that it can be easily accessed.
118+
pub fn from_invocation(invocation: &JsonInvocation) -> Self {
119+
fn parse(node: &JsonNode) -> Option<BuildStep> {
120+
match node {
121+
JsonNode::RustbuildStep {
122+
type_: kind,
123+
children,
124+
duration_excluding_children_sec,
125+
..
126+
} => {
127+
let children: Vec<_> = children.into_iter().filter_map(parse).collect();
128+
let children_duration = children.iter().map(|c| c.duration).sum::<Duration>();
129+
Some(BuildStep {
130+
r#type: kind.to_string(),
131+
children,
132+
duration: children_duration
133+
+ Duration::from_secs_f64(*duration_excluding_children_sec),
134+
})
135+
}
136+
JsonNode::TestSuite(_) => None,
137+
}
138+
}
139+
140+
let duration = Duration::from_secs_f64(invocation.duration_including_children_sec);
141+
let children: Vec<_> = invocation.children.iter().filter_map(parse).collect();
142+
Self { r#type: "total".to_string(), children, duration }
143+
}
144+
145+
pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> {
146+
let mut result = Vec::new();
147+
self.find_by_type(r#type, &mut result);
148+
result
149+
}
150+
151+
fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a Self>) {
152+
if self.r#type == r#type {
153+
result.push(self);
154+
}
155+
for child in &self.children {
156+
child.find_by_type(r#type, result);
157+
}
158+
}
159+
}
160+
161+
/// Writes build steps into a nice indented table.
162+
pub fn format_build_steps(root: &BuildStep) -> String {
163+
use std::fmt::Write;
164+
165+
let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
166+
167+
fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
168+
substeps.push((level, step));
169+
for child in &step.children {
170+
visit(child, level + 1, substeps);
171+
}
172+
}
173+
174+
visit(root, 0, &mut substeps);
175+
176+
let mut output = String::new();
177+
for (level, step) in substeps {
178+
let label = format!("{}{}", ".".repeat(level as usize), step.r#type);
179+
writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap();
180+
}
181+
output
182+
}

Diff for: src/tools/opt-dist/src/metrics.rs

+3-70
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
use std::time::Duration;
22

3-
use build_helper::metrics::{JsonNode, JsonRoot};
3+
use build_helper::metrics::{BuildStep, JsonRoot, format_build_steps};
44
use camino::Utf8Path;
55

66
use crate::timer::TimerSection;
77

8-
#[derive(Clone, Debug)]
9-
pub struct BuildStep {
10-
r#type: String,
11-
children: Vec<BuildStep>,
12-
duration: Duration,
13-
}
14-
15-
impl BuildStep {
16-
pub fn find_all_by_type(&self, r#type: &str) -> Vec<&BuildStep> {
17-
let mut result = Vec::new();
18-
self.find_by_type(r#type, &mut result);
19-
result
20-
}
21-
fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a BuildStep>) {
22-
if self.r#type == r#type {
23-
result.push(self);
24-
}
25-
for child in &self.children {
26-
child.find_by_type(r#type, result);
27-
}
28-
}
29-
}
30-
318
/// Loads the metrics of the most recent bootstrap execution from a metrics.json file.
329
pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> {
3310
let content = std::fs::read(path.as_std_path())?;
@@ -37,30 +14,7 @@ pub fn load_metrics(path: &Utf8Path) -> anyhow::Result<BuildStep> {
3714
.pop()
3815
.ok_or_else(|| anyhow::anyhow!("No bootstrap invocation found in metrics file"))?;
3916

40-
fn parse(node: JsonNode) -> Option<BuildStep> {
41-
match node {
42-
JsonNode::RustbuildStep {
43-
type_: kind,
44-
children,
45-
duration_excluding_children_sec,
46-
..
47-
} => {
48-
let children: Vec<_> = children.into_iter().filter_map(parse).collect();
49-
let children_duration = children.iter().map(|c| c.duration).sum::<Duration>();
50-
Some(BuildStep {
51-
r#type: kind.to_string(),
52-
children,
53-
duration: children_duration
54-
+ Duration::from_secs_f64(duration_excluding_children_sec),
55-
})
56-
}
57-
JsonNode::TestSuite(_) => None,
58-
}
59-
}
60-
61-
let duration = Duration::from_secs_f64(invocation.duration_including_children_sec);
62-
let children: Vec<_> = invocation.children.into_iter().filter_map(parse).collect();
63-
Ok(BuildStep { r#type: "root".to_string(), children, duration })
17+
Ok(BuildStep::from_invocation(&invocation))
6418
}
6519

6620
/// 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) {
8236
timer.add_duration("Rustc", rustc_duration);
8337
}
8438

85-
log_metrics(metrics);
86-
}
87-
88-
fn log_metrics(metrics: &BuildStep) {
89-
use std::fmt::Write;
90-
91-
let mut substeps: Vec<(u32, &BuildStep)> = Vec::new();
92-
93-
fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) {
94-
substeps.push((level, step));
95-
for child in &step.children {
96-
visit(child, level + 1, substeps);
97-
}
98-
}
99-
100-
visit(metrics, 0, &mut substeps);
101-
102-
let mut output = String::new();
103-
for (level, step) in substeps {
104-
let label = format!("{}{}", ".".repeat(level as usize), step.r#type);
105-
writeln!(output, "{label:<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap();
106-
}
39+
let output = format_build_steps(metrics);
10740
log::info!("Build step durations\n{output}");
10841
}

0 commit comments

Comments
 (0)