[PATCH v2 0/6] Improve make and make check parallelism
Adhemerval Zanella
adhemerval.zanella@linaro.org
Mon Jun 15 19:32:36 GMT 2026
One thing that has bothered me for some time is that neither 'make' nor
'make check' scales well with the number of cores: although each
subdirectory builds with full internal parallelism, the top-level
recursion is marked .NOTPARALLEL and runs the sub-makes strictly one at
a time.
Every subdirectory's compile tail and link step therefore leaves most
cores idle, and the constant additions to the testsuite keep making it
worse. Profiling the check phase also showed that some of the tests-special
are among the main culprits, most notably check-installed-headers, which
performs dozens of serial compiler invocations per installed header.
This series makes the subdirectory recursion run in parallel while
encoding the ordering the serial recursion relied on as explicit
dependencies:
1. scripts/gen-sorted.awk also emits the dependency edges it already
collects from the Depend files, so the parent makefile can use
them as real rules instead of a flattened total order.
2. The top-level Makefile drops .NOTPARALLEL. The subdirectories
that generate shared files consumed by the rest of the build run
serially first (csu, plus mach and hurd on Hurd), the Depend
edges become rule dependencies, elf stays last (its rtld link
consumes the aggregated libc_pic.a), pass barriers keep others
after lib and tests after others, and the subdirectory-built
files that top-level rules list as prerequisites get order-only
edges.
3. The tests and xtests classes carry only the pass barrier and none
of the csu-first or Depend edges, so 'make subdir/tests' runs just
that subdirectory's tests. A full 'make check' (run-built-tests=yes)
additionally serializes the timing-sensitive runs (see below).
4. elf is no longer forced last for the others and tests passes,
where the pass barriers already provide everything it needs.
5. The container testroot, which performs a full DESTDIR
installation, is no longer created when run-built-tests=no, since
no container test will run.
6. check-installed-headers compiles each header through its own
intermediate target so the compiler invocations spread across the
jobserver; the per-subdirectory .out aggregates the results in
the original order, so its contents and the test results are
unchanged.
A new 'make check-parallel' (and 'xcheck-parallel') runs the whole
testsuite with *no serialization at all*, through a new
serialize-tests flag (default on) that gates the per-subdirectory
.NOTPARALLEL and the run-time ordering.
Unlike v1, the series now also speeds up a full 'make check' with
run-built-tests=yes. The timing-sensitive subdirectories -- nptl (or
htl on Hurd) and rt -- must not have their tests run under heavy
parallel load, so their runs are serialized (each keeps a .NOTPARALLEL)
and ordered after the rest of the test run, one group at a time, the
threading subdirectory then rt.
Their test programs, however, are still built with full parallelism,
since building and running a subdirectory's tests are fused in a single
sub-make. The 'make check' now runs in two passes -- it builds every test
program with run-built-tests=no, where the recursion is fully parallel,
and then runs the tests with run-built-tests=yes.
Build results are unchanged: all built objects, archives, and shared
objects are bit-identical to the serial build across repeated clean
parallel builds, the installed tree layout is identical, and the
tests.sum results are identical. Since most of the possible failure
modes are races, the series was validated with repeated from-scratch
builds on x86_64-linux-gnu (24 threads), aarch64-linux-gnu (80 cores).
Benchmarks (cumulative; each percentage is relative to the previous
row, the first patch only adds data and acts as the baseline):
* x86_64 [1]
Commit | make | make check [3]
----------------------------------------------------------------------|----------------------|------------------------------------------
scripts/gen-sorted.awk: Also emit the subdirectory dependency edges | 1m18,728s | 6m14,957s
Makefile: Run the subdirectory recursion in parallel | 1m01,713s (-21.6%) | 3m10,413s (-49.2%)
Makefile: Do not force elf last for the others and tests passes | 1m00,562s (-1.9%) | 3m01,644s (-4.6%)
Makefile: Do not install the container testroot if not running tests | 1m00,703s (+0.2%) | 2m49,552s (-6.7%)
Run check-installed-headers concurrently for each header | 1m00,598s (-0.2%) | 2m50,389s (+0.5%)
----------------------------------------------------------------------|----------------------|------------------------------------------
* aarch64: Neoverse-N1 / 80c [2]
Commit | make | make check [3]
----------------------------------------------------------------------|----------------------|------------------------------------------
scripts/gen-sorted.awk: Also emit the subdirectory dependency edges | 1m45.251s | 14m46.183s
Makefile: Run the subdirectory recursion in parallel | 0m56.703s (-46.1%) | 04m58.726s (-66.3%)
Makefile: Do not force elf last for the others and tests passes | 0m53.887s (-5.0%) | 04m23.790s (-11.7%)
Makefile: Do not install the container testroot if not running tests | 0m54.801s (+1.7%) | 04m01.574s (-8.4%)
Run check-installed-headers concurrently for each header | 0m54.978s (+0.3%) | 03m02.405s (-24.5%)
----------------------------------------------------------------------|----------------------|------------------------------------------
A full 'make check' with run-built-tests=yes, baseline (serial
recursion) versus the full series, and with 'make check-parallel':
* x86_64: Ryzen 5900 / 12c/24t
Configuration | make check [3]
----------------------------------------------------------------------|---------------
baseline (serial recursion | 17m43,757s
this series (make check | 12m52,644s
this series (make check-parallel) | 5m54,945s
----------------------------------------------------------------------|---------------
* aarch64: Neoverse-N1 / 80c
Configuration | make check [3]
----------------------------------------------------------------------|---------------
baseline (serial recursion | 29m37.604s
this series (make check | 15m01.576s
this series (make check-parallel) | 12m52.494s
----------------------------------------------------------------------|---------------
On aarch64 (80c) 'make check-parallel' oversubscribes the machine
enough to produce spurious test timeouts (note the sys time), so it
needs a larger TIMEOUTFACTOR there; the default 'make check' does not.
[1] Ryzen 5900 / 12c/24t, gcc 16.1.1 / ld 2.46 / gnumake 4.3, targetting x86_64-linux-gnu
[2] Neoverse-N1 / 80c, gcc 15.2.1 / ld 2.45 / gnumake 4.3, targetting aarch64-linux-gnu
[3] run-built-tests=no
[4] run-built-tests=yes
Changes since v1:
* 'make subdir/tests' now runs only that subdirectory's tests; in v1
the Depend edges on the tests class also pulled in (and ran) the
tests of every subdirectory reachable through them.
* A full 'make check' (run-built-tests=yes) is now supported and
faster: nptl/htl and rt are run serially and last, each with its
own .NOTPARALLEL, while their test programs still build in parallel
via the two-pass 'make check' described above.
* New 'make check-parallel'/'xcheck-parallel' to run the suite with no
serialization (patch 6).
* catgets: declare its test locales through gen-locales.mk. catgets runs
gencat under those locales but never declared them as prerequisites.
Adhemerval Zanella (6):
scripts/gen-sorted.awk: Also emit the subdirectory dependency edges
Makefile: Run the subdirectory recursion in parallel
Makefile: Do not force elf last for the others and tests passes
Makefile: Do not install the container testroot if not running tests
Run check-installed-headers concurrently for each header
Makerules: add 'make check-parallel' to run tests without
serialization
Makeconfig | 8 ++
Makefile | 195 ++++++++++++++++++++++++++++++++++++++---
Makerules | 44 +++++++++-
Rules | 38 +++++---
catgets/Makefile | 14 ++-
elf/Makefile | 5 ++
htl/Makefile | 8 ++
nptl/Makefile | 5 +-
rt/Makefile | 9 ++
scripts/gen-sorted.awk | 6 ++
10 files changed, 298 insertions(+), 34 deletions(-)
--
2.43.0
More information about the Libc-alpha
mailing list