@@ -620,20 +620,25 @@ def get_files(directory: Path, filter: Optional[Callable[[Path], bool]] = None)
620
620
yield path
621
621
622
622
623
- def build_rustc (
623
+ def bootstrap_build (
624
624
pipeline : Pipeline ,
625
625
args : List [str ],
626
- env : Optional [Dict [str , str ]] = None
626
+ env : Optional [Dict [str , str ]] = None ,
627
+ targets : Iterable [str ] = ("library/std" , )
627
628
):
629
+ if env is None :
630
+ env = {}
631
+ else :
632
+ env = dict (env )
633
+ env ["RUST_BACKTRACE" ] = "1"
628
634
arguments = [
629
635
sys .executable ,
630
636
pipeline .checkout_path () / "x.py" ,
631
637
"build" ,
632
638
"--target" , PGO_HOST ,
633
639
"--host" , PGO_HOST ,
634
640
"--stage" , "2" ,
635
- "library/std"
636
- ] + args
641
+ ] + list (targets ) + args
637
642
cmd (arguments , env = env )
638
643
639
644
@@ -776,18 +781,18 @@ def record_metrics(pipeline: Pipeline, timer: Timer):
776
781
if metrics is None :
777
782
return
778
783
llvm_steps = tuple (metrics .find_all_by_type ("bootstrap::llvm::Llvm" ))
779
- assert len (llvm_steps ) > 0
780
784
llvm_duration = sum (step .duration for step in llvm_steps )
781
785
782
786
rustc_steps = tuple (metrics .find_all_by_type ("bootstrap::compile::Rustc" ))
783
- assert len (rustc_steps ) > 0
784
787
rustc_duration = sum (step .duration for step in rustc_steps )
785
788
786
789
# The LLVM step is part of the Rustc step
787
- rustc_duration -= llvm_duration
790
+ rustc_duration = max ( 0 , rustc_duration - llvm_duration )
788
791
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 )
791
796
792
797
log_metrics (metrics )
793
798
@@ -872,79 +877,114 @@ def extract_dist_dir(name: str) -> Path:
872
877
))
873
878
874
879
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 ]):
876
881
# Clear and prepare tmp directory
877
882
shutil .rmtree (pipeline .opt_artifacts (), ignore_errors = True )
878
883
os .makedirs (pipeline .opt_artifacts (), exist_ok = True )
879
884
880
885
pipeline .build_rustc_perf ()
881
886
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 )
891
900
892
901
with stage1 .section ("Gather profiles" ):
893
- gather_llvm_profiles (pipeline , runner )
902
+ gather_rustc_profiles (pipeline , runner )
894
903
print_free_disk_space (pipeline )
895
904
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 ()
908
909
])
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 )
910
933
911
934
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
+ ]
913
941
print_free_disk_space (pipeline )
914
942
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 )
920
945
921
- # Stage 3: Build rustc + BOLT instrumented LLVM
946
+ """
947
+ Stage 3: Build BOLT instrumented LLVM
948
+
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
+ """
922
954
if pipeline .supports_bolt ():
923
955
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 = [
926
958
"--llvm-profile-use" ,
927
959
pipeline .llvm_profile_merged_file (),
928
960
"--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"
931
964
])
932
- record_metrics (pipeline , rustc_build )
965
+ record_metrics (pipeline , llvm_bolt_instrument )
933
966
934
967
with stage3 .section ("Gather profiles" ):
935
968
gather_llvm_bolt_profiles (pipeline , runner )
936
969
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 )
943
975
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
+ # We want to keep the already built PGO-optimized `rustc`.
977
+ dist_build_args += [
978
+ "--keep-stage" , "0" ,
979
+ "--keep-stage" , "1"
980
+ ]
981
+
982
+ """
983
+ Final stage: Build PGO optimized rustc + PGO/BOLT optimized LLVM
984
+ """
985
+ with timer .section ("Final stage (dist build)" ) as final_stage :
986
+ cmd (dist_build_args )
987
+ record_metrics (pipeline , final_stage )
948
988
949
989
# Try builds can be in various broken states, so we don't want to gatekeep them with tests
950
990
if not is_try_build ():
0 commit comments