Skip to content

Commit 49bfb9d

Browse files
authored
Improve build efficiency by building library subprojects in parallel (#630)
Each library variant build consists of three subprojects, which require sequential configuring and building. While the build steps can be parallelized by using multiple processes to compile the sources, the configuration step is largely single threaded. The multilib project has to build many variants now, and so a significant amount of time is spent waiting for the configuration of various projects to finish. This patch attempts to make the build process more efficient by running all the configuration steps for every variant subproject in parallel. The configuration/build steps in the underlying runtimes project are exposed, so that the higher level multilib project can invoke them as a single target. So instead of building each variant in turn, all the versions of compiler-rt are configured, then all versions are built, then all the C libraries are configured, and so on. This maximizes the amount of work that can be done at any given time. The build steps already benefit from parallelization: although built in series, each has the full number of available processes to use. However, at higher CPU counts there is an observable limit on how many processes each build can effectively use. So it may also be more efficient to instead run the build steps in parallel with a smaller number of proceses available to each. The option to control it (ENABLE_PARALLEL_LIB_BUILD) is OFF by default as which strategy is faster may come down to your available hardware, whereas ENABLE_PARALLEL_LIB_CONFIG should always be beneficial, so I've defaulted that to ON.
1 parent 4c3a6dd commit 49bfb9d

File tree

3 files changed

+132
-17
lines changed

3 files changed

+132
-17
lines changed

CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,20 @@ option(
150150
"During checkout, apply optional downstream patches to
151151
llvm-project to improve performance."
152152
)
153+
option(
154+
ENABLE_PARALLEL_LIB_CONFIG
155+
"Run the library variant configuration steps in parallel."
156+
ON
157+
)
158+
option(
159+
ENABLE_PARALLEL_LIB_BUILD
160+
"Run the library variant build steps in parallel."
161+
OFF
162+
)
163+
set(PARALLEL_LIB_BUILD_LEVELS
164+
"1" CACHE STRING
165+
"If ENABLE_PARALLEL_LIB_BUILD is ON, this number of processes will be assigned to each variant built."
166+
)
153167
option(
154168
ENABLE_QEMU_TESTING
155169
"Enable tests that use QEMU. This option is ON by default."
@@ -599,6 +613,9 @@ if(NOT PREBUILT_TARGET_LIBRARIES)
599613
-DLLVM_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/llvm
600614
-DMULTILIB_JSON=${LLVM_TOOLCHAIN_MULTILIB_JSON}
601615
-DENABLE_VARIANTS=${ENABLE_VARIANTS_PASSTHROUGH}
616+
-DENABLE_PARALLEL_LIB_CONFIG=${ENABLE_PARALLEL_LIB_CONFIG}
617+
-DENABLE_PARALLEL_LIB_BUILD=${ENABLE_PARALLEL_LIB_BUILD}
618+
-DPARALLEL_LIB_BUILD_LEVELS=${PARALLEL_LIB_BUILD_LEVELS}
602619
-DLIBC_HDRGEN=${LIBC_HDRGEN}
603620
-DFVP_INSTALL_DIR=${FVP_INSTALL_DIR}
604621
-DENABLE_QEMU_TESTING=${ENABLE_QEMU_TESTING}
@@ -608,9 +625,8 @@ if(NOT PREBUILT_TARGET_LIBRARIES)
608625
-DFETCHCONTENT_SOURCE_DIR_PICOLIBC=${FETCHCONTENT_SOURCE_DIR_PICOLIBC}
609626
-DFETCHCONTENT_SOURCE_DIR_NEWLIB=${FETCHCONTENT_SOURCE_DIR_NEWLIB}
610627
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
611-
USES_TERMINAL_CONFIGURE FALSE
628+
USES_TERMINAL_CONFIGURE TRUE
612629
USES_TERMINAL_BUILD TRUE
613-
USES_TERMINAL_TEST TRUE
614630
LIST_SEPARATOR ,
615631
CONFIGURE_HANDLED_BY_BUILD TRUE
616632
TEST_EXCLUDE_FROM_MAIN TRUE

arm-multilib/CMakeLists.txt

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,25 @@ set(
5050
fvp/get_fvps.sh"
5151
)
5252
set(FVP_CONFIG_DIR "${TOOLCHAIN_SOURCE_DIR}/fvp/config" CACHE STRING "The directory in which the FVP models are installed.")
53+
option(
54+
ENABLE_PARALLEL_LIB_CONFIG
55+
"Run the library variant configuration steps in parallel."
56+
ON
57+
)
58+
option(
59+
ENABLE_PARALLEL_LIB_BUILD
60+
"Run the library variant build steps in parallel."
61+
OFF
62+
)
63+
set(PARALLEL_LIB_BUILD_LEVELS
64+
"1" CACHE STRING
65+
"If ENABLE_PARALLEL_LIB_BUILD is ON, this number of processes will be assigned to each variant built."
66+
)
67+
if(NOT CMAKE_GENERATOR MATCHES "Ninja")
68+
if (ENABLE_PARALLEL_LIB_CONFIG OR ENABLE_PARALLEL_LIB_BUILD)
69+
message(WARNING "Library build parallelization should only be enabled with the Ninja generator.")
70+
endif()
71+
endif()
5372

5473
# If a compiler launcher such as ccache has been set, it should be
5574
# passed down to each subproject build.
@@ -131,6 +150,34 @@ add_dependencies(
131150
check-unwind
132151
)
133152

153+
if(ENABLE_PARALLEL_LIB_CONFIG OR ENABLE_PARALLEL_LIB_BUILD)
154+
# Additional targets to build the variant subprojects in parallel.
155+
# The build steps can use multible jobs to compile in parallel, but
156+
# the configuration steps are largely single threaded. This creates a
157+
# bottleneck if each variant is built in series.
158+
# It is significantly faster to run all the subproject configuration
159+
# steps in parallel, run the build steps, then run the next set of
160+
# configuration steps in parallel, etc.
161+
set(
162+
subtargets
163+
compiler_rt-configure
164+
compiler_rt-build
165+
clib-configure
166+
clib-build
167+
cxxlibs-configure
168+
cxxlibs-build
169+
)
170+
set(subtarget_deps none ${subtargets})
171+
list(REMOVE_AT subtarget_deps 6)
172+
173+
foreach(subtarget subtarget_dep IN ZIP_LISTS subtargets subtarget_deps)
174+
add_custom_target(${subtarget}-all)
175+
if(NOT subtarget_dep STREQUAL "none")
176+
add_dependencies(${subtarget}-all ${subtarget_dep}-all)
177+
endif()
178+
endforeach()
179+
endif()
180+
134181
# Read the JSON file to load a multilib configuration.
135182
file(READ ${MULTILIB_JSON} multilib_json_str)
136183
string(JSON multilib_defs GET ${multilib_json_str} "libs")
@@ -218,11 +265,58 @@ foreach(lib_idx RANGE ${lib_count_dec})
218265
STEP_TARGETS build install
219266
USES_TERMINAL_CONFIGURE FALSE
220267
USES_TERMINAL_BUILD TRUE
221-
USES_TERMINAL_TEST TRUE
222268
LIST_SEPARATOR ,
223269
CONFIGURE_HANDLED_BY_BUILD TRUE
224270
TEST_EXCLUDE_FROM_MAIN TRUE
225271
)
272+
273+
if(ENABLE_PARALLEL_LIB_CONFIG OR ENABLE_PARALLEL_LIB_BUILD)
274+
# Create additional steps to configure/build the subprojects.
275+
# These are collected to be run together, so that all the
276+
# configuration steps can be run in parallel.
277+
# Each step should depend on the previous, with the first depending on the pre-defined
278+
# 'configure' step, and the pre-defined 'build' step depending on the last.
279+
set(subtarget_deps configure ${subtargets} build)
280+
list(SUBLIST subtarget_deps 0 6 subtarget_dependees)
281+
list(SUBLIST subtarget_deps 2 6 subtarget_dependers)
282+
283+
# First loop to add the steps and targets.
284+
foreach(subtarget subtarget_dependee IN ZIP_LISTS subtargets subtarget_dependees)
285+
# Enabling USES_TERMINAL puts the step in Ninja's "console" job pool, which
286+
# prevents the steps from being run in parallel since each must be given
287+
# exclusive access to the terminal. When disabled, the console won't be updated
288+
# with any output from the step until it completes.
289+
set(step_uses_terminal ON)
290+
set(step_extra_env "")
291+
if(${subtarget} MATCHES "-configure$" AND ENABLE_PARALLEL_LIB_CONFIG)
292+
set(step_uses_terminal OFF)
293+
elseif(${subtarget} MATCHES "-build$" AND ENABLE_PARALLEL_LIB_BUILD)
294+
set(step_uses_terminal OFF)
295+
set(step_extra_env ${CMAKE_COMMAND} -E env CMAKE_BUILD_PARALLEL_LEVEL=${PARALLEL_LIB_BUILD_LEVELS})
296+
endif()
297+
ExternalProject_Add_Step(
298+
runtimes-${variant}
299+
${subtarget}
300+
COMMAND ${step_extra_env} ${CMAKE_COMMAND} --build <BINARY_DIR> --target ${subtarget}
301+
DEPENDEES ${subtarget_dependee}
302+
DEPENDERS build
303+
USES_TERMINAL ${step_uses_terminal}
304+
)
305+
ExternalProject_Add_StepTargets(runtimes-${variant} ${subtarget})
306+
add_dependencies(${subtarget}-all runtimes-${variant}-${subtarget})
307+
endforeach()
308+
309+
# Second loop to set the steps that will depend on the new targets.
310+
foreach(subtarget subtarget_depender IN ZIP_LISTS subtargets subtarget_dependers)
311+
ExternalProject_Add_StepDependencies(
312+
runtimes-${variant}
313+
${subtarget_depender}
314+
${subtarget}-all
315+
)
316+
endforeach()
317+
endif()
318+
319+
# Add custom check targets.
226320
set(check_targets "")
227321
if(read_ENABLE_LIBC_TESTS)
228322
list(APPEND check_targets check-${C_LIBRARY})

arm-runtimes/CMakeLists.txt

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,10 @@ set(compile_arch_flags "--target=${target_triple} ${COMPILE_FLAGS}")
210210
# flags, and requires a sysroot.
211211
set(lib_compile_flags "${compile_arch_flags} -ffunction-sections -fdata-sections -fno-ident --sysroot ${TEMP_LIB_DIR}")
212212

213-
# Declare this target now, since compiler-rt requires the dependency.
213+
# Generic target names for the C library.
214+
# Declare these now, since compiler-rt requires the 'install' dependency.
215+
add_custom_target(clib-configure)
216+
add_custom_target(clib-build)
214217
add_custom_target(clib-install)
215218

216219
###############################################################################
@@ -288,8 +291,8 @@ ExternalProject_Add(
288291
-DLLVM_CMAKE_DIR=${LLVM_BINARY_DIR}
289292
-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON
290293
${compiler_rt_test_cmake_args}
291-
STEP_TARGETS build install
292-
USES_TERMINAL_CONFIGURE FALSE
294+
STEP_TARGETS configure build install
295+
USES_TERMINAL_CONFIGURE TRUE
293296
USES_TERMINAL_BUILD TRUE
294297
USES_TERMINAL_INSTALL TRUE
295298
LIST_SEPARATOR ,
@@ -399,12 +402,13 @@ if(C_LIBRARY STREQUAL picolibc)
399402
<SOURCE_DIR>
400403
BUILD_COMMAND ${MESON_EXECUTABLE} compile
401404
INSTALL_COMMAND ${MESON_EXECUTABLE} install ${MESON_INSTALL_QUIET}
402-
USES_TERMINAL_CONFIGURE FALSE
405+
USES_TERMINAL_CONFIGURE TRUE
403406
USES_TERMINAL_BUILD TRUE
407+
USES_TERMINAL_INSTALL TRUE
404408
LIST_SEPARATOR ,
405409
CONFIGURE_HANDLED_BY_BUILD TRUE
406410
TEST_EXCLUDE_FROM_MAIN TRUE
407-
STEP_TARGETS build install
411+
STEP_TARGETS configure build install
408412
)
409413

410414
add_custom_target(check-picolibc)
@@ -523,12 +527,13 @@ if(C_LIBRARY STREQUAL newlib)
523527
<BINARY_DIR>/${target_triple}/libgloss/${cpu_family}/libcrt0-nosys.a
524528
${TEMP_LIB_DIR}/lib
525529
# FIXME: TEST_COMMAND?
526-
USES_TERMINAL_CONFIGURE FALSE
530+
USES_TERMINAL_CONFIGURE TRUE
527531
USES_TERMINAL_BUILD TRUE
532+
USES_TERMINAL_INSTALL TRUE
528533
# Always run the build command so that incremental builds are correct.
529534
CONFIGURE_HANDLED_BY_BUILD TRUE
530535
TEST_EXCLUDE_FROM_MAIN TRUE
531-
STEP_TARGETS install # FIXME: test?
536+
STEP_TARGETS configure build install # FIXME: test?
532537
)
533538
endif()
534539

@@ -620,11 +625,10 @@ if(C_LIBRARY STREQUAL llvmlibc)
620625
-DLLVM_ENABLE_RUNTIMES=libc
621626
-DLLVM_INCLUDE_TESTS=OFF # llvmlibc's tests require C++, so can't be built until llvmlibc can support libc++
622627
-DLLVM_LIBC_FULL_BUILD=ON
623-
STEP_TARGETS build install
624-
USES_TERMINAL_CONFIGURE FALSE
628+
STEP_TARGETS configure build install
629+
USES_TERMINAL_CONFIGURE TRUE
625630
USES_TERMINAL_BUILD TRUE
626631
USES_TERMINAL_INSTALL TRUE
627-
USES_TERMINAL_TEST TRUE
628632
LIST_SEPARATOR ,
629633
CONFIGURE_HANDLED_BY_BUILD TRUE
630634
INSTALL_COMMAND ${CMAKE_COMMAND} --install .
@@ -652,7 +656,7 @@ if(C_LIBRARY STREQUAL llvmlibc)
652656
${compiler_launcher_cmake_args}
653657
${common_llvmlibc_cmake_args}
654658
STEP_TARGETS build install
655-
USES_TERMINAL_CONFIGURE FALSE
659+
USES_TERMINAL_CONFIGURE TRUE
656660
USES_TERMINAL_BUILD TRUE
657661
USES_TERMINAL_INSTALL TRUE
658662
USES_TERMINAL_TEST TRUE
@@ -661,6 +665,8 @@ if(C_LIBRARY STREQUAL llvmlibc)
661665
)
662666
endif()
663667

668+
add_dependencies(clib-configure ${C_LIBRARY}-configure)
669+
add_dependencies(clib-build ${C_LIBRARY}-build)
664670
add_dependencies(clib-install ${C_LIBRARY}-install)
665671

666672
###############################################################################
@@ -758,11 +764,10 @@ if(ENABLE_CXX_LIBS)
758764
-DRUNTIME_VARIANT_NAME=${VARIANT}
759765
${cxxlibs_extra_cmake_options}
760766
${cxxlibs_test_cmake_options}
761-
STEP_TARGETS build install
762-
USES_TERMINAL_CONFIGURE FALSE
767+
STEP_TARGETS configure build install
768+
USES_TERMINAL_CONFIGURE TRUE
763769
USES_TERMINAL_BUILD TRUE
764770
USES_TERMINAL_INSTALL TRUE
765-
USES_TERMINAL_TEST TRUE
766771
LIST_SEPARATOR ,
767772
CONFIGURE_HANDLED_BY_BUILD TRUE
768773
)

0 commit comments

Comments
 (0)