Skip to content

Commit 14ed9fa

Browse files
committed
Avoid one rustc rebuild in the optimized build pipeline
1 parent b3dd578 commit 14ed9fa

File tree

2 files changed

+93
-55
lines changed

2 files changed

+93
-55
lines changed

src/bootstrap/compile.rs

+4
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ impl Step for Std {
118118
|| builder.config.keep_stage_std.contains(&compiler.stage)
119119
{
120120
builder.info("Warning: Using a potentially old libstd. This may not behave well.");
121+
122+
copy_third_party_objects(builder, &compiler, target);
123+
copy_self_contained_objects(builder, &compiler, target);
124+
121125
builder.ensure(StdLink::from_std(self, compiler));
122126
return;
123127
}

src/ci/stage-build.py

+89-55
Original file line numberDiff line numberDiff line change
@@ -620,20 +620,25 @@ def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None)
620620
yield path
621621

622622

623-
def build_rustc(
623+
def bootstrap_build(
624624
pipeline: Pipeline,
625625
args: List[str],
626-
env: Optional[Dict[str, str]] = None
626+
env: Optional[Dict[str, str]] = None,
627+
targets: Iterable[str] = ("library/std", )
627628
):
629+
if env is None:
630+
env = {}
631+
else:
632+
env = dict(env)
633+
env["RUST_BACKTRACE"] = "1"
628634
arguments = [
629635
sys.executable,
630636
pipeline.checkout_path() / "x.py",
631637
"build",
632638
"--target", PGO_HOST,
633639
"--host", PGO_HOST,
634640
"--stage", "2",
635-
"library/std"
636-
] + args
641+
] + list(targets) + args
637642
cmd(arguments, env=env)
638643

639644

@@ -776,18 +781,18 @@ def record_metrics(pipeline: Pipeline, timer: Timer):
776781
if metrics is None:
777782
return
778783
llvm_steps = tuple(metrics.find_all_by_type("bootstrap::llvm::Llvm"))
779-
assert len(llvm_steps) > 0
780784
llvm_duration = sum(step.duration for step in llvm_steps)
781785

782786
rustc_steps = tuple(metrics.find_all_by_type("bootstrap::compile::Rustc"))
783-
assert len(rustc_steps) > 0
784787
rustc_duration = sum(step.duration for step in rustc_steps)
785788

786789
# The LLVM step is part of the Rustc step
787-
rustc_duration -= llvm_duration
790+
rustc_duration = max(0, rustc_duration - llvm_duration)
788791

789-
timer.add_duration("LLVM", llvm_duration)
790-
timer.add_duration("Rustc", rustc_duration)
792+
if llvm_duration > 0:
793+
timer.add_duration("LLVM", llvm_duration)
794+
if rustc_duration > 0:
795+
timer.add_duration("Rustc", rustc_duration)
791796

792797
log_metrics(metrics)
793798

@@ -872,79 +877,108 @@ def extract_dist_dir(name: str) -> Path:
872877
))
873878

874879

875-
def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRunner, final_build_args: List[str]):
880+
def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRunner, dist_build_args: List[str]):
876881
# Clear and prepare tmp directory
877882
shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True)
878883
os.makedirs(pipeline.opt_artifacts(), exist_ok=True)
879884

880885
pipeline.build_rustc_perf()
881886

882-
# Stage 1: Build rustc + PGO instrumented LLVM
883-
with timer.section("Stage 1 (LLVM PGO)") as stage1:
884-
with stage1.section("Build rustc and LLVM") as rustc_build:
885-
build_rustc(pipeline, args=[
886-
"--llvm-profile-generate"
887-
], env=dict(
888-
LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
889-
))
890-
record_metrics(pipeline, rustc_build)
887+
"""
888+
Stage 1: Build PGO instrumented rustc
889+
890+
We use a normal build of LLVM, because gathering PGO profiles for LLVM and `rustc` at the same time
891+
can cause issues.
892+
"""
893+
with timer.section("Stage 1 (rustc PGO)") as stage1:
894+
with stage1.section("Build PGO instrumented rustc and LLVM") as rustc_pgo_instrument:
895+
bootstrap_build(pipeline, args=[
896+
"--rust-profile-generate",
897+
pipeline.rustc_profile_dir_root()
898+
])
899+
record_metrics(pipeline, rustc_pgo_instrument)
891900

892901
with stage1.section("Gather profiles"):
893-
gather_llvm_profiles(pipeline, runner)
902+
gather_rustc_profiles(pipeline, runner)
894903
print_free_disk_space(pipeline)
895904

896-
clear_llvm_files(pipeline)
897-
final_build_args += [
898-
"--llvm-profile-use",
899-
pipeline.llvm_profile_merged_file()
900-
]
901-
902-
# Stage 2: Build PGO instrumented rustc + LLVM
903-
with timer.section("Stage 2 (rustc PGO)") as stage2:
904-
with stage2.section("Build rustc and LLVM") as rustc_build:
905-
build_rustc(pipeline, args=[
906-
"--rust-profile-generate",
907-
pipeline.rustc_profile_dir_root()
905+
with stage1.section("Build PGO optimized rustc") as rustc_pgo_use:
906+
bootstrap_build(pipeline, args=[
907+
"--rust-profile-use",
908+
pipeline.rustc_profile_merged_file()
908909
])
909-
record_metrics(pipeline, rustc_build)
910+
record_metrics(pipeline, rustc_pgo_use)
911+
dist_build_args += [
912+
"--rust-profile-use",
913+
pipeline.rustc_profile_merged_file()
914+
]
915+
916+
"""
917+
Stage 2: Gather LLVM PGO profiles
918+
"""
919+
with timer.section("Stage 2 (LLVM PGO)") as stage2:
920+
# Clear normal LLVM artifacts
921+
clear_llvm_files(pipeline)
922+
923+
with stage2.section("Build PGO instrumented LLVM") as llvm_pgo_instrument:
924+
bootstrap_build(pipeline, args=[
925+
"--llvm-profile-generate",
926+
# We want to keep the already built PGO-optimized `rustc`.
927+
"--keep-stage", "0",
928+
"--keep-stage", "1"
929+
], env=dict(
930+
LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p")
931+
))
932+
record_metrics(pipeline, llvm_pgo_instrument)
910933

911934
with stage2.section("Gather profiles"):
912-
gather_rustc_profiles(pipeline, runner)
935+
gather_llvm_profiles(pipeline, runner)
936+
937+
dist_build_args += [
938+
"--llvm-profile-use",
939+
pipeline.llvm_profile_merged_file(),
940+
]
913941
print_free_disk_space(pipeline)
914942

915-
clear_llvm_files(pipeline)
916-
final_build_args += [
917-
"--rust-profile-use",
918-
pipeline.rustc_profile_merged_file()
919-
]
943+
# Clear PGO-instrumented LLVM artifacts
944+
clear_llvm_files(pipeline)
945+
946+
"""
947+
Stage 3: Build BOLT instrumented LLVM
920948
921-
# Stage 3: Build rustc + BOLT instrumented LLVM
949+
We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles.
950+
Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
951+
BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc,
952+
therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused.
953+
"""
922954
if pipeline.supports_bolt():
923955
with timer.section("Stage 3 (LLVM BOLT)") as stage3:
924-
with stage3.section("Build rustc and LLVM") as rustc_build:
925-
build_rustc(pipeline, args=[
956+
with stage3.section("Build BOLT instrumented LLVM") as llvm_bolt_instrument:
957+
bootstrap_build(pipeline, args=[
926958
"--llvm-profile-use",
927959
pipeline.llvm_profile_merged_file(),
928960
"--llvm-bolt-profile-generate",
929-
"--rust-profile-use",
930-
pipeline.rustc_profile_merged_file()
961+
# We want to keep the already built PGO-optimized `rustc`.
962+
"--keep-stage", "0",
963+
"--keep-stage", "1"
931964
])
932-
record_metrics(pipeline, rustc_build)
965+
record_metrics(pipeline, llvm_bolt_instrument)
933966

934967
with stage3.section("Gather profiles"):
935968
gather_llvm_bolt_profiles(pipeline, runner)
936969

937-
# LLVM is not being cleared here, we want to reuse the previous build
938-
print_free_disk_space(pipeline)
939-
final_build_args += [
940-
"--llvm-bolt-profile-use",
941-
pipeline.llvm_bolt_profile_merged_file()
942-
]
970+
dist_build_args += [
971+
"--llvm-bolt-profile-use",
972+
pipeline.llvm_bolt_profile_merged_file()
973+
]
974+
print_free_disk_space(pipeline)
943975

944-
# Stage 4: Build PGO optimized rustc + PGO/BOLT optimized LLVM
945-
with timer.section("Stage 4 (final build)") as stage4:
946-
cmd(final_build_args)
947-
record_metrics(pipeline, stage4)
976+
"""
977+
Final stage: Build PGO optimized rustc + PGO/BOLT optimized LLVM
978+
"""
979+
with timer.section("Final stage (dist build)") as final_stage:
980+
cmd(dist_build_args)
981+
record_metrics(pipeline, final_stage)
948982

949983
# Try builds can be in various broken states, so we don't want to gatekeep them with tests
950984
if not is_try_build():

0 commit comments

Comments
 (0)