Skip to content

Commit be2f111

Browse files
committed
bench_pr: track switch to callgrind/callgrind_annotate
1 parent 9c0dc8c commit be2f111

File tree

3 files changed

+50
-66
lines changed

3 files changed

+50
-66
lines changed

ci-bench-runner/src/job/bench_pr.rs

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use std::cmp::Ordering;
22
use std::collections::HashMap;
33
use std::fmt::Write;
44
use std::fs;
5-
use std::fs::File;
65
use std::ops::Deref;
76
use std::path::Path;
8-
use std::process::{Command, Stdio};
7+
use std::process::Command;
98

109
use anyhow::{anyhow, bail, Context};
1110
use askama::Template;
@@ -554,7 +553,7 @@ fn compare_results(
554553
};
555554

556555
let cachegrind_diff = if scenario_kind == ScenarioKind::Icount {
557-
Some(cachegrind_diff(job_output_path, scenario)?)
556+
Some(callgrind_diff(job_output_path, scenario)?)
558557
} else {
559558
None
560559
};
@@ -604,68 +603,56 @@ fn split_on_threshold(diffs: Vec<ScenarioDiff>) -> (Vec<ScenarioDiff>, Vec<Scena
604603
}
605604

606605
/// Returns the detailed instruction diff between the baseline and the candidate
607-
pub fn cachegrind_diff(job_output_path: &Path, scenario: &str) -> anyhow::Result<String> {
608-
// The latest version of valgrind has deprecated cg_diff, which has been superseded by
609-
// cg_annotate. Many systems are running older versions, though, so we are sticking with cg_diff
610-
// for the time being.
611-
612-
let diffs_path = job_output_path.join("diffs");
613-
fs::create_dir_all(&diffs_path).context("failed to create dir for cg_diff output")?;
614-
615-
let baseline_cachegrind_file_path = job_output_path
616-
.join("base/results/cachegrind")
617-
.join(scenario);
618-
let candidate_cachegrind_file_path = job_output_path
619-
.join("candidate/results/cachegrind")
620-
.join(scenario);
621-
let diff_file_path = diffs_path.join(scenario);
622-
623-
// cg_diff generates a diff between two cachegrind output files in a custom format that is not
624-
// user-friendly
625-
let diff_file = File::create(&diff_file_path).context("cannot create temp file for cg_diff")?;
626-
let cg_diff = Command::new("cg_diff")
627-
// remove per-compilation uniqueness in symbols, eg
628-
// _ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$14reserve_rehash17hc60392f3f3eac4b2E.llvm.9716880419886440089 ->
629-
// _ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$14reserve_rehashE
630-
.arg("--mod-funcname=s/17h[0-9a-f]+E\\.llvm\\.\\d+/E/")
631-
// remove the leading path, which is unique for each checkout of the repository (we replace it by `rustls`)
632-
.arg("--mod-filename=s/.+\\/(target\\/release\\/build.+)/rustls\\/\\1/")
633-
.arg(baseline_cachegrind_file_path)
634-
.arg(candidate_cachegrind_file_path)
635-
.stdout(Stdio::from(diff_file))
636-
.spawn()
637-
.context("cannot spawn cg_diff subprocess")?
638-
.wait()
639-
.context("error waiting for cg_diff to finish")?;
640-
641-
if !cg_diff.success() {
642-
bail!(
643-
"cg_diff finished with an error (code = {:?})",
644-
cg_diff.code()
606+
pub fn callgrind_diff(job_output_path: &Path, scenario: &str) -> anyhow::Result<String> {
607+
// callgrind_annotate formats the callgrind output file, suitable for comparison with
608+
// callgrind_differ
609+
let callgrind_annotate_base = Command::new("callgrind_annotate")
610+
.arg(
611+
job_output_path
612+
.join("base/results/callgrind")
613+
.join(scenario),
645614
)
646-
}
647-
648-
// cg_annotate transforms the output of cg_diff into something a user can understand
649-
let cg_annotate = Command::new("cg_annotate")
650-
.arg(diff_file_path)
615+
// do not annotate source, to keep output compact
651616
.arg("--auto=no")
652617
.output()
653-
.context("error waiting for cg_annotate to finish")?;
618+
.context("error waiting for callgrind_annotate to finish")?;
654619

655-
let stdout =
656-
String::from_utf8(cg_annotate.stdout).context("cg_annotate produced invalid UTF8")?;
620+
let callgrind_annotate_candidate = Command::new("callgrind_annotate")
621+
.arg(
622+
job_output_path
623+
.join("candidate/results/callgrind")
624+
.join(scenario),
625+
)
626+
// do not annotate source, to keep output compact
627+
.arg("--auto=no")
628+
.output()
629+
.context("error waiting for callgrind_annotate to finish")?;
657630

658-
if !cg_annotate.status.success() {
659-
let stderr =
660-
String::from_utf8(cg_annotate.stderr).context("cg_annotate produced invalid UTF8")?;
631+
if !callgrind_annotate_base.status.success() {
632+
anyhow::bail!(
633+
"callgrind_annotate for base finished with an error (code = {:?})",
634+
callgrind_annotate_base.status.code()
635+
)
636+
}
661637

662-
bail!(
663-
"cg_annotate finished with an error (code = {:?}). Stdout:\n{stdout}\nStderr:\n{stderr}",
664-
cg_annotate.status.code()
638+
if !callgrind_annotate_candidate.status.success() {
639+
anyhow::bail!(
640+
"callgrind_annotate for candidate finished with an error (code = {:?})",
641+
callgrind_annotate_candidate.status.code()
665642
)
666643
}
667644

668-
Ok(stdout)
645+
let string_base = String::from_utf8(callgrind_annotate_base.stdout)
646+
.context("callgrind_annotate produced invalid UTF8")?;
647+
let string_candidate = String::from_utf8(callgrind_annotate_candidate.stdout)
648+
.context("callgrind_annotate produced invalid UTF8")?;
649+
650+
// TODO: reinstate actual diffing, using `callgrind_differ` crate
651+
Ok(format!(
652+
"Base output:\n{string_base}\n\
653+
=====\n\n\
654+
Candidate output:\n{string_candidate}\n"
655+
))
669656
}
670657

671658
#[derive(Template)]

ci-bench-runner/src/test/mod.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ mod webhook {
7979
}
8080
}
8181

82-
mod cachegrind {
83-
pub static SAMPLE_OUTPUT: &str = include_str!("data/cachegrind_outputs/sample");
82+
mod callgrind {
83+
pub static SAMPLE_OUTPUT: &str = include_str!("data/callgrind_outputs/sample");
8484
}
8585

8686
struct MockBenchRunner {
@@ -134,14 +134,11 @@ impl BenchRunner for MockBenchRunner {
134134
// Fake icounts
135135
fs::write(results_dir.join("icounts.csv"), "fake_bench,12345")?;
136136

137-
// Fake cachegrind output
138-
let cachegrind_dir = results_dir.join("cachegrind");
139-
fs::create_dir(&cachegrind_dir)?;
140-
fs::write(
141-
cachegrind_dir.join("calibration"),
142-
cachegrind::SAMPLE_OUTPUT,
143-
)?;
144-
fs::write(cachegrind_dir.join("fake_bench"), cachegrind::SAMPLE_OUTPUT)?;
137+
// Fake callgrind output
138+
let callgrind_dir = results_dir.join("callgrind");
139+
fs::create_dir(&callgrind_dir)?;
140+
fs::write(callgrind_dir.join("calibration"), callgrind::SAMPLE_OUTPUT)?;
141+
fs::write(callgrind_dir.join("fake_bench"), callgrind::SAMPLE_OUTPUT)?;
145142

146143
// Fake walltimes
147144
fs::write(

0 commit comments

Comments
 (0)