@@ -124,6 +124,12 @@ def llvm_bolt_profile_merged_file(self) -> Path:
124124 def metrics_path (self ) -> Path :
125125 return self .build_root () / "build" / "metrics.json"
126126
127+ def executable_extension (self ) -> str :
128+ raise NotImplementedError
129+
130+ def skipped_tests (self ) -> Iterable [str ]:
131+ return ()
132+
127133
128134class LinuxPipeline (Pipeline ):
129135 def checkout_path (self ) -> Path :
@@ -152,6 +158,13 @@ def build_rustc_perf(self):
152158 def supports_bolt (self ) -> bool :
153159 return True
154160
161+ def executable_extension (self ) -> str :
162+ return ""
163+
164+ def skipped_tests (self ) -> Iterable [str ]:
165+ # This test fails because of linker errors, as of June 2023.
166+ yield "tests/ui/process/nofile-limit.rs"
167+
155168
156169class WindowsPipeline (Pipeline ):
157170 def __init__ (self ):
@@ -211,6 +224,13 @@ def rustc_profile_template_path(self) -> Path:
211224 def supports_bolt (self ) -> bool :
212225 return False
213226
227+ def executable_extension (self ) -> str :
228+ return ".exe"
229+
230+ def skipped_tests (self ) -> Iterable [str ]:
231+ # This test fails as of June 2023
232+ yield "tests\\ codegen\\ vec-shrink-panik.rs"
233+
214234
215235def get_timestamp () -> float :
216236 return time .time ()
@@ -403,9 +423,9 @@ def delete_directory(path: Path):
403423 shutil .rmtree (path )
404424
405425
406- def unpack_archive (archive : Path ):
426+ def unpack_archive (archive : Path , target_dir : Optional [ Path ] = None ):
407427 LOGGER .info (f"Unpacking archive `{ archive } `" )
408- shutil .unpack_archive (archive )
428+ shutil .unpack_archive (str ( archive ), extract_dir = str ( target_dir ) if target_dir is not None else None )
409429
410430
411431def download_file (src : str , target : Path ):
@@ -455,6 +475,7 @@ def cmd(
455475 )
456476 return subprocess .run (args , env = environment , check = True )
457477
478+
458479class BenchmarkRunner :
459480 def run_rustc (self , pipeline : Pipeline ):
460481 raise NotImplementedError
@@ -465,6 +486,7 @@ def run_llvm(self, pipeline: Pipeline):
465486 def run_bolt (self , pipeline : Pipeline ):
466487 raise NotImplementedError
467488
489+
468490class DefaultBenchmarkRunner (BenchmarkRunner ):
469491 def run_rustc (self , pipeline : Pipeline ):
470492 # Here we're profiling the `rustc` frontend, so we also include `Check`.
@@ -478,6 +500,7 @@ def run_rustc(self, pipeline: Pipeline):
478500 LLVM_PROFILE_FILE = str (pipeline .rustc_profile_template_path ())
479501 )
480502 )
503+
481504 def run_llvm (self , pipeline : Pipeline ):
482505 run_compiler_benchmarks (
483506 pipeline ,
@@ -494,6 +517,7 @@ def run_bolt(self, pipeline: Pipeline):
494517 crates = LLVM_BOLT_CRATES
495518 )
496519
520+
497521def run_compiler_benchmarks (
498522 pipeline : Pipeline ,
499523 profiles : List [str ],
@@ -650,10 +674,8 @@ def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner):
650674def gather_rustc_profiles (pipeline : Pipeline , runner : BenchmarkRunner ):
651675 LOGGER .info ("Running benchmarks with PGO instrumented rustc" )
652676
653-
654677 runner .run_rustc (pipeline )
655678
656-
657679 profile_path = pipeline .rustc_profile_merged_file ()
658680 LOGGER .info (f"Merging Rustc PGO profiles to { profile_path } " )
659681 cmd ([
@@ -770,6 +792,86 @@ def record_metrics(pipeline: Pipeline, timer: Timer):
770792 log_metrics (metrics )
771793
772794
795+ def run_tests (pipeline : Pipeline ):
796+ """
797+ After `dist` is executed, we extract its archived components into a sysroot directory,
798+ and then use that extracted rustc as a stage0 compiler.
799+ Then we run a subset of tests using that compiler, to have a basic smoke test which checks
800+ whether the optimization pipeline hasn't broken something.
801+ """
802+ build_dir = pipeline .build_root () / "build"
803+ dist_dir = build_dir / "dist"
804+
805+ def extract_dist_dir (name : str ) -> Path :
806+ target_dir = build_dir / "optimized-dist"
807+ target_dir .mkdir (parents = True , exist_ok = True )
808+ unpack_archive (dist_dir / f"{ name } .tar.xz" , target_dir = target_dir )
809+ extracted_path = target_dir / name
810+ assert extracted_path .is_dir ()
811+ return extracted_path
812+
813+ # Extract rustc, libstd, cargo and src archives to create the optimized sysroot
814+ rustc_dir = extract_dist_dir (f"rustc-nightly-{ PGO_HOST } " ) / "rustc"
815+ libstd_dir = extract_dist_dir (f"rust-std-nightly-{ PGO_HOST } " ) / f"rust-std-{ PGO_HOST } "
816+ cargo_dir = extract_dist_dir (f"cargo-nightly-{ PGO_HOST } " ) / f"cargo"
817+ extracted_src_dir = extract_dist_dir ("rust-src-nightly" ) / "rust-src"
818+
819+ # We need to manually copy libstd to the extracted rustc sysroot
820+ shutil .copytree (
821+ libstd_dir / "lib" / "rustlib" / PGO_HOST / "lib" ,
822+ rustc_dir / "lib" / "rustlib" / PGO_HOST / "lib"
823+ )
824+
825+ # Extract sources - they aren't in the `rustc-nightly-{host}` tarball, so we need to manually copy libstd
826+ # sources to the extracted sysroot. We need sources available so that `-Zsimulate-remapped-rust-src-base`
827+ # works correctly.
828+ shutil .copytree (
829+ extracted_src_dir / "lib" / "rustlib" / "src" ,
830+ rustc_dir / "lib" / "rustlib" / "src"
831+ )
832+
833+ rustc_path = rustc_dir / "bin" / f"rustc{ pipeline .executable_extension ()} "
834+ assert rustc_path .is_file ()
835+ cargo_path = cargo_dir / "bin" / f"cargo{ pipeline .executable_extension ()} "
836+ assert cargo_path .is_file ()
837+
838+ config_content = f"""profile = "user"
839+ changelog-seen = 2
840+
841+ [build]
842+ rustc = "{ rustc_path .as_posix ()} "
843+ cargo = "{ cargo_path .as_posix ()} "
844+
845+ [llvm]
846+ download-ci-llvm = true
847+ """
848+ logging .info (f"Using following `config.toml` for running tests:\n { config_content } " )
849+
850+ # Simulate a stage 0 compiler with the extracted optimized dist artifacts.
851+ with open ("config.toml" , "w" ) as f :
852+ f .write (config_content )
853+
854+ args = [
855+ sys .executable ,
856+ pipeline .checkout_path () / "x.py" ,
857+ "test" ,
858+ "--stage" , "0" ,
859+ "tests/assembly" ,
860+ "tests/codegen" ,
861+ "tests/codegen-units" ,
862+ "tests/incremental" ,
863+ "tests/mir-opt" ,
864+ "tests/pretty" ,
865+ "tests/run-pass-valgrind" ,
866+ "tests/ui" ,
867+ ]
868+ for test_path in pipeline .skipped_tests ():
869+ args .extend (["--exclude" , test_path ])
870+ cmd (args = args , env = dict (
871+ COMPILETEST_FORCE_STAGE0 = "1"
872+ ))
873+
874+
773875def execute_build_pipeline (timer : Timer , pipeline : Pipeline , runner : BenchmarkRunner , final_build_args : List [str ]):
774876 # Clear and prepare tmp directory
775877 shutil .rmtree (pipeline .opt_artifacts (), ignore_errors = True )
@@ -844,6 +946,11 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu
844946 cmd (final_build_args )
845947 record_metrics (pipeline , stage4 )
846948
949+ # Try builds can be in various broken states, so we don't want to gatekeep them with tests
950+ if not is_try_build ():
951+ with timer .section ("Run tests" ):
952+ run_tests (pipeline )
953+
847954
848955def run (runner : BenchmarkRunner ):
849956 logging .basicConfig (
0 commit comments