Skip to content

Commit 8e840f7

Browse files
committed
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 will be already built in Stage 1, so my previous PR should be addressed for this change
1 parent d2baa49 commit 8e840f7

File tree

4 files changed

+87
-56
lines changed

4 files changed

+87
-56
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: 71 additions & 51 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,68 +263,79 @@ 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
285298
// We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles.
286299
// Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
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.
302+
let libdir = env.build_artifacts().join("stage2").join("lib");
289303
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")?;
304+
let llvm_profile = if env.build_llvm() {
305+
stage.section("Build PGO optimized LLVM", |stage| {
306+
Bootstrap::build(env)
307+
.with_llvm_bolt_ldflags()
308+
.llvm_pgo_optimize(llvm_pgo_profile.as_ref())
309+
.avoid_rustc_rebuild()
310+
.run(stage)
311+
})?;
312+
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+
};
320339

321340
let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
322341

@@ -334,15 +353,16 @@ fn execute_pipeline(
334353
bolt_optimize(&rustc_lib, &rustc_profile, env)
335354
.context("Could not optimize rustc with BOLT")?;
336355

337-
// LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
338-
Ok(vec![llvm_profile, rustc_profile])
356+
// LLVM is not being cleared here. Either we built it and we want to use the BOLT-optimized LLVM, or we
357+
// didn't build it, so we don't want to remove it.
358+
Ok(vec![llvm_profile, Some(rustc_profile)])
339359
})?
340360
} else {
341361
vec![]
342362
};
343363

344364
let mut dist = Bootstrap::dist(env, &dist_args)
345-
.llvm_pgo_optimize(&llvm_pgo_profile)
365+
.llvm_pgo_optimize(llvm_pgo_profile.as_ref())
346366
.rustc_pgo_optimize(&rustc_pgo_profile)
347367
.avoid_rustc_rebuild();
348368

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)