Enable split-dwarf and thin archives when possible. (#11292)
Split-dwarf separates debug info to per-object .dwo files, which reduces
IO throughout the build. It works best with the gdb-index linker feature
(of gold and lld), which links to this debug info (vs embedding) and
also adds an index to speed debugger launch.
Thin archives, which is a feature of GNU AR and llvm-ar on Linux
produces static archives that do not embed object files, instead just
referencing them by path.
While spit-dwarf is aimed at debug configurations, thin archives can
help all builds.
Results:
```
Before:
Clean build:
real 7m24.609s
user 392m31.930s
sys 18m59.113s
build dir: 11GiB
libIREECompiler.so: 1.4GiB
Trivial relink the compiler:
real 0m5.336s
user 0m12.862s
sys 0m31.818s
After:
Clean build:
real 7m38.461s
user 402m52.180s
sys 18m8.314s
build dir: 5.2GiB
libIREECompiler.so: 490MiB
Trivial relink the compiler:
real 0m4.350s
user 0m8.233s
sys 0m8.104s
gdb of iree-compile starts instantly and sets a breakpoint on ireeCompilerRunMain with no delay (a few seconds to step in)
```
For a RelWithDebInfo build as documented on our website, wall clock time
to do a clean build is in the noise on my machine, but with the new
flags:
* Build directory size is reduced by >50%
* Size of the main compiler shared library is reduced by ~65%
* Time to incremental relink of the compiler after a trivial change to a
C file is reduced by ~18%.
Ideally there would be a less invasive way to enable these things, but
that isn't coming any time soon. I think the complexity is worth it. The
trivial relink case shows that this should make the cycle time better
disproportionately on lower end machines as well.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3754730..6181fba 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -266,6 +266,8 @@
option(IREE_ENABLE_TSAN "Enable thread sanitizer" OFF)
option(IREE_BYTECODE_MODULE_ENABLE_TSAN "Enable thread sanitizer in IREE modules in tests" OFF)
option(IREE_ENABLE_UBSAN "Enable undefined behavior sanitizer" OFF)
+option(IREE_ENABLE_SPLIT_DWARF "Enable gsplit-dwarf for debug information if the platform supports it" OFF)
+option(IREE_ENABLE_THIN_ARCHIVES "Enables thin ar archives (elf systems only). Disable for released static archives" OFF)
# STREQUAL feels wrong here - we don't care about the exact true-value used,
# ON or TRUE or something else. But we haven't been able to think of a less bad
@@ -364,7 +366,6 @@
include(iree_macros)
include(iree_copts)
-include(sanitizers)
include(iree_cc_binary)
include(iree_cc_library)
include(iree_cc_test)
diff --git a/build_tools/cmake/iree_setup_toolchain.cmake b/build_tools/cmake/iree_setup_toolchain.cmake
index b1dbfa9..bdb54d9 100644
--- a/build_tools/cmake/iree_setup_toolchain.cmake
+++ b/build_tools/cmake/iree_setup_toolchain.cmake
@@ -4,6 +4,9 @@
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+include(CheckCXXCompilerFlag)
+include(CheckLinkerFlag)
+
# Appends ${VALUE} to each argument.
function(iree_append_to_lists VALUE)
foreach(_VARIABLE ${ARGN})
@@ -11,6 +14,10 @@
endforeach(_VARIABLE)
endfunction()
+#-------------------------------------------------------------------------------
+# Linker setup
+#-------------------------------------------------------------------------------
+
if(IREE_ENABLE_LLD)
if(IREE_USE_LINKER)
message(FATAL_ERROR "IREE_ENABLE_LLD and IREE_USE_LINKER can't be set at the same time")
@@ -57,3 +64,84 @@
message(FATAL_ERROR "Compiler '${CMAKE_C_COMPILER}' does not support '${IREE_LINKER_FLAG}'")
endif()
endif()
+
+#-------------------------------------------------------------------------------
+# Sanitizer configurations
+#-------------------------------------------------------------------------------
+
+# Note: we add these flags to the global CMake flags, not to IREE-specific
+# variables such as IREE_DEFAULT_COPTS so that all symbols are consistently
+# defined with the same sanitizer flags, including e.g. standard library
+# symbols that might be used by both IREE and non-IREE (e.g. LLVM) code.
+
+if(IREE_ENABLE_ASAN)
+ string(APPEND CMAKE_CXX_FLAGS " -fsanitize=address")
+ string(APPEND CMAKE_C_FLAGS " -fsanitize=address")
+endif()
+if(IREE_ENABLE_MSAN)
+ string(APPEND CMAKE_CXX_FLAGS " -fsanitize=memory")
+ string(APPEND CMAKE_C_FLAGS " -fsanitize=memory")
+endif()
+if(IREE_ENABLE_TSAN)
+ string(APPEND CMAKE_CXX_FLAGS " -fsanitize=thread")
+ string(APPEND CMAKE_C_FLAGS " -fsanitize=thread")
+endif()
+if(IREE_ENABLE_UBSAN)
+ string(APPEND CMAKE_CXX_FLAGS " -fsanitize=undefined")
+ string(APPEND CMAKE_C_FLAGS " -fsanitize=undefined")
+endif()
+
+#-------------------------------------------------------------------------------
+# Build performance optimizations
+#-------------------------------------------------------------------------------
+
+# Split DWARF breaks debug information out of object files and stores them in
+# separate .dwo files. This reduces a lot of needless I/O during normal build
+# activities. It consists of the -gsplit-dwarf compiler flag and (for maximum
+# effect) the --gdb-index linker flag, which just emits an index to binaries
+# instead of full debug contents. gdb-index is supported by gold and partially
+# supported by LLD (LLD supports it if split-dwarf objects were compiled with
+# ggnu-pubnames).
+# If https://gitlab.kitware.com/cmake/cmake/-/issues/21179 is ever implemented,
+# use that.
+if(IREE_ENABLE_SPLIT_DWARF)
+ check_cxx_compiler_flag(-gsplit-dwarf IREE_SUPPORTS_SPLIT_DWARF)
+ if(IREE_SUPPORTS_SPLIT_DWARF)
+ # Also add -ggnu-pubnames for compilation because it links faster and lld
+ # doesn't do the slow path without it.
+ iree_append_to_lists(" -gsplit-dwarf -ggnu-pubnames"
+ CMAKE_C_FLAGS_DEBUG
+ CMAKE_CXX_FLAGS_DEBUG
+ CMAKE_C_FLAGS_RELWITHDEBINFO
+ CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ )
+ endif()
+ check_linker_flag(CXX "-Wl,--gdb-index" IREE_SUPPORTS_GDB_INDEX)
+ if(IREE_SUPPORTS_GDB_INDEX)
+ message(STATUS "Enabling gdb-index (binaries with debug info are not relocatable)")
+ iree_append_to_lists(" -Wl,--gdb-index"
+ CMAKE_EXE_LINKER_FLAGS_DEBUG
+ CMAKE_MODULE_LINKER_FLAGS_DEBUG
+ CMAKE_SHARED_LINKER_FLAGS_DEBUG
+ CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
+ CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
+ CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
+ )
+ endif()
+endif()
+
+# Thin archives makes static archives that only link to backing object files
+# instead of embedding them. This makes them non-relocatable but is almost
+# always the right thing outside of certain deployment/packaging scenarios.
+if(IREE_ENABLE_THIN_ARCHIVES)
+ execute_process(COMMAND ${CMAKE_AR} -V OUTPUT_VARIABLE IREE_AR_VERSION)
+ if ("${IREE_AR_VERSION}" MATCHES "^GNU ar|LLVM")
+ message(STATUS "Enabling thin archives (static libraries will not be relocatable)")
+ set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qT <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qT <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> crT <TARGET> <LINK_FLAGS> <OBJECTS>")
+ set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> crT <TARGET> <LINK_FLAGS> <OBJECTS>")
+ else()
+ message(WARNING "Thin archives requested but not supported by ar")
+ endif()
+endif()
diff --git a/build_tools/cmake/sanitizers.cmake b/build_tools/cmake/sanitizers.cmake
deleted file mode 100644
index 4df913f..0000000
--- a/build_tools/cmake/sanitizers.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2020 The IREE Authors
-#
-# Licensed under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#-------------------------------------------------------------------------------
-# Sanitizer configurations
-#-------------------------------------------------------------------------------
-
-# Note: we add these flags to the global CMake flags, not to IREE-specific
-# variables such as IREE_DEFAULT_COPTS so that all symbols are consistently
-# defined with the same sanitizer flags, including e.g. standard library
-# symbols that might be used by both IREE and non-IREE (e.g. LLVM) code.
-
-if(IREE_ENABLE_ASAN)
- string(APPEND CMAKE_CXX_FLAGS " -fsanitize=address")
- string(APPEND CMAKE_C_FLAGS " -fsanitize=address")
-endif()
-if(IREE_ENABLE_MSAN)
- string(APPEND CMAKE_CXX_FLAGS " -fsanitize=memory")
- string(APPEND CMAKE_C_FLAGS " -fsanitize=memory")
-endif()
-if(IREE_ENABLE_TSAN)
- string(APPEND CMAKE_CXX_FLAGS " -fsanitize=thread")
- string(APPEND CMAKE_C_FLAGS " -fsanitize=thread")
-endif()
-if(IREE_ENABLE_UBSAN)
- string(APPEND CMAKE_CXX_FLAGS " -fsanitize=undefined")
- string(APPEND CMAKE_C_FLAGS " -fsanitize=undefined")
-endif()