Skip to content

Commit b8120d0

Browse files
committed
Store runtime benchmark execution errors into the database
1 parent 531080d commit b8120d0

File tree

2 files changed

+76
-35
lines changed

2 files changed

+76
-35
lines changed

collector/src/lib.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,18 @@ impl CollectorCtx {
344344
.await
345345
}
346346

347-
pub async fn start_runtime_step(&self, conn: &dyn Connection, group: &BenchmarkGroup) -> bool {
348-
conn.collector_start_step(self.artifact_row_id, &runtime_group_step_name(group))
347+
/// Starts a new runtime benchmark collector step.
348+
/// If this step was already computed, returns None.
349+
/// Otherwise returns Some(<name of step>).
350+
pub async fn start_runtime_step(
351+
&self,
352+
conn: &dyn Connection,
353+
group: &BenchmarkGroup,
354+
) -> Option<String> {
355+
let step_name = runtime_group_step_name(group);
356+
conn.collector_start_step(self.artifact_row_id, &step_name)
349357
.await
358+
.then_some(step_name)
350359
}
351360

352361
pub async fn end_runtime_step(&self, conn: &dyn Connection, group: &BenchmarkGroup) {

collector/src/runtime/mod.rs

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use std::io::{BufRead, BufReader};
1+
use std::io::{BufRead, BufReader, Cursor};
22
use std::path::Path;
33
use std::process::{Command, Stdio};
44

5+
use anyhow::Context;
56
use thousands::Separable;
67

78
use benchlib::comm::messages::{BenchmarkMessage, BenchmarkResult, BenchmarkStats};
@@ -12,7 +13,7 @@ pub use benchmark::{
1213
use database::{ArtifactIdNumber, CollectionId, Connection};
1314

1415
use crate::utils::git::get_rustc_perf_commit;
15-
use crate::CollectorCtx;
16+
use crate::{run_command_with_output, CollectorCtx};
1617

1718
mod benchmark;
1819

@@ -38,41 +39,62 @@ pub async fn bench_runtime(
3839
);
3940

4041
let rustc_perf_version = get_rustc_perf_commit();
41-
4242
let mut benchmark_index = 0;
4343
for group in suite.groups {
44-
if !collector.start_runtime_step(conn, &group).await {
44+
let Some(step_name) = collector.start_runtime_step(conn, &group).await else {
4545
eprintln!("skipping {} -- already benchmarked", group.name);
4646
continue;
47-
}
47+
};
4848

4949
let mut tx = conn.transaction().await;
50-
for message in execute_runtime_benchmark_binary(&group.binary, &filter, iterations)? {
51-
let message = message.map_err(|err| {
52-
anyhow::anyhow!(
53-
"Cannot parse BenchmarkMessage from benchmark {}: {err:?}",
54-
group.binary.display()
55-
)
56-
})?;
57-
match message {
58-
BenchmarkMessage::Result(result) => {
59-
benchmark_index += 1;
60-
println!(
61-
"Finished {}/{} ({}/{})",
62-
group.name, result.name, benchmark_index, filtered
63-
);
64-
65-
print_stats(&result);
66-
record_stats(
67-
tx.conn(),
68-
collector.artifact_row_id,
69-
&rustc_perf_version,
70-
result,
50+
51+
// Async block is used to easily capture all results, it basically simulates a `try` block.
52+
// Extracting this into a separate function would be annoying, as there would be many
53+
// parameters.
54+
let result = async {
55+
let messages = execute_runtime_benchmark_binary(&group.binary, &filter, iterations)?;
56+
for message in messages {
57+
let message = message.map_err(|err| {
58+
anyhow::anyhow!(
59+
"Cannot parse BenchmarkMessage from benchmark {}: {err:?}",
60+
group.binary.display()
7161
)
72-
.await;
62+
})?;
63+
match message {
64+
BenchmarkMessage::Result(result) => {
65+
benchmark_index += 1;
66+
println!(
67+
"Finished {}/{} ({}/{})",
68+
group.name, result.name, benchmark_index, filtered
69+
);
70+
71+
print_stats(&result);
72+
record_stats(
73+
tx.conn(),
74+
collector.artifact_row_id,
75+
&rustc_perf_version,
76+
result,
77+
)
78+
.await;
79+
}
7380
}
7481
}
82+
83+
Ok::<_, anyhow::Error>(())
7584
}
85+
.await
86+
.with_context(|| format!("Failed to execute runtime benchmark group {}", group.name));
87+
88+
if let Err(error) = result {
89+
eprintln!("collector error: {:#}", error);
90+
tx.conn()
91+
.record_error(
92+
collector.artifact_row_id,
93+
&step_name,
94+
&format!("{:?}", error),
95+
)
96+
.await;
97+
};
7698

7799
collector.end_runtime_step(tx.conn(), &group).await;
78100
tx.commit()
@@ -178,6 +200,9 @@ fn execute_runtime_benchmark_binary(
178200
command.arg("--iterations");
179201
command.arg(&iterations.to_string());
180202

203+
// We want to see a backtrace if the benchmark panics
204+
command.env("RUST_BACKTRACE", "1");
205+
181206
if let Some(ref exclude) = filter.exclude {
182207
command.args(["--exclude", exclude]);
183208
}
@@ -186,14 +211,21 @@ fn execute_runtime_benchmark_binary(
186211
}
187212

188213
command.stdout(Stdio::piped());
189-
let mut child = command.spawn()?;
190-
let stdout = child.stdout.take().unwrap();
214+
command.stderr(Stdio::piped());
191215

192-
let reader = BufReader::new(stdout);
193-
let iterator = reader.lines().map(|line| {
216+
let output = run_command_with_output(&mut command)?;
217+
if !output.status.success() {
218+
return Err(anyhow::anyhow!(
219+
"Process finished with exit code {}\n{}",
220+
output.status.code().unwrap_or(-1),
221+
String::from_utf8_lossy(&output.stderr)
222+
));
223+
}
224+
225+
let reader = BufReader::new(Cursor::new(output.stdout));
226+
Ok(reader.lines().map(|line| {
194227
Ok(line.and_then(|line| Ok(serde_json::from_str::<BenchmarkMessage>(&line)?))?)
195-
});
196-
Ok(iterator)
228+
}))
197229
}
198230

199231
fn calculate_mean<I: Iterator<Item = f64> + Clone>(iter: I) -> f64 {

0 commit comments

Comments
 (0)