Skip to content
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

llvm: build with PGO #79454

Closed
wants to merge 1 commit into from
Closed
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
138 changes: 133 additions & 5 deletions Formula/llvm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,17 @@ def install
clang-tools-extra
lld
lldb
openmp
polly
mlir
polly
]
runtimes = %w[
compiler-rt
libcxx
libcxxabi
libunwind
]
on_macos { runtimes << "openmp" }
on_linux { projects << "openmp" }

py_ver = Language::Python.major_minor_version("python3")
site_packages = Language::Python.site_packages("python3").delete_prefix("lib/")
Expand Down Expand Up @@ -110,7 +111,7 @@ def install
-DLIBOMP_INSTALL_ALIASES=OFF
-DCLANG_PYTHON_BINDINGS_VERSIONS=#{py_ver}
-DPACKAGE_VENDOR=#{tap.user}
-DPACKAGE_BUGREPORT=#{tap.issues_url}
-DBUG_REPORT_URL=#{tap.issues_url}
-DCLANG_VENDOR_UTI=org.#{tap.user.downcase}.clang
]

Expand All @@ -122,13 +123,12 @@ def install
args << "-DFFI_LIBRARY_DIR=#{Formula["libffi"].opt_lib}"
end

sdk = MacOS.sdk_path_if_needed
on_macos do
args << "-DLLVM_BUILD_LLVM_C_DYLIB=ON"
args << "-DLLVM_ENABLE_LIBCXX=ON"
args << "-DLLVM_CREATE_XCODE_TOOLCHAIN=#{MacOS::Xcode.installed? ? "ON" : "OFF"}"
args << "-DRUNTIMES_CMAKE_ARGS=-DCMAKE_INSTALL_RPATH=#{rpath}"

sdk = MacOS.sdk_path_if_needed
args << "-DDEFAULT_SYSROOT=#{sdk}" if sdk
end

Expand Down Expand Up @@ -163,6 +163,134 @@ def install
end

llvmpath = buildpath/"llvm"
pgo_build = false
on_macos { pgo_build = build.stable? && build.bottle? }
if pgo_build
# We build LLVM a few times first for optimisations. See
# https://github.com/Homebrew/homebrew-core/issues/77975

# PGO build adapted from:
# https://llvm.org/docs/HowToBuildWithPGO.html#building-clang-with-pgo
# https://github.com/llvm/llvm-project/blob/33ba8bd2/llvm/utils/collect_and_build_with_pgo.py
# https://github.com/facebookincubator/BOLT/blob/01f471e7/docs/OptimizingClang.md
extra_args = [
"-DLLVM_TARGETS_TO_BUILD=Native",
"-DLLVM_ENABLE_PROJECTS=clang;compiler-rt;lld",
]
cflags = ENV.cflags&.split || []
cxxflags = ENV.cxxflags&.split || []

# The later stage builds avoid the shims, and the build
# will target Penryn unless otherwise specified
if Hardware::CPU.intel?
cflags << "-march=#{Hardware.oldest_cpu}"
cxxflags << "-march=#{Hardware.oldest_cpu}"
end

on_macos do
extra_args << "-DLLVM_ENABLE_LIBCXX=ON"
extra_args << "-DDEFAULT_SYSROOT=#{sdk}" if sdk
end

extra_args << "-DCMAKE_C_FLAGS=#{cflags.join(" ")}" unless cflags.empty?
extra_args << "-DCMAKE_CXX_FLAGS=#{cxxflags.join(" ")}" unless cxxflags.empty?

# First, build a stage1 compiler. It might be possible to skip this step on macOS
# and use system Clang instead, but this stage does not take too long, and we want
# to avoid incompatibilities from generating profile data with a newer Clang than
# the one we consume the data with.
mkdir llvmpath/"stage1" do
system "cmake", "-G", "Unix Makefiles", "..",
*extra_args, *std_cmake_args
system "cmake", "--build", ".", "--target", "clang", "llvm-profdata", "profile"
end

# Our just-built Clang needs a little help finding C++ headers,
# since the atomic and type_traits headers are not in the SDK
# on macOS versions before Big Sur.
on_macos do
if MacOS.version <= :catalina && sdk
toolchain_path = if MacOS::CLT.installed?
MacOS::CLT::PKG_PATH
else
MacOS::Xcode.toolchain_path
end

cxxflags << "-isystem#{toolchain_path}/usr/include/c++/v1"
cxxflags << "-isystem#{toolchain_path}/usr/include"
cxxflags << "-isystem#{MacOS.sdk_path_if_needed}/usr/include"

extra_args.reject! { |s| s["CMAKE_CXX_FLAGS"] }
extra_args << "-DCMAKE_CXX_FLAGS=#{cxxflags.join(" ")}"
end
end

# Next, build an instrumented stage2 compiler
mkdir llvmpath/"stage2" do
# LLVM Profile runs out of static counters
# https://reviews.llvm.org/D92669, https://reviews.llvm.org/D93281
# Without this, the build produces many warnings of the form
# LLVM Profile Warning: Unable to track new values: Running out of static counters.
instrumented_cflags = cflags + ["-Xclang -mllvm -Xclang -vp-counters-per-site=6"]
instrumented_cxxflags = cxxflags + ["-Xclang -mllvm -Xclang -vp-counters-per-site=6"]
Comment on lines +234 to +235
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this, the build produces many warnings of the form

LLVM Profile Warning: Unable to track new values: Running out of static counters.  Consider using option -mllvm -vp-counters-per-site=<n> to allocate more value profile counters at compile time.

It is my understanding that when this occurs there is no benefit to generating additional profile data.

instrumented_extra_args = extra_args.reject { |s| s["CMAKE_C_FLAGS"] || s["CMAKE_CXX_FLAGS"] }

system "cmake", "-G", "Unix Makefiles", "..",
"-DCMAKE_C_COMPILER=#{llvmpath}/stage1/bin/clang",
"-DCMAKE_CXX_COMPILER=#{llvmpath}/stage1/bin/clang++",
"-DLLVM_BUILD_INSTRUMENTED=IR",
"-DLLVM_BUILD_RUNTIME=NO",
"-DCMAKE_C_FLAGS=#{instrumented_cflags.join(" ")}",
"-DCMAKE_CXX_FLAGS=#{instrumented_cxxflags.join(" ")}",
*instrumented_extra_args, *std_cmake_args
system "cmake", "--build", ".", "--target", "clang", "lld"

# We run some `check-*` targets to increase profiling
# coverage. These do not need to succeed.
begin
system "cmake", "--build", ".", "--target", "check-clang", "check-llvm", "--", "--keep-going"
rescue RuntimeError
nil
end
end

# Then, generate the profile data
mkdir llvmpath/"stage2-profdata" do
system "cmake", "-G", "Unix Makefiles", "..",
"-DCMAKE_C_COMPILER=#{llvmpath}/stage2/bin/clang",
"-DCMAKE_CXX_COMPILER=#{llvmpath}/stage2/bin/clang++",
*extra_args, *std_cmake_args

# This build is for profiling, so it is safe to ignore errors.
# We pass `--keep-going` to `make` to ignore the error that requires
# deparallelisation on ARM. (See below.)
begin
system "cmake", "--build", ".", "--", "--keep-going"
rescue RuntimeError
nil
end
end

# Merge the generated profile data
profpath = llvmpath/"stage2/profiles"
system llvmpath/"stage1/bin/llvm-profdata",
"merge",
"-output=#{profpath}/pgo_profile.prof",
*Dir[profpath/"*.profraw"]

# Make sure to build with our profiled compiler and use the profile data
args << "-DCMAKE_C_COMPILER=#{llvmpath}/stage1/bin/clang"
args << "-DCMAKE_CXX_COMPILER=#{llvmpath}/stage1/bin/clang++"
args << "-DLLVM_PROFDATA_FILE=#{profpath}/pgo_profile.prof"

# Silence some warnings
cflags << "-Wno-backend-plugin"
cxxflags << "-Wno-backend-plugin"
args << "-DCMAKE_C_FLAGS=#{cflags.join(" ")}"
args << "-DCMAKE_CXX_FLAGS=#{cxxflags.join(" ")}"
end

# Now, we can build.
mkdir llvmpath/"build" do
system "cmake", "-G", "Unix Makefiles", "..", *(std_cmake_args + args)
# Workaround for CMake Error: failed to create symbolic link
Expand Down