Skip to content

Commit 67179cf

Browse files
authored
Rollup merge of #125165 - Oneirical:pgo-branch-weights, r=jieyouxu
Migrate `run-make/pgo-branch-weights` to `rmake` Part of #121876 and the associated [Google Summer of Code project](https://blog.rust-lang.org/2024/05/01/gsoc-2024-selected-projects.html). This is a scary one and I expect things to break. Set as draft, because this isn't ready. - [x] There is this comment here, which suggests the test is excluded from the testing process due to a platform specific issue? I can't see anything here that would cause this test to not run... > // FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works // properly. Since we only have GCC on the CI ignore the test for now." EDIT: This is specific to Windows-gnu. - [x] The Makefile has this line: ``` ifneq (,$(findstring x86,$(TARGET))) COMMON_FLAGS=-Clink-args=-fuse-ld=gold ``` I honestly can't tell whether this is checking if the target IS x86, or IS NOT. EDIT: It's checking if it IS x86. - [x] I don't know why the Makefile was trying to pass an argument directly in the Makefile instead of setting that "aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc" input as a variable in the Rust program directly. I changed that, let me know if that was wrong. - [x] Trying to rewrite `cat "$(TMPDIR)/interesting.ll" | "$(LLVM_FILECHECK)" filecheck-patterns.txt` resulted in some butchery. For starters, in `tools.mk`, LLVM_FILECHECK corrects its own backslashes on Windows distributions, but there is no further mention of it, so I assume this is a preset environment variable... but is it really? Then, the command itself uses a Standard Input and a passed input file as an argument simultaneously, according to the [documentation](https://llvm.org/docs/CommandGuide/FileCheck.html#synopsis). try-job: x86_64-mingw try-job: i686-mingw
2 parents 9cdfe28 + ec1786c commit 67179cf

File tree

8 files changed

+243
-92
lines changed

8 files changed

+243
-92
lines changed

src/tools/run-make-support/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
pub mod cc;
77
pub mod clang;
88
pub mod diff;
9-
pub mod llvm_readobj;
9+
pub mod llvm;
1010
pub mod run;
1111
pub mod rustc;
1212
pub mod rustdoc;
@@ -23,8 +23,8 @@ pub use wasmparser;
2323
pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
2424
pub use clang::{clang, Clang};
2525
pub use diff::{diff, Diff};
26-
pub use llvm_readobj::{llvm_readobj, LlvmReadobj};
27-
pub use run::{run, run_fail};
26+
pub use llvm::{llvm_profdata, llvm_readobj, llvm_filecheck, LlvmProfdata, LlvmReadobj, LlvmFilecheck};
27+
pub use run::{run, run_fail, run_with_args};
2828
pub use rustc::{aux_build, rustc, Rustc};
2929
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
3030

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
use std::env;
2+
use std::path::{Path, PathBuf};
3+
use std::process::{Command, Output};
4+
use std::io::{BufReader, Read, Write};
5+
use std::fs::File;
6+
7+
use crate::handle_failed_output;
8+
9+
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
10+
/// at `$LLVM_BIN_DIR/llvm-readobj`.
11+
pub fn llvm_readobj() -> LlvmReadobj {
12+
LlvmReadobj::new()
13+
}
14+
15+
/// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
16+
/// at `$LLVM_BIN_DIR/llvm-profdata`.
17+
pub fn llvm_profdata() -> LlvmProfdata {
18+
LlvmProfdata::new()
19+
}
20+
21+
/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
22+
/// at `$LLVM_FILECHECK`.
23+
pub fn llvm_filecheck() -> LlvmFilecheck {
24+
LlvmFilecheck::new()
25+
}
26+
27+
/// A `llvm-readobj` invocation builder.
28+
#[derive(Debug)]
29+
pub struct LlvmReadobj {
30+
cmd: Command,
31+
}
32+
33+
/// A `llvm-profdata` invocation builder.
34+
#[derive(Debug)]
35+
pub struct LlvmProfdata {
36+
cmd: Command,
37+
}
38+
39+
/// A `llvm-filecheck` invocation builder.
40+
#[derive(Debug)]
41+
pub struct LlvmFilecheck {
42+
cmd: Command,
43+
}
44+
45+
crate::impl_common_helpers!(LlvmReadobj);
46+
47+
/// Generate the path to the bin directory of LLVM.
48+
pub fn llvm_bin_dir() -> PathBuf {
49+
let llvm_bin_dir = env::var("LLVM_BIN_DIR")
50+
.expect("`LLVM_BIN_DIR` not specified, but this is required to find `llvm-readobj`");
51+
PathBuf::from(llvm_bin_dir)
52+
}
53+
54+
impl LlvmReadobj {
55+
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
56+
/// at `$LLVM_BIN_DIR/llvm-readobj`.
57+
pub fn new() -> Self {
58+
let llvm_readobj = llvm_bin_dir().join("llvm-readobj");
59+
let cmd = Command::new(llvm_readobj);
60+
Self { cmd }
61+
}
62+
63+
/// Provide an input file.
64+
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
65+
self.cmd.arg(path.as_ref());
66+
self
67+
}
68+
69+
/// Pass `--file-header` to display file headers.
70+
pub fn file_header(&mut self) -> &mut Self {
71+
self.cmd.arg("--file-header");
72+
self
73+
}
74+
75+
/// Get the [`Output`][::std::process::Output] of the finished process.
76+
#[track_caller]
77+
pub fn command_output(&mut self) -> Output {
78+
self.cmd.output().expect("failed to get output of finished process")
79+
}
80+
}
81+
82+
impl LlvmProfdata {
83+
/// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
84+
/// at `$LLVM_BIN_DIR/llvm-profdata`.
85+
pub fn new() -> Self {
86+
let llvm_profdata = llvm_bin_dir().join("llvm-profdata");
87+
let cmd = Command::new(llvm_profdata);
88+
Self { cmd }
89+
}
90+
91+
/// Provide an input file.
92+
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
93+
self.cmd.arg("-o");
94+
self.cmd.arg(path.as_ref());
95+
self
96+
}
97+
98+
/// Specify the output file path.
99+
pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
100+
self.cmd.arg(path.as_ref());
101+
self
102+
}
103+
104+
/// Take several profile data files generated by PGO instrumentation and merge them
105+
/// together into a single indexed profile data file.
106+
pub fn merge(&mut self) -> &mut Self {
107+
self.cmd.arg("merge");
108+
self
109+
}
110+
111+
/// Get the [`Output`][::std::process::Output] of the finished process.
112+
#[track_caller]
113+
pub fn command_output(&mut self) -> Output {
114+
self.cmd.output().expect("failed to get output of finished process")
115+
}
116+
}
117+
118+
impl LlvmFilecheck {
119+
/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
120+
/// at `$LLVM_FILECHECK`.
121+
pub fn new() -> Self {
122+
let llvm_filecheck = env::var("LLVM_FILECHECK").expect("LLVM_FILECHECK env var not specified");
123+
let cmd = Command::new(llvm_filecheck);
124+
Self { cmd }
125+
}
126+
127+
/// Pipe a file into standard input containing patterns that will be matched against the .patterns(path) call.
128+
pub fn stdin<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
129+
let file = File::open(path).unwrap();
130+
let reader = BufReader::new(file);
131+
let byte_vec = read_bytes(reader).expect("failed to read bytes of standard input");
132+
let byte_slice = byte_vec.as_slice();
133+
self.cmd.stdin(std::process::Stdio::piped());
134+
let mut child = self.cmd.spawn().unwrap();
135+
let mut stdin = child.stdin.take().unwrap();
136+
stdin.write_all(byte_slice).unwrap();
137+
stdin.flush().unwrap();
138+
child.wait_with_output().unwrap();
139+
self
140+
}
141+
142+
/// Provide the patterns that need to be matched.
143+
pub fn patterns<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
144+
self.cmd.arg(path.as_ref());
145+
self
146+
}
147+
}
148+
149+
fn read_bytes<R: Read>(mut reader: R) -> Result<Vec<u8>, std::io::Error> {
150+
let mut buffer = Vec::new();
151+
reader.read_to_end(&mut buffer)?;
152+
Ok(buffer)
153+
}

src/tools/run-make-support/src/llvm_readobj.rs

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/tools/run-make-support/src/run.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ use crate::is_windows;
66

77
use super::{bin_name, handle_failed_output};
88

9-
fn run_common(name: &str) -> (Command, Output) {
9+
fn run_common(name: &str, args: Option<&[&str]>) -> (Command, Output) {
1010
let mut bin_path = PathBuf::new();
1111
bin_path.push(env::var("TMPDIR").unwrap());
1212
bin_path.push(&bin_name(name));
1313
let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
1414
let mut cmd = Command::new(bin_path);
15+
if let Some(args) = args {
16+
for arg in args {
17+
cmd.arg(arg);
18+
}
19+
}
1520
cmd.env(&ld_lib_path_envvar, {
1621
let mut paths = vec![];
1722
paths.push(PathBuf::from(env::var("TMPDIR").unwrap()));
@@ -43,7 +48,20 @@ pub fn run(name: &str) -> Output {
4348
let caller_location = std::panic::Location::caller();
4449
let caller_line_number = caller_location.line();
4550

46-
let (cmd, output) = run_common(name);
51+
let (cmd, output) = run_common(name, None);
52+
if !output.status.success() {
53+
handle_failed_output(&cmd, output, caller_line_number);
54+
}
55+
output
56+
}
57+
58+
/// Run a built binary with one or more argument(s) and make sure it succeeds.
59+
#[track_caller]
60+
pub fn run_with_args(name: &str, args: &[&str]) -> Output {
61+
let caller_location = std::panic::Location::caller();
62+
let caller_line_number = caller_location.line();
63+
64+
let (cmd, output) = run_common(name, Some(args));
4765
if !output.status.success() {
4866
handle_failed_output(&cmd, output, caller_line_number);
4967
}
@@ -56,7 +74,7 @@ pub fn run_fail(name: &str) -> Output {
5674
let caller_location = std::panic::Location::caller();
5775
let caller_line_number = caller_location.line();
5876

59-
let (cmd, output) = run_common(name);
77+
let (cmd, output) = run_common(name, None);
6078
if output.status.success() {
6179
handle_failed_output(&cmd, output, caller_line_number);
6280
}

src/tools/run-make-support/src/rustc.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,24 @@ impl Rustc {
131131
self
132132
}
133133

134+
/// Specify directory path used for profile generation
135+
pub fn profile_generate<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
136+
let mut arg = OsString::new();
137+
arg.push("-Cprofile-generate=");
138+
arg.push(path.as_ref());
139+
self.cmd.arg(&arg);
140+
self
141+
}
142+
143+
/// Specify directory path used for profile usage
144+
pub fn profile_use<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
145+
let mut arg = OsString::new();
146+
arg.push("-Cprofile-use=");
147+
arg.push(path.as_ref());
148+
self.cmd.arg(&arg);
149+
self
150+
}
151+
134152
/// Specify error format to use
135153
pub fn error_format(&mut self, format: &str) -> &mut Self {
136154
self.cmd.arg(format!("--error-format={format}"));

src/tools/tidy/src/allowed_run_make_makefiles.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ run-make/pass-linker-flags/Makefile
193193
run-make/pass-non-c-like-enum-to-c/Makefile
194194
run-make/pdb-alt-path/Makefile
195195
run-make/pdb-buildinfo-cl-cmd/Makefile
196-
run-make/pgo-branch-weights/Makefile
197196
run-make/pgo-gen-lto/Makefile
198197
run-make/pgo-gen-no-imp-symbols/Makefile
199198
run-make/pgo-gen/Makefile

tests/run-make/pgo-branch-weights/Makefile

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// This test generates an instrumented binary - a program which
2+
// will keep track of how many times it calls each function, a useful
3+
// feature for optimization. Then, an argument (aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc)
4+
// is passed into the instrumented binary, which should react with a number of function calls
5+
// fully known in advance. (For example, the letter 'a' results in calling f1())
6+
7+
// If the test passes, the expected function call count was added to the use-phase LLVM-IR.
8+
// See https://github.com/rust-lang/rust/pull/66631
9+
10+
//@ needs-profiler-support
11+
//@ ignore-cross-compile
12+
13+
// (This test has problems generating profdata on mingw. This could use further investigation.)
14+
//@ ignore-windows-gnu
15+
16+
use run_make_support::{
17+
llvm_filecheck, llvm_profdata, run_with_args, rustc, rustdoc, target, tmp_dir,
18+
};
19+
use std::fs;
20+
21+
fn main() {
22+
let path_prof_data_dir = tmp_dir().join("prof_data_dir");
23+
let path_merged_profdata = path_prof_data_dir.join("merged.profdata");
24+
rustc().input("opaque.rs").run();
25+
fs::create_dir_all(&path_prof_data_dir);
26+
rustc()
27+
.input("interesting.rs")
28+
.profile_generate(&path_prof_data_dir)
29+
.opt()
30+
.codegen_units(1)
31+
.run();
32+
rustc().input("main.rs").profile_generate(&path_prof_data_dir).opt().run();
33+
run_with_args("main", &["aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc"]);
34+
llvm_profdata()
35+
.merge()
36+
.output(&path_merged_profdata)
37+
.input(path_prof_data_dir)
38+
.command_output();
39+
rustc()
40+
.input("interesting.rs")
41+
.profile_use(path_merged_profdata)
42+
.opt()
43+
.codegen_units(1)
44+
.emit("llvm-ir")
45+
.run();
46+
let interesting_ll = tmp_dir().join("interesting.ll");
47+
llvm_filecheck().patterns("filecheck-patterns.txt").stdin(interesting_ll);
48+
}

0 commit comments

Comments
 (0)