Skip to content

Commit 41d7cb2

Browse files
committed
Make it easy to add diffing of output of arbitrary profilers (demonstrate for dep-graph)
1 parent 8be7e34 commit 41d7cb2

File tree

4 files changed

+134
-40
lines changed

4 files changed

+134
-40
lines changed

collector/src/bin/collector.rs

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,15 @@ 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+
fn generate_diffs(
143136
id1: &str,
144137
id2: &str,
145138
out_dir: &Path,
146139
benchmarks: &[Benchmark],
147140
profiles: &[Profile],
148141
scenarios: &[Scenario],
149142
errors: &mut BenchmarkErrors,
143+
profiler: &Profiler,
150144
) -> Vec<PathBuf> {
151145
let mut annotated_diffs = Vec::new();
152146
for benchmark in benchmarks {
@@ -166,22 +160,28 @@ fn generate_cachegrind_diffs(
166160
}) {
167161
let filename = |prefix, id| {
168162
format!(
169-
"{}-{}-{}-{:?}-{}",
170-
prefix, id, benchmark.name, profile, scenario
163+
"{}-{}-{}-{:?}-{}{}",
164+
prefix,
165+
id,
166+
benchmark.name,
167+
profile,
168+
scenario,
169+
profiler.postfix()
171170
)
172171
};
173172
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));
173+
let prefix = profiler.prefix();
174+
let left = out_dir.join(filename(prefix, id1));
175+
let right = out_dir.join(filename(prefix, id2));
176+
let output = out_dir.join(filename(profiler.output_prefix(), &id_diff));
177177

178-
if let Err(e) = cachegrind_diff(&cgout1, &cgout2, &cgann_diff) {
178+
if let Err(e) = profiler.diff(&left, &right, &output) {
179179
errors.incr();
180180
eprintln!("collector error: {:?}", e);
181181
continue;
182182
}
183183

184-
annotated_diffs.push(cgann_diff);
184+
annotated_diffs.push(output);
185185
}
186186
}
187187
}
@@ -1145,29 +1145,26 @@ fn main_result() -> anyhow::Result<i32> {
11451145
let id1 = get_toolchain_and_profile(local.rustc.as_str(), "1")?;
11461146
let id2 = get_toolchain_and_profile(rustc2.as_str(), "2")?;
11471147

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: {}", diffs[0].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-
}
1148+
profiler.diff_prereqs()?;
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!("{}-latest", profiler.output_prefix()));
1161+
std::fs::copy(diff, &short).expect("copy to short path");
1162+
eprintln!("Original diff at: {}", diffs[0].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: 65 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, check_installed};
45
use anyhow::Context;
56
use std::collections::HashMap;
67
use std::fs::File;
@@ -51,6 +52,68 @@ impl Profiler {
5152
| Profiler::DepGraph
5253
)
5354
}
55+
56+
pub fn diff_prereqs(&self) -> anyhow::Result<()> {
57+
use Profiler::*;
58+
match self {
59+
Cachegrind => {
60+
check_installed("valgrind")?;
61+
check_installed("cg_annotate")?;
62+
}
63+
64+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
65+
| Bytehound | Eprintln | LlvmLines | MonoItems | DepGraph | LlvmIr => {}
66+
}
67+
Ok(())
68+
}
69+
70+
/// A file prefix added to all files of this profiler.
71+
pub fn prefix(&self) -> &'static str {
72+
use Profiler::*;
73+
match self {
74+
Cachegrind => "cgout",
75+
DepGraph => "dep-graph",
76+
77+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
78+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => "",
79+
}
80+
}
81+
82+
/// A postfix added to the file that gets diffed.
83+
pub fn postfix(&self) -> &'static str {
84+
use Profiler::*;
85+
match self {
86+
Cachegrind => "",
87+
DepGraph => ".txt",
88+
89+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
90+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => "",
91+
}
92+
}
93+
94+
/// A file prefix to use for the diff output.
95+
pub fn output_prefix(&self) -> &'static str {
96+
use Profiler::*;
97+
match self {
98+
Cachegrind => "cgann-diff",
99+
DepGraph => "dep-graph-diff",
100+
101+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
102+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => "",
103+
}
104+
}
105+
106+
/// Actually perform the diff
107+
pub fn diff(&self, left: &Path, right: &Path, output: &Path) -> anyhow::Result<()> {
108+
use Profiler::*;
109+
match self {
110+
Cachegrind => cachegrind_diff(left, right, output),
111+
DepGraph => run_diff(left, right, output),
112+
113+
SelfProfile | PerfRecord | Oprofile | Samply | Callgrind | Dhat | DhatCopy | Massif
114+
| Bytehound | Eprintln | LlvmLines | MonoItems | LlvmIr => Ok(()),
115+
}
116+
}
54117
}
55118

56119
pub struct ProfileProcessor<'a> {

collector/src/utils/diff.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::{
2+
fs::File,
3+
path::Path,
4+
process::{Command, Stdio},
5+
};
6+
7+
use anyhow::Context as _;
8+
9+
use super::is_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+
if !is_installed("diff") {
14+
anyhow::bail!("`diff` not installed.");
15+
}
16+
Command::new("diff")
17+
.arg(left)
18+
.arg(right)
19+
.stderr(Stdio::inherit())
20+
.stdout(File::create(out_file)?)
21+
.status()
22+
.context("failed to run `diff`")?;
23+
24+
Ok(())
25+
}

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)