Skip to content

Commit

Permalink
test(pgo): ensure PGO works (#14859)
Browse files Browse the repository at this point in the history
### What does this PR try to resolve?

This is a regression test to prevent issues like #7416.

The test only run on Linux,
as other platforms have different requirements for PGO,
or emit different PGO function missing warnings.

### How should we test and review this PR?

Not sure how brittle it is. We can optionally run it only on Cargo's CI?

cc #14830
  • Loading branch information
epage authored Nov 26, 2024
2 parents 7aa570a + 02e25d5 commit 917e646
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/testsuite/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ mod package_features;
mod patch;
mod path;
mod paths;
mod pgo;
mod pkgid;
mod precise_pre_release;
mod proc_macro;
Expand Down
111 changes: 111 additions & 0 deletions tests/testsuite/pgo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//! Test if PGO works.

use std::path::PathBuf;
use std::process::Command;

use cargo_test_support::prelude::*;
use cargo_test_support::project;
use cargo_test_support::str;

fn llvm_profdata() -> Option<PathBuf> {
let output = Command::new("rustc")
.arg("--print=target-libdir")
.output()
.expect("rustc to run");
assert!(output.status.success());
let mut libdir = PathBuf::from(String::from_utf8(output.stdout).unwrap());
assert!(libdir.pop());
let mut bin = libdir.join("bin").join("llvm-profdata");
bin.exists().then(|| bin.clone()).or_else(|| {
bin.set_extension("exe");
bin.exists().then_some(bin)
})
}

#[cargo_test]
fn pgo_works() {
if cfg!(not(target_os = "linux")) {
// macOS may emit different LLVM PGO warnings.
// Windows LLVM has different requirements.
return;
}

let Some(llvm_profdata) = llvm_profdata() else {
return;
};

let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
edition = "2021"
"#,
)
.file(
"src/main.rs",
r#"
fn fibonacci(n: u64) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn main() {
for i in [15, 20, 25] {
let _ = fibonacci(i);
}
}
"#,
)
.build();

let target_dir = p.build_dir();
let release_bin = target_dir.join("release").join("foo");
let pgo_data_dir = target_dir.join("pgo-data");
let profdata_path = target_dir.join("merged.profdata");

// Build the instrumented binary
p.cargo("build --release")
.env(
"RUSTFLAGS",
format!("-Cprofile-generate={}", pgo_data_dir.display()),
)
.run();
// Run the instrumented binary
cargo_test_support::execs()
.with_process_builder(cargo_test_support::process(release_bin))
.run();

cargo_test_support::process(llvm_profdata)
.arg("merge")
.arg("-o")
.arg(&profdata_path)
.arg(pgo_data_dir)
.status()
.unwrap();

// Use merged profdata during optimization.
//
// -Cllvm-args=-pgo-warn-missing-function is essential.
// If there are LLVM warnings, there might be something wrong.
p.cargo("build --release -v")
.env(
"RUSTFLAGS",
format!(
"-Cprofile-use={} -Cllvm-args=-pgo-warn-missing-function",
profdata_path.display()
),
)
.with_stderr_data(str![[r#"
[DIRTY] foo v0.0.0 ([ROOT]/foo): the rustflags changed
[COMPILING] foo v0.0.0 ([ROOT]/foo)
[RUNNING] `rustc [..]-Cprofile-use=[ROOT]/foo/target/merged.profdata -Cllvm-args=-pgo-warn-missing-function`
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
"#]])
.run();
}

0 comments on commit 917e646

Please sign in to comment.