@@ -124,6 +124,12 @@ def llvm_bolt_profile_merged_file(self) -> Path:
124
124
def metrics_path (self ) -> Path :
125
125
return self .build_root () / "build" / "metrics.json"
126
126
127
+ def executable_extension (self ) -> str :
128
+ raise NotImplementedError
129
+
130
+ def skipped_tests (self ) -> Iterable [str ]:
131
+ return ()
132
+
127
133
128
134
class LinuxPipeline (Pipeline ):
129
135
def checkout_path (self ) -> Path :
@@ -152,6 +158,13 @@ def build_rustc_perf(self):
152
158
def supports_bolt (self ) -> bool :
153
159
return True
154
160
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
+
155
168
156
169
class WindowsPipeline (Pipeline ):
157
170
def __init__ (self ):
@@ -211,6 +224,13 @@ def rustc_profile_template_path(self) -> Path:
211
224
def supports_bolt (self ) -> bool :
212
225
return False
213
226
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
+
214
234
215
235
def get_timestamp () -> float :
216
236
return time .time ()
@@ -403,9 +423,9 @@ def delete_directory(path: Path):
403
423
shutil .rmtree (path )
404
424
405
425
406
- def unpack_archive (archive : Path ):
426
+ def unpack_archive (archive : Path , target_dir : Optional [ Path ] = None ):
407
427
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 )
409
429
410
430
411
431
def download_file (src : str , target : Path ):
@@ -455,6 +475,7 @@ def cmd(
455
475
)
456
476
return subprocess .run (args , env = environment , check = True )
457
477
478
+
458
479
class BenchmarkRunner :
459
480
def run_rustc (self , pipeline : Pipeline ):
460
481
raise NotImplementedError
@@ -465,6 +486,7 @@ def run_llvm(self, pipeline: Pipeline):
465
486
def run_bolt (self , pipeline : Pipeline ):
466
487
raise NotImplementedError
467
488
489
+
468
490
class DefaultBenchmarkRunner (BenchmarkRunner ):
469
491
def run_rustc (self , pipeline : Pipeline ):
470
492
# Here we're profiling the `rustc` frontend, so we also include `Check`.
@@ -478,6 +500,7 @@ def run_rustc(self, pipeline: Pipeline):
478
500
LLVM_PROFILE_FILE = str (pipeline .rustc_profile_template_path ())
479
501
)
480
502
)
503
+
481
504
def run_llvm (self , pipeline : Pipeline ):
482
505
run_compiler_benchmarks (
483
506
pipeline ,
@@ -494,6 +517,7 @@ def run_bolt(self, pipeline: Pipeline):
494
517
crates = LLVM_BOLT_CRATES
495
518
)
496
519
520
+
497
521
def run_compiler_benchmarks (
498
522
pipeline : Pipeline ,
499
523
profiles : List [str ],
@@ -650,10 +674,8 @@ def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner):
650
674
def gather_rustc_profiles (pipeline : Pipeline , runner : BenchmarkRunner ):
651
675
LOGGER .info ("Running benchmarks with PGO instrumented rustc" )
652
676
653
-
654
677
runner .run_rustc (pipeline )
655
678
656
-
657
679
profile_path = pipeline .rustc_profile_merged_file ()
658
680
LOGGER .info (f"Merging Rustc PGO profiles to { profile_path } " )
659
681
cmd ([
@@ -770,6 +792,86 @@ def record_metrics(pipeline: Pipeline, timer: Timer):
770
792
log_metrics (metrics )
771
793
772
794
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
+
773
875
def execute_build_pipeline (timer : Timer , pipeline : Pipeline , runner : BenchmarkRunner , final_build_args : List [str ]):
774
876
# Clear and prepare tmp directory
775
877
shutil .rmtree (pipeline .opt_artifacts (), ignore_errors = True )
@@ -844,6 +946,11 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu
844
946
cmd (final_build_args )
845
947
record_metrics (pipeline , stage4 )
846
948
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
+
847
954
848
955
def run (runner : BenchmarkRunner ):
849
956
logging .basicConfig (
0 commit comments