Skip to content

enable PGO on x86_64-apple-darwin #110639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ jobs:
os: ubuntu-20.04-8core-32gb
- name: dist-x86_64-apple
env:
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
SCRIPT: PGO_HOST=x86_64-apple-darwin python3 src/ci/stage-build.py python3 ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
Expand Down
39 changes: 34 additions & 5 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::config::{LlvmLibunwind, RustcLto, TargetSelection};
use crate::dist;
use crate::llvm;
use crate::tool::SourceType;
use crate::util::get_clang_cl_resource_dir;
use crate::util::get_clang_rt_dir;
use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date};
use crate::LLVM_TOOLS;
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
Expand Down Expand Up @@ -923,10 +923,39 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
// found. This is to avoid the linker errors about undefined references to
// `__llvm_profile_instrument_memop` when linking `rustc_driver`.
let mut llvm_linker_flags = String::new();
if builder.config.llvm_profile_generate && target.contains("msvc") {
if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
// Add clang's runtime library directory to the search path
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
if builder.config.llvm_profile_generate {
if target.contains("msvc") {
if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
// Add clang's runtime library directory to the search path
let clang_rt_dir = get_clang_rt_dir(clang_cl_path, true);
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
}
}

if target.contains("apple") {
let clang_rt_profile_lib_suffix = if target.ends_with("ios-sim") {
"iossim"
} else if target.ends_with("ios") {
"ios"
} else if target.ends_with("tvos-sim") {
"tvossim"
} else if target.ends_with("tvos") {
"tvos"
} else if target.ends_with("darwin") {
"osx"
} else if target.ends_with("watchos-sim") {
"watchossim"
} else if target.ends_with("watchos") {
"watchos"
} else {
panic!("clang has no clang_rt.profile library for {target}");
};

let clang = builder.cc(target);
let clang_rt_dir = get_clang_rt_dir(clang, false);
let clang_rt_profile_lib = format!("libclang_rt.profile_{clang_rt_profile_lib_suffix}");
llvm_linker_flags.push_str(&format!("-l{clang_rt_profile_lib}"));
llvm_linker_flags.push_str(" ");
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/bootstrap/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::process::Command;
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::channel;
use crate::config::{Config, TargetSelection};
use crate::util::get_clang_cl_resource_dir;
use crate::util::get_clang_rt_dir;
use crate::util::{self, exe, output, t, up_to_date};
use crate::{CLang, GitRepo};

Expand Down Expand Up @@ -331,7 +331,10 @@ impl Step for Llvm {
// This flag makes sure `FileCheck` is copied in the final binaries directory.
cfg.define("LLVM_INSTALL_UTILS", "ON");

let mut enabled_llvm_projects = Vec::new();

if builder.config.llvm_profile_generate {
enabled_llvm_projects.push("compiler-rt");
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);
Expand All @@ -344,6 +347,7 @@ impl Step for Llvm {
if builder.config.llvm_bolt_profile_generate
|| builder.config.llvm_bolt_profile_use.is_some()
{
enabled_llvm_projects.push("bolt");
// Relocations are required for BOLT to work.
ldflags.push_all("-Wl,-q");
}
Expand Down Expand Up @@ -403,8 +407,6 @@ impl Step for Llvm {
cfg.define("LLVM_BUILD_32_BITS", "ON");
}

let mut enabled_llvm_projects = Vec::new();

if util::forcing_clang_based_tests() {
enabled_llvm_projects.push("clang");
enabled_llvm_projects.push("compiler-rt");
Expand Down Expand Up @@ -828,7 +830,7 @@ impl Step for Lld {
if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
// Find clang's runtime library directory and push that as a search path to the
// cmake linker flags.
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
let clang_rt_dir = get_clang_rt_dir(clang_cl_path, true);
ldflags.push_all(&format!("/libpath:{}", clang_rt_dir.display()));
}
}
Expand Down
34 changes: 14 additions & 20 deletions src/bootstrap/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,28 +488,22 @@ fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBu
}
}

/// Adapted from https://github.com/llvm/llvm-project/blob/782e91224601e461c019e0a4573bbccc6094fbcd/llvm/cmake/modules/HandleLLVMOptions.cmake#L1058-L1079
///
/// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource
/// directory to the linker flags, otherwise there will be linker errors about the profiler runtime
/// missing. This function returns the path to that directory.
pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf {
// Similar to how LLVM does it, to find clang's library runtime directory:
// - we ask `clang-cl` to locate the `clang_rt.builtins` lib.
let mut builtins_locator = Command::new(clang_cl_path);
builtins_locator.args(&["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]);

let clang_rt_builtins = output(&mut builtins_locator);
let clang_rt_builtins = Path::new(clang_rt_builtins.trim());
pub fn get_clang_rt_dir(clang: impl AsRef<Path>, is_msvc: bool) -> PathBuf {
let mut cmd = Command::new(clang.as_ref());
if is_msvc {
cmd.args(&["/clang:-print-runtime-dir"]);
} else {
cmd.args(&["-print-runtime-dir"]);
};

let dir = output(&mut cmd);
let dir = PathBuf::from(dir.trim());
assert!(
clang_rt_builtins.exists(),
"`clang-cl` must correctly locate the library runtime directory"
dir.exists(),
"`{}` must correctly locate the library runtime directory",
clang.as_ref().display()
);

// - the profiler runtime will be located in the same directory as the builtins lib, like
// `$LLVM_DISTRO_ROOT/lib/clang/$LLVM_VERSION/lib/windows`.
let clang_rt_dir = clang_rt_builtins.parent().expect("The clang lib folder should exist");
clang_rt_dir.to_path_buf()
dir
}

pub fn lld_flag_no_threads(is_windows: bool) -> &'static str {
Expand Down
2 changes: 1 addition & 1 deletion src/ci/github-actions/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ jobs:

- name: dist-x86_64-apple
env:
SCRIPT: ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
SCRIPT: PGO_HOST=x86_64-apple-darwin python3 src/ci/stage-build.py python3 ./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin
RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
Expand Down
13 changes: 9 additions & 4 deletions src/ci/scripts/install-clang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ if isMacOS; then
if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then
bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin"
else
file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
OSX_ARCH=$(uname -m)
file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-${OSX_ARCH}-apple-darwin.tar.xz"
retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-${OSX_ARCH}-apple-darwin.tar.xz"

mkdir -p citools && cd citools

tar xJf "clang+llvm-${LLVM_VERSION}-${OSX_ARCH}-apple-darwin.tar.xz"
mv "clang+llvm-${LLVM_VERSION}-${OSX_ARCH}-apple-darwin" clang-rust
bindir="$(pwd)/clang-rust/bin"
fi

ciCommandSetEnv CC "${bindir}/clang"
Expand Down
43 changes: 43 additions & 0 deletions src/ci/stage-build.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,47 @@ def rustc_profile_template_path(self) -> Path:
def supports_bolt(self) -> bool:
return False

class DarwinPipeline(Pipeline):
def __init__(self):
self.checkout_dir = Path(os.getcwd())

def checkout_path(self) -> Path:
return self.checkout_dir

def downloaded_llvm_dir(self) -> Path:
return self.checkout_path() / "citools" / "clang-rust"

def build_root(self) -> Path:
return self.checkout_path()

def opt_artifacts(self) -> Path:
return Path("/tmp/tmp-multistage/opt-artifacts")

def build_rustc_perf(self):
# rustc-perf version from 2022-07-22
perf_commit = "9dfaa35193154b690922347ee1141a06ec87a199"
rustc_perf_zip_path = self.opt_artifacts() / "perf.zip"

def download_rustc_perf():
download_file(
f"https://github.com/rust-lang/rustc-perf/archive/{perf_commit}.zip",
rustc_perf_zip_path
)
with change_cwd(self.opt_artifacts()):
unpack_archive(rustc_perf_zip_path)
move_path(Path(f"rustc-perf-{perf_commit}"), self.rustc_perf_dir())
delete_file(rustc_perf_zip_path)

retry_action(download_rustc_perf, "Download rustc-perf")

with change_cwd(self.rustc_perf_dir()):
cmd([self.cargo_stage_0(), "build", "-p", "collector"], env=dict(
RUSTC=str(self.rustc_stage_0()),
RUSTC_BOOTSTRAP="1"
))

def supports_bolt(self) -> bool:
return False

def get_timestamp() -> float:
return time.time()
Expand Down Expand Up @@ -576,6 +617,8 @@ def create_pipeline() -> Pipeline:
return LinuxPipeline()
elif sys.platform in ("cygwin", "win32"):
return WindowsPipeline()
elif sys.platform == "darwin":
return DarwinPipeline()
else:
raise Exception(f"Optimized build is not supported for platform {sys.platform}")

Expand Down