Several improvements on lintcheck perf (desc.)

- Now lintcheck perf deletes target directory after benchmarking,
benchmarking with a cache isn't very useful or telling of any
precise outcome.

- Support for benchmarking several times without having to do
a cargo clean. Now we can benchmark a PR and master (or a single
change in the same commit) without having to move the perf.data files
into an external directory.

- Compress perf.data to allow for allowing multiple stacks and
occupy much less space
This commit is contained in:
blyxyas 2025-02-10 23:29:19 +01:00
parent e0175f8b8b
commit 0ee39a2015

View file

@ -120,14 +120,16 @@ impl Crate {
if config.perf {
cmd = Command::new("perf");
let perf_data_filename = get_perf_data_filename(&self.path);
cmd.args(&[
"record",
"-e",
"instructions", // Only count instructions
"-g", // Enable call-graph, useful for flamegraphs and produces richer reports
"--quiet", // Do not tamper with lintcheck's normal output
"--compression-level=22",
"-o",
"perf.data",
&perf_data_filename,
"--",
"cargo",
]);
@ -165,7 +167,7 @@ impl Crate {
return Vec::new();
}
if !config.fix {
if !config.fix && !config.perf {
cmd.arg("--message-format=json");
}
@ -203,6 +205,11 @@ impl Crate {
return Vec::new();
}
// We don't want to keep target directories if benchmarking
if config.perf {
let _ = fs::remove_dir_all(&shared_target_dir);
}
// get all clippy warnings and ICEs
let mut entries: Vec<ClippyCheckOutput> = Message::parse_stream(stdout.as_bytes())
.filter_map(|msg| match msg {
@ -441,6 +448,35 @@ fn lintcheck(config: LintcheckConfig) {
fs::write(&config.lintcheck_results_path, text).unwrap();
}
/// Traverse a directory looking for `perf.data.<number>` files, and adds one
/// to the most recent of those files, returning the new most recent `perf.data`
/// file name.
fn get_perf_data_filename(source_path: &Path) -> String {
if source_path.join("perf.data").exists() {
let mut max_number = 0;
fs::read_dir(source_path)
.unwrap()
.filter_map(Result::ok)
.filter(|path| {
path.file_name()
.as_os_str()
.to_string_lossy() // We don't care about data loss, as we're checking for equality
.starts_with("perf.data")
})
.for_each(|path| {
let file_name = path.file_name();
let file_name = file_name.as_os_str().to_str().unwrap().split('.').next_back().unwrap();
if let Ok(parsed_file_name) = file_name.parse::<usize>() {
if parsed_file_name >= max_number {
max_number = parsed_file_name + 1;
}
}
});
return format!("perf.data.{max_number}");
}
String::from("perf.data")
}
/// Returns the path to the Clippy project directory
#[must_use]
fn clippy_project_root() -> &'static Path {