Skip to content

Commit 0892746

Browse files
committed
Make it easy to add diffing of output of arbitrary profilers (demonstrate for dep-graph)
1 parent a9cc22f commit 0892746

File tree

5 files changed

+111
-44
lines changed

5 files changed

+111
-44
lines changed

collector/src/bin/collector.rs

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,16 @@ fn check_measureme_installed() -> Result<(), String> {
132132
}
133133
}
134134

135-
fn check_installed(name: &str) -> anyhow::Result<()> {
136-
if !is_installed(name) {
137-
anyhow::bail!("`{}` is not installed but must be", name);
138-
}
139-
Ok(())
140-
}
141-
142-
fn generate_cachegrind_diffs(
135+
#[allow(clippy::too_many_arguments)]
136+
fn generate_diffs(
143137
id1: &str,
144138
id2: &str,
145139
out_dir: &Path,
146140
benchmarks: &[Benchmark],
147141
profiles: &[Profile],
148142
scenarios: &[Scenario],
149143
errors: &mut BenchmarkErrors,
144+
profiler: &Profiler,
150145
) -> Vec<PathBuf> {
151146
let mut annotated_diffs = Vec::new();
152147
for benchmark in benchmarks {
@@ -166,22 +161,28 @@ fn generate_cachegrind_diffs(
166161
}) {
167162
let filename = |prefix, id| {
168163
format!(
169-
"{}-{}-{}-{:?}-{}",
170-
prefix, id, benchmark.name, profile, scenario
164+
"{}-{}-{}-{:?}-{}{}",
165+
prefix,
166+
id,
167+
benchmark.name,
168+
profile,
169+
scenario,
170+
profiler.postfix()
171171
)
172172
};
173173
let id_diff = format!("{}-{}", id1, id2);
174-
let cgout1 = out_dir.join(filename("cgout", id1));
175-
let cgout2 = out_dir.join(filename("cgout", id2));
176-
let cgann_diff = out_dir.join(filename("cgann-diff", &id_diff));
174+
let prefix = profiler.prefix();
175+
let left = out_dir.join(filename(prefix, id1));
176+
let right = out_dir.join(filename(prefix, id2));
177+
let output = out_dir.join(filename(&format!("{prefix}-diff"), &id_diff));
177178

178-
if let Err(e) = cachegrind_diff(&cgout1, &cgout2, &cgann_diff) {
179+
if let Err(e) = profiler.diff(&left, &right, &output) {
179180
errors.incr();
180181
eprintln!("collector error: {:?}", e);
181182
continue;
182183
}
183184

184-
annotated_diffs.push(cgann_diff);
185+
annotated_diffs.push(output);
185186
}
186187
}
187188
}
@@ -1145,29 +1146,25 @@ fn main_result() -> anyhow::Result<i32> {
11451146
let id1 = get_toolchain_and_profile(local.rustc.as_str(), "1")?;
11461147
let id2 = get_toolchain_and_profile(rustc2.as_str(), "2")?;
11471148

1148-
if profiler == Profiler::Cachegrind {
1149-
check_installed("valgrind")?;
1150-
check_installed("cg_annotate")?;
1151-
1152-
let diffs = generate_cachegrind_diffs(
1153-
&id1,
1154-
&id2,
1155-
&out_dir,
1156-
&benchmarks,
1157-
profiles,
1158-
scenarios,
1159-
&mut errors,
1160-
);
1161-
if let [diff] = &diffs[..] {
1162-
let short = out_dir.join("cgann-diff-latest");
1163-
std::fs::copy(diff, &short).expect("copy to short path");
1164-
eprintln!("Original diff at: {}", diff.to_string_lossy());
1165-
eprintln!("Short path: {}", short.to_string_lossy());
1166-
} else {
1167-
eprintln!("Diffs:");
1168-
for diff in diffs {
1169-
eprintln!("{}", diff.to_string_lossy());
1170-
}
1149+
let diffs = generate_diffs(
1150+
&id1,
1151+
&id2,
1152+
&out_dir,
1153+
&benchmarks,
1154+
profiles,
1155+
scenarios,
1156+
&mut errors,
1157+
&profiler,
1158+
);
1159+
if let [diff] = &diffs[..] {
1160+
let short = out_dir.join(format!("{}-diff-latest", profiler.prefix()));
1161+
std::fs::copy(diff, &short).expect("copy to short path");
1162+
eprintln!("Original diff at: {}", diff.to_string_lossy());
1163+
eprintln!("Short path: {}", short.to_string_lossy());
1164+
} else {
1165+
eprintln!("Diffs:");
1166+
for diff in diffs {
1167+
eprintln!("{}", diff.to_string_lossy());
11711168
}
11721169
}
11731170
} else {

collector/src/compile/execute/profiler.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::compile::execute::{PerfTool, ProcessOutputData, Processor, Retry};
2-
use crate::utils;
3-
use crate::utils::cachegrind::cachegrind_annotate;
2+
use crate::utils::cachegrind::{cachegrind_annotate, cachegrind_diff};
3+
use crate::utils::diff::run_diff;
4+
use crate::utils::{self};
45
use anyhow::Context;
56
use std::collections::HashMap;
67
use std::fs::File;
@@ -51,6 +52,42 @@ impl Profiler {
5152
| Profiler::DepGraph
5253
)
5354
}
55+
56+
/// A file prefix added to all files of this profiler.
57+
pub fn prefix(&self) -> &'static str {
58+
use Profiler::*;
59+
match self {
60+
Cachegrind => "cgout",
61+
DepGraph => "dep-graph",
62+
63+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
64+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => "",
65+
}
66+
}
67+
68+
/// A postfix added to the file that gets diffed.
69+
pub fn postfix(&self) -> &'static str {
70+
use Profiler::*;
71+
match self {
72+
Cachegrind => "",
73+
DepGraph => ".txt",
74+
75+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
76+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => "",
77+
}
78+
}
79+
80+
/// Actually perform the diff
81+
pub fn diff(&self, left: &Path, right: &Path, output: &Path) -> anyhow::Result<()> {
82+
use Profiler::*;
83+
match self {
84+
Cachegrind => cachegrind_diff(left, right, output),
85+
DepGraph => run_diff(left, right, output),
86+
87+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
88+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => Ok(()),
89+
}
90+
}
5491
}
5592

5693
pub struct ProfileProcessor<'a> {

collector/src/utils/cachegrind.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::utils::is_installed;
21
use crate::utils::mangling::demangle_file;
32
use anyhow::Context;
43
use std::fs::File;
@@ -7,6 +6,8 @@ use std::path::Path;
76
use std::process::{Command, Stdio};
87
use std::{fs, io};
98

9+
use super::check_installed;
10+
1011
/// Annotate and demangle the output of Cachegrind using the `cg_annotate` tool.
1112
pub fn cachegrind_annotate(
1213
input: &Path,
@@ -70,6 +71,7 @@ pub fn cachegrind_annotate(
7071

7172
/// Creates a diff between two `cgout` files, and annotates the diff.
7273
pub fn cachegrind_diff(cgout_a: &Path, cgout_b: &Path, output: &Path) -> anyhow::Result<()> {
74+
check_installed("valgrind")?;
7375
let cgout_diff = tempfile::NamedTempFile::new()?.into_temp_path();
7476

7577
run_cg_diff(cgout_a, cgout_b, &cgout_diff).context("Cannot run cg_diff")?;
@@ -80,9 +82,7 @@ pub fn cachegrind_diff(cgout_a: &Path, cgout_b: &Path, output: &Path) -> anyhow:
8082

8183
/// Compares two Cachegrind output files using `cg_diff` and writes the result to `path`.
8284
fn run_cg_diff(cgout1: &Path, cgout2: &Path, path: &Path) -> anyhow::Result<()> {
83-
if !is_installed("cg_diff") {
84-
anyhow::bail!("`cg_diff` not installed.");
85-
}
85+
check_installed("cg_diff")?;
8686
let status = Command::new("cg_diff")
8787
.arg(r"--mod-filename=s/\/rustc\/[^\/]*\///")
8888
.arg("--mod-funcname=s/[.]llvm[.].*//")
@@ -100,6 +100,7 @@ fn run_cg_diff(cgout1: &Path, cgout2: &Path, path: &Path) -> anyhow::Result<()>
100100

101101
/// Postprocess Cachegrind output file and writes the result to `path`.
102102
fn annotate_diff(cgout: &Path, path: &Path) -> anyhow::Result<()> {
103+
check_installed("cg_annotate")?;
103104
let status = Command::new("cg_annotate")
104105
.arg("--show-percs=no")
105106
.arg(cgout)

collector/src/utils/diff.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use std::{
2+
fs::File,
3+
path::Path,
4+
process::{Command, Stdio},
5+
};
6+
7+
use anyhow::Context as _;
8+
9+
use super::check_installed;
10+
11+
/// Compares two text files using `diff` and writes the result to `path`.
12+
pub fn run_diff(left: &Path, right: &Path, out_file: &Path) -> anyhow::Result<()> {
13+
check_installed("diff")?;
14+
Command::new("diff")
15+
.arg(left)
16+
.arg(right)
17+
.stderr(Stdio::inherit())
18+
.stdout(File::create(out_file)?)
19+
.status()
20+
.context("failed to run `diff`")?;
21+
22+
Ok(())
23+
}

collector/src/utils/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::future::Future;
22
use std::process::{Command, Stdio};
33

44
pub mod cachegrind;
5+
pub mod diff;
56
pub mod fs;
67
pub mod git;
78
pub mod mangling;
@@ -23,3 +24,11 @@ pub fn is_installed(name: &str) -> bool {
2324
.status()
2425
.is_ok()
2526
}
27+
28+
/// Checks if the given binary can be executed and bails otherwise.
29+
pub fn check_installed(name: &str) -> anyhow::Result<()> {
30+
if !is_installed(name) {
31+
anyhow::bail!("`{}` is not installed but must be", name);
32+
}
33+
Ok(())
34+
}

0 commit comments

Comments
 (0)