Skip to content

Commit b16264a

Browse files
committed
rewrite pgo-branch-weights (1/2)
1 parent 3ea5e23 commit b16264a

File tree

7 files changed

+234
-42
lines changed

7 files changed

+234
-42
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod command;
99
pub mod diff;
1010
mod drop_bomb;
1111
pub mod fs_wrapper;
12-
pub mod llvm_readobj;
12+
pub mod llvm;
1313
pub mod run;
1414
pub mod rustc;
1515
pub mod rustdoc;
@@ -29,8 +29,8 @@ pub use wasmparser;
2929
pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
3030
pub use clang::{clang, Clang};
3131
pub use diff::{diff, Diff};
32-
pub use llvm_readobj::{llvm_readobj, LlvmReadobj};
33-
pub use run::{cmd, run, run_fail};
32+
pub use llvm::{llvm_profdata, llvm_readobj, llvm_filecheck, LlvmProfdata, LlvmReadobj, LlvmFilecheck};
33+
pub use run::{cmd, run, run_fail, run_with_args};
3434
pub use rustc::{aux_build, rustc, Rustc};
3535
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
3636

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

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@ use crate::{cwd, env_var, is_windows, set_host_rpath};
99
use super::handle_failed_output;
1010

1111
#[track_caller]
12-
fn run_common(name: &str) -> Command {
12+
fn run_common(name: &str, args: Option<&[&str]>) -> Command {
1313
let mut bin_path = PathBuf::new();
1414
bin_path.push(cwd());
1515
bin_path.push(name);
1616
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
1717
let mut cmd = Command::new(bin_path);
18+
if let Some(args) = args {
19+
for arg in args {
20+
cmd.arg(arg);
21+
}
22+
}
1823
cmd.env(&ld_lib_path_envvar, {
1924
let mut paths = vec![];
2025
paths.push(cwd());
@@ -43,7 +48,19 @@ fn run_common(name: &str) -> Command {
4348
#[track_caller]
4449
pub fn run(name: &str) -> CompletedProcess {
4550
let caller = panic::Location::caller();
46-
let mut cmd = run_common(name);
51+
let mut cmd = run_common(name, None);
52+
let output = cmd.run();
53+
if !output.status().success() {
54+
handle_failed_output(&cmd, output, caller.line());
55+
}
56+
output
57+
}
58+
59+
/// Run a built binary with one or more argument(s) and make sure it succeeds.
60+
#[track_caller]
61+
pub fn run_with_args(name: &str, args: &[&str]) -> CompletedProcess {
62+
let caller = std::panic::Location::caller();
63+
let mut cmd = run_common(name, Some(args));
4764
let output = cmd.run();
4865
if !output.status().success() {
4966
handle_failed_output(&cmd, output, caller.line());
@@ -55,7 +72,7 @@ pub fn run(name: &str) -> CompletedProcess {
5572
#[track_caller]
5673
pub fn run_fail(name: &str) -> CompletedProcess {
5774
let caller = panic::Location::caller();
58-
let mut cmd = run_common(name);
75+
let mut cmd = run_common(name, None);
5976
let output = cmd.run_fail();
6077
if output.status().success() {
6178
handle_failed_output(&cmd, output, caller.line());

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,24 @@ impl Rustc {
146146
self
147147
}
148148

149+
/// Specify directory path used for profile generation
150+
pub fn profile_generate<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
151+
let mut arg = OsString::new();
152+
arg.push("-Cprofile-generate=");
153+
arg.push(path.as_ref());
154+
self.cmd.arg(&arg);
155+
self
156+
}
157+
158+
/// Specify directory path used for profile usage
159+
pub fn profile_use<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
160+
let mut arg = OsString::new();
161+
arg.push("-Cprofile-use=");
162+
arg.push(path.as_ref());
163+
self.cmd.arg(&arg);
164+
self
165+
}
166+
149167
/// Specify error format to use
150168
pub fn error_format(&mut self, format: &str) -> &mut Self {
151169
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
@@ -168,7 +168,6 @@ run-make/pass-linker-flags/Makefile
168168
run-make/pass-non-c-like-enum-to-c/Makefile
169169
run-make/pdb-alt-path/Makefile
170170
run-make/pdb-buildinfo-cl-cmd/Makefile
171-
run-make/pgo-branch-weights/Makefile
172171
run-make/pgo-gen-lto/Makefile
173172
run-make/pgo-gen-no-imp-symbols/Makefile
174173
run-make/pgo-gen/Makefile

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

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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::{llvm_filecheck, llvm_profdata, run_with_args, rustc, rustdoc, target};
17+
use std::fs;
18+
19+
fn main() {
20+
let path_prof_data_dir = Path::new("prof_data_dir");
21+
let path_merged_profdata = path_prof_data_dir.join("merged.profdata");
22+
rustc().input("opaque.rs").run();
23+
fs::create_dir_all(&path_prof_data_dir);
24+
rustc()
25+
.input("interesting.rs")
26+
.profile_generate(&path_prof_data_dir)
27+
.opt()
28+
.codegen_units(1)
29+
.run();
30+
rustc().input("main.rs").profile_generate(&path_prof_data_dir).opt().run();
31+
run_with_args("main", &["aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc"]);
32+
llvm_profdata().merge().output(&path_merged_profdata).input(path_prof_data_dir).run();
33+
rustc()
34+
.input("interesting.rs")
35+
.profile_use(path_merged_profdata)
36+
.opt()
37+
.codegen_units(1)
38+
.emit("llvm-ir")
39+
.run();
40+
llvm_filecheck().patterns("filecheck-patterns.txt").stdin("interesting_ll").run();
41+
}

0 commit comments

Comments
 (0)