From 8fb3161bf5d4211c4c3bab1e57b57fe8a0cab1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 May 2023 23:42:51 +0200 Subject: [PATCH 1/5] Use CS PGO for LLVM --- src/bootstrap/llvm.rs | 17 +++++++++--- src/ci/stage-build.py | 60 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 67cb88373910c..a7cdb6ad8c722 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -331,15 +331,24 @@ impl Step for Llvm { // This flag makes sure `FileCheck` is copied in the final binaries directory. cfg.define("LLVM_INSTALL_UTILS", "ON"); + let mut cxxflags = vec![]; if builder.config.llvm_profile_generate { - cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); - if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { - cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); + if std::env::var("LLVM_USE_CS_PGO").is_ok() { + cfg.define("LLVM_BUILD_INSTRUMENTED", "CSIR"); + if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { + cfg.define("LLVM_CSPROFILE_DATA_DIR", llvm_profile_dir); + } + } else { + cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); + if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { + cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); + } } cfg.define("LLVM_BUILD_RUNTIME", "No"); } if let Some(path) = builder.config.llvm_profile_use.as_ref() { - cfg.define("LLVM_PROFDATA_FILE", &path); + // cfg.define("LLVM_PROFDATA_FILE", &path); + cxxflags.push(&format!("-fprofile-use={path}")); } if builder.config.llvm_bolt_profile_generate || builder.config.llvm_bolt_profile_use.is_some() diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 8d03d3759bf00..9c5f540cf432c 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -48,6 +48,7 @@ LLVM_BOLT_CRATES = LLVM_PGO_CRATES + class Pipeline: # Paths def checkout_path(self) -> Path: @@ -86,6 +87,9 @@ def opt_artifacts(self) -> Path: def llvm_profile_dir_root(self) -> Path: return self.opt_artifacts() / "llvm-pgo" + def llvm_profile_merged_file_intermediate(self) -> Path: + return self.opt_artifacts() / "llvm-pgo-intermediate.profdata" + def llvm_profile_merged_file(self) -> Path: return self.opt_artifacts() / "llvm-pgo.profdata" @@ -450,6 +454,7 @@ def cmd( ) return subprocess.run(args, env=environment, check=True) + class BenchmarkRunner: def run_rustc(self, pipeline: Pipeline): raise NotImplementedError @@ -460,6 +465,7 @@ def run_llvm(self, pipeline: Pipeline): def run_bolt(self, pipeline: Pipeline): raise NotImplementedError + class DefaultBenchmarkRunner(BenchmarkRunner): def run_rustc(self, pipeline: Pipeline): # Here we're profiling the `rustc` frontend, so we also include `Check`. @@ -473,6 +479,7 @@ def run_rustc(self, pipeline: Pipeline): LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) ) ) + def run_llvm(self, pipeline: Pipeline): run_compiler_benchmarks( pipeline, @@ -489,6 +496,7 @@ def run_bolt(self, pipeline: Pipeline): crates=LLVM_BOLT_CRATES ) + def run_compiler_benchmarks( pipeline: Pipeline, profiles: List[str], @@ -622,7 +630,7 @@ def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner): runner.run_llvm(pipeline) - profile_path = pipeline.llvm_profile_merged_file() + profile_path = pipeline.llvm_profile_merged_file_intermediate() LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") cmd([ pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", @@ -642,13 +650,37 @@ def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner): delete_directory(pipeline.llvm_profile_dir_root()) +def gather_llvm_cs_profiles(pipeline: Pipeline, runner: BenchmarkRunner): + LOGGER.info("Running benchmarks with CS PGO instrumented LLVM") + + runner.run_llvm(pipeline) + + profile_path = pipeline.llvm_profile_merged_file() + LOGGER.info(f"Merging LLVM CS PGO profiles to {profile_path}") + cmd([ + pipeline.downloaded_llvm_dir() / "bin" / "llvm-profdata", + "merge", + "-o", profile_path, + pipeline.llvm_profile_dir_root(), + pipeline.llvm_profile_merged_file_intermediate() + ]) + + LOGGER.info("LLVM CS PGO statistics") + LOGGER.info(f"{profile_path}: {format_bytes(get_path_size(profile_path))}") + LOGGER.info( + f"{pipeline.llvm_profile_dir_root()}: {format_bytes(get_path_size(pipeline.llvm_profile_dir_root()))}") + LOGGER.info(f"Profile file count: {count_files(pipeline.llvm_profile_dir_root())}") + + # We don't need the individual .profraw files now that they have been merged + # into a final .profdata + delete_directory(pipeline.llvm_profile_dir_root()) + + def gather_rustc_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with PGO instrumented rustc") - runner.run_rustc(pipeline) - profile_path = pipeline.rustc_profile_merged_file() LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") cmd([ @@ -787,6 +819,27 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu print_free_disk_space(pipeline) clear_llvm_files(pipeline) + + # Stage 1b: Build rustc + CS PGO instrumented LLVM + with timer.section("Stage 1b (LLVM CS PGO)") as stage1b: + with stage1.section("Build rustc and LLVM") as rustc_build: + build_rustc(pipeline, args=[ + "--llvm-profile-generate", + "--llvm-profile-use", + pipeline.llvm_profile_merged_file_intermediate() + ], env=dict( + LLVM_USE_CS_PGO="1", + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p"), + + )) + record_metrics(pipeline, rustc_build) + + with stage1b.section("Gather profiles"): + gather_llvm_cs_profiles(pipeline, runner) + print_free_disk_space(pipeline) + + clear_llvm_files(pipeline) + final_build_args += [ "--llvm-profile-use", pipeline.llvm_profile_merged_file() @@ -865,6 +918,7 @@ def run(runner: BenchmarkRunner): print_binary_sizes(pipeline) + if __name__ == "__main__": runner = DefaultBenchmarkRunner() run(runner) From 71c23761d97927023cfff662ced94de8da64bdc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 22 May 2023 19:39:16 +0200 Subject: [PATCH 2/5] Use more PGO counters --- src/bootstrap/llvm.rs | 1 + src/ci/stage-build.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index a7cdb6ad8c722..3aabc4cdaa1fc 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -344,6 +344,7 @@ impl Step for Llvm { cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); } } + cfg.define("LLVM_VP_COUNTERS_PER_SITE", "10"); cfg.define("LLVM_BUILD_RUNTIME", "No"); } if let Some(path) = builder.config.llvm_profile_use.as_ref() { diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 9c5f540cf432c..79ba7a87644e4 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -822,7 +822,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu # Stage 1b: Build rustc + CS PGO instrumented LLVM with timer.section("Stage 1b (LLVM CS PGO)") as stage1b: - with stage1.section("Build rustc and LLVM") as rustc_build: + with stage1b.section("Build rustc and LLVM") as rustc_build: build_rustc(pipeline, args=[ "--llvm-profile-generate", "--llvm-profile-use", From 282dec1320e25f6d7219dd4a9e146c590108cae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 22 May 2023 19:55:19 +0200 Subject: [PATCH 3/5] Set counters using LLVM CLI flags --- src/bootstrap/llvm.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 3aabc4cdaa1fc..e5d118acaf05f 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -342,9 +342,10 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); + cxxflags.push("-mllvm"); + cxxflags.push("-vp-counters-per-site=10"); } } - cfg.define("LLVM_VP_COUNTERS_PER_SITE", "10"); cfg.define("LLVM_BUILD_RUNTIME", "No"); } if let Some(path) = builder.config.llvm_profile_use.as_ref() { From aeb7b54c3f536bbcccc7f1ee5785ceab27addab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 23 May 2023 09:51:49 +0200 Subject: [PATCH 4/5] Try different profile format name --- src/bootstrap/llvm.rs | 4 ++-- src/ci/stage-build.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index e5d118acaf05f..faeefbaff780f 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -342,10 +342,10 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); - cxxflags.push("-mllvm"); - cxxflags.push("-vp-counters-per-site=10"); } } + cxxflags.push("-mllvm"); + cxxflags.push("-vp-counters-per-site=10"); cfg.define("LLVM_BUILD_RUNTIME", "No"); } if let Some(path) = builder.config.llvm_profile_use.as_ref() { diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 79ba7a87644e4..316909186f3e5 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -829,8 +829,8 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu pipeline.llvm_profile_merged_file_intermediate() ], env=dict( LLVM_USE_CS_PGO="1", - LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p"), - + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "%4m.profraw"), + # LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p"), )) record_metrics(pipeline, rustc_build) From 21d4c2d286933e00fee7e43365b464e465837ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 23 May 2023 17:55:53 +0200 Subject: [PATCH 5/5] Try using flags directly --- src/bootstrap/llvm.rs | 41 ++++++++++++++++++++++++++++------------- src/ci/stage-build.py | 5 ++--- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index faeefbaff780f..faeefc76f2f9d 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -331,26 +331,34 @@ impl Step for Llvm { // This flag makes sure `FileCheck` is copied in the final binaries directory. cfg.define("LLVM_INSTALL_UTILS", "ON"); - let mut cxxflags = vec![]; + let mut cxxflags: Vec = Vec::new(); if builder.config.llvm_profile_generate { if std::env::var("LLVM_USE_CS_PGO").is_ok() { - cfg.define("LLVM_BUILD_INSTRUMENTED", "CSIR"); - if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { - cfg.define("LLVM_CSPROFILE_DATA_DIR", llvm_profile_dir); - } + //cfg.define("LLVM_BUILD_INSTRUMENTED", "CSIR"); + cxxflags.push(format!( + "-fcs-profile-generate={}", + std::env::var("LLVM_PROFILE_DIR").unwrap() + )); + //if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { + // cfg.define("LLVM_CSPROFILE_DATA_DIR", llvm_profile_dir); + //} + cxxflags.push("-mllvm".to_string()); + cxxflags.push("-vp-counters-per-site=10".to_string()); } else { - cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); - if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { - cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); - } + //cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); + //if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") { + // cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir); + //} + cxxflags.push(format!( + "-fprofile-generate={}", + std::env::var("LLVM_PROFILE_DIR").unwrap() + )); } - cxxflags.push("-mllvm"); - cxxflags.push("-vp-counters-per-site=10"); cfg.define("LLVM_BUILD_RUNTIME", "No"); } if let Some(path) = builder.config.llvm_profile_use.as_ref() { // cfg.define("LLVM_PROFDATA_FILE", &path); - cxxflags.push(&format!("-fprofile-use={path}")); + cxxflags.push(format!("-fprofile-use={path}")); } if builder.config.llvm_bolt_profile_generate || builder.config.llvm_bolt_profile_use.is_some() @@ -485,7 +493,14 @@ impl Step for Llvm { cfg.define("LLVM_VERSION_SUFFIX", suffix); } - configure_cmake(builder, target, &mut cfg, true, ldflags, &[]); + configure_cmake( + builder, + target, + &mut cfg, + true, + ldflags, + &cxxflags.iter().map(|s| s.as_str()).collect::>(), + ); configure_llvm(builder, target, &mut cfg); for (key, val) in &builder.config.llvm_build_config { diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 316909186f3e5..08ae6931be0bb 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -810,7 +810,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu build_rustc(pipeline, args=[ "--llvm-profile-generate" ], env=dict( - LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p") + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "profiles") )) record_metrics(pipeline, rustc_build) @@ -829,8 +829,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRu pipeline.llvm_profile_merged_file_intermediate() ], env=dict( LLVM_USE_CS_PGO="1", - LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "%4m.profraw"), - # LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "prof-%p"), + LLVM_PROFILE_DIR=str(pipeline.llvm_profile_dir_root() / "profiles2"), )) record_metrics(pipeline, rustc_build)