@@ -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