Skip to content

Commit d08b352

Browse files
Auto merge of #143928 - ognevny:opt-dist-build-llvm, r=<try>
opt-dist: make llvm builds optional adds command line option for disabling llvm builds. it's useful in case of user having their own optimized LLVM, so they won't waste time for (at least) 3 LLVM builds. in this case PGO optimized rustc will be already built in Stage 1, so #143898 should be addressed for this change couldn't test locally on Linux laptop due to small SSD storage, will try now with windows-msvc host <!-- homu-ignore:start --> <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r? <reviewer name> --> <!-- homu-ignore:end --> r? `@Kobzol` try-job: dist-x86_64-linux try-job: dist-x86_64-msvc
2 parents 1aa5b22 + d9c2a27 commit d08b352

File tree

4 files changed

+91
-57
lines changed

4 files changed

+91
-57
lines changed

src/tools/opt-dist/src/environment.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct Environment {
2727
shared_llvm: bool,
2828
run_tests: bool,
2929
fast_try_build: bool,
30+
build_llvm: bool,
3031
}
3132

3233
impl Environment {
@@ -111,6 +112,10 @@ impl Environment {
111112
pub fn is_fast_try_build(&self) -> bool {
112113
self.fast_try_build
113114
}
115+
116+
pub fn build_llvm(&self) -> bool {
117+
self.build_llvm
118+
}
114119
}
115120

116121
/// What is the extension of binary executables on this platform?

src/tools/opt-dist/src/exec.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,10 @@ impl Bootstrap {
139139
self
140140
}
141141

142-
pub fn llvm_pgo_optimize(mut self, profile: &LlvmPGOProfile) -> Self {
143-
self.cmd = self.cmd.arg("--llvm-profile-use").arg(profile.0.as_str());
142+
pub fn llvm_pgo_optimize(mut self, profile: Option<&LlvmPGOProfile>) -> Self {
143+
if let Some(prof) = profile {
144+
self.cmd = self.cmd.arg("--llvm-profile-use").arg(prof.0.as_str());
145+
}
144146
self
145147
}
146148

@@ -174,8 +176,10 @@ impl Bootstrap {
174176
self
175177
}
176178

177-
pub fn with_bolt_profile(mut self, profile: BoltProfile) -> Self {
178-
self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str());
179+
pub fn with_bolt_profile(mut self, profile: Option<BoltProfile>) -> Self {
180+
if let Some(prof) = profile {
181+
self.cmd = self.cmd.arg("--reproducible-artifact").arg(prof.0.as_str());
182+
}
179183
self
180184
}
181185

src/tools/opt-dist/src/main.rs

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ enum EnvironmentCmd {
9898
/// Perform tests after final build if it's not a fast try build
9999
#[arg(long)]
100100
run_tests: bool,
101+
102+
/// Will be LLVM built during the run?
103+
#[arg(long, default_value_t = true, action(clap::ArgAction::Set))]
104+
build_llvm: bool,
101105
},
102106
/// Perform an optimized build on Linux CI, from inside Docker.
103107
LinuxCi {
@@ -133,6 +137,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
133137
benchmark_cargo_config,
134138
shared,
135139
run_tests,
140+
build_llvm,
136141
} => {
137142
let env = EnvironmentBuilder::default()
138143
.host_tuple(target_triple)
@@ -148,6 +153,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
148153
.benchmark_cargo_config(benchmark_cargo_config)
149154
.run_tests(run_tests)
150155
.fast_try_build(is_fast_try_build)
156+
.build_llvm(build_llvm)
151157
.build()?;
152158

153159
(env, shared.build_args)
@@ -172,6 +178,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
172178
.skipped_tests(vec![])
173179
.run_tests(true)
174180
.fast_try_build(is_fast_try_build)
181+
.build_llvm(true)
175182
.build()?;
176183

177184
(env, shared.build_args)
@@ -193,6 +200,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
193200
.skipped_tests(vec![])
194201
.run_tests(true)
195202
.fast_try_build(is_fast_try_build)
203+
.build_llvm(true)
196204
.build()?;
197205

198206
(env, shared.build_args)
@@ -255,30 +263,35 @@ fn execute_pipeline(
255263
// Stage 2: Gather LLVM PGO profiles
256264
// Here we build a PGO instrumented LLVM, reusing the previously PGO optimized rustc.
257265
// Then we use the instrumented LLVM to gather LLVM PGO profiles.
258-
let llvm_pgo_profile = timer.section("Stage 2 (LLVM PGO)", |stage| {
259-
// Remove the previous, uninstrumented build of LLVM.
260-
clear_llvm_files(env)?;
266+
let llvm_pgo_profile = if env.build_llvm() {
267+
timer.section("Stage 2 (LLVM PGO)", |stage| {
268+
// Remove the previous, uninstrumented build of LLVM.
269+
clear_llvm_files(env)?;
261270

262-
let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo");
271+
let llvm_profile_dir_root = env.artifact_dir().join("llvm-pgo");
263272

264-
stage.section("Build PGO instrumented LLVM", |section| {
265-
Bootstrap::build(env)
266-
.llvm_pgo_instrument(&llvm_profile_dir_root)
267-
.avoid_rustc_rebuild()
268-
.run(section)
269-
})?;
273+
stage.section("Build PGO instrumented LLVM", |section| {
274+
Bootstrap::build(env)
275+
.llvm_pgo_instrument(&llvm_profile_dir_root)
276+
.avoid_rustc_rebuild()
277+
.run(section)
278+
})?;
270279

271-
let profile = stage
272-
.section("Gather profiles", |_| gather_llvm_profiles(env, &llvm_profile_dir_root))?;
280+
let profile = stage.section("Gather profiles", |_| {
281+
gather_llvm_profiles(env, &llvm_profile_dir_root)
282+
})?;
273283

274-
print_free_disk_space()?;
284+
print_free_disk_space()?;
275285

276-
// Proactively delete the instrumented artifacts, to avoid using them by accident in
277-
// follow-up stages.
278-
clear_llvm_files(env)?;
286+
// Proactively delete the instrumented artifacts, to avoid using them by accident in
287+
// follow-up stages.
288+
clear_llvm_files(env)?;
279289

280-
Ok(profile)
281-
})?;
290+
Ok(Some(profile))
291+
})?
292+
} else {
293+
None
294+
};
282295

283296
let bolt_profiles = if env.use_bolt() {
284297
// Stage 3: Build BOLT instrumented LLVM
@@ -287,38 +300,48 @@ fn execute_pipeline(
287300
// BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc,
288301
// therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused.
289302
timer.section("Stage 3 (BOLT)", |stage| {
290-
stage.section("Build PGO optimized LLVM", |stage| {
291-
Bootstrap::build(env)
292-
.with_llvm_bolt_ldflags()
293-
.llvm_pgo_optimize(&llvm_pgo_profile)
294-
.avoid_rustc_rebuild()
295-
.run(stage)
296-
})?;
297-
298-
let libdir = env.build_artifacts().join("stage2").join("lib");
299-
// The actual name will be something like libLLVM.so.18.1-rust-dev.
300-
let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?;
301-
302-
log::info!("Optimizing {llvm_lib} with BOLT");
303-
304-
// FIXME(kobzol): try gather profiles together, at once for LLVM and rustc
305-
// Instrument the libraries and gather profiles
306-
let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| {
307-
stage.section("Gather profiles", |_| {
308-
gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir)
309-
})
310-
})?;
311-
print_free_disk_space()?;
312-
313-
// Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked
314-
// from several places, and this specific path (`llvm_lib`) will *not* be packaged into
315-
// the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
316-
// therefore it will actually optimize all the hard links, which means that the final
317-
// packaged `libLLVM.so` file *will* be BOLT optimized.
318-
bolt_optimize(&llvm_lib, &llvm_profile, env)
319-
.context("Could not optimize LLVM with BOLT")?;
320-
321-
let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
303+
let llvm_profile = if env.build_llvm() {
304+
stage.section("Build PGO optimized LLVM", |stage| {
305+
Bootstrap::build(env)
306+
.with_llvm_bolt_ldflags()
307+
.llvm_pgo_optimize(llvm_pgo_profile.as_ref())
308+
.avoid_rustc_rebuild()
309+
.run(stage)
310+
})?;
311+
312+
let libdir = env.build_artifacts().join("stage2").join("lib");
313+
// The actual name will be something like libLLVM.so.18.1-rust-dev.
314+
let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?;
315+
316+
log::info!("Optimizing {llvm_lib} with BOLT");
317+
318+
// FIXME(kobzol): try gather profiles together, at once for LLVM and rustc
319+
// Instrument the libraries and gather profiles
320+
let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| {
321+
stage.section("Gather profiles", |_| {
322+
gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir)
323+
})
324+
})?;
325+
print_free_disk_space()?;
326+
327+
// Now optimize the library with BOLT. The `libLLVM-XXX.so` library is actually hard-linked
328+
// from several places, and this specific path (`llvm_lib`) will *not* be packaged into
329+
// the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
330+
// therefore it will actually optimize all the hard links, which means that the final
331+
// packaged `libLLVM.so` file *will* be BOLT optimized.
332+
bolt_optimize(&llvm_lib, &llvm_profile, env)
333+
.context("Could not optimize LLVM with BOLT")?;
334+
335+
Some(llvm_profile)
336+
} else {
337+
None
338+
};
339+
340+
let rustc_lib = io::find_file_in_dir(
341+
&env.build_artifacts().join("stage2").join("lib"),
342+
"librustc_driver",
343+
".so",
344+
)?;
322345

323346
log::info!("Optimizing {rustc_lib} with BOLT");
324347

@@ -335,14 +358,14 @@ fn execute_pipeline(
335358
.context("Could not optimize rustc with BOLT")?;
336359

337360
// LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
338-
Ok(vec![llvm_profile, rustc_profile])
361+
Ok(vec![llvm_profile, Some(rustc_profile)])
339362
})?
340363
} else {
341364
vec![]
342365
};
343366

344367
let mut dist = Bootstrap::dist(env, &dist_args)
345-
.llvm_pgo_optimize(&llvm_pgo_profile)
368+
.llvm_pgo_optimize(llvm_pgo_profile.as_ref())
346369
.rustc_pgo_optimize(&rustc_pgo_profile)
347370
.avoid_rustc_rebuild();
348371

src/tools/opt-dist/src/training.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ pub fn gather_rustc_profiles(
163163
let merged_profile = env.artifact_dir().join("rustc-pgo.profdata");
164164
log::info!("Merging Rustc PGO profiles to {merged_profile}");
165165

166-
merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?;
166+
let llvm_profdata = if env.build_llvm() { LlvmProfdata::Target } else { LlvmProfdata::Host };
167+
168+
merge_llvm_profiles(env, &merged_profile, profile_root, llvm_profdata)?;
167169
log_profile_stats("Rustc", &merged_profile, profile_root)?;
168170

169171
// We don't need the individual .profraw files now that they have been merged

0 commit comments

Comments
 (0)