@@ -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,114 @@ 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 )
920945
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+ """
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+ # 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 )
948988
949989 # Try builds can be in various broken states, so we don't want to gatekeep them with tests
950990 if not is_try_build ():
0 commit comments