[PATCH v2 0/6] Improve make and make check parallelism
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Tue Jun 16 21:00:27 GMT 2026
On 16/06/26 17:06, DJ Delorie wrote:
> Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
>> Every subdirectory's compile tail and link step therefore leaves most
>> cores idle,
>
> One trick I use is to sort the things to build by size, largest first.
> That tends to pack into available cores better. Currently we sort by
> name.
That interesting, do you mean to sort by the number of files within
the subfolder, or use the file size as a proxy?
I might try to check if this pays out, and most likely create a better
observation tools besides measuring time. At least with a very unscientific
measurement (staring at btop output), I noticed that for 'make' the
serialization points seems minimal (csu, then rtld mainly).
>
>> This series makes the subdirectory recursion run in parallel while
>> encoding the ordering the serial recursion relied on as explicit
>> dependencies:
>
> A few weeks ago I asked an AI to try to fix the problems that stopped us
> from doing parallel toplevel. I won't share the results as it would
> taint your patch, but it had a few suggestions (and claimed way more of
> a speedup than you report, but I never had a chance to validate it):
>
> * There are some toplevel tasks that need to be run serially, mostly
> relating to generating the various versions files. It used flock(1)
> to serialize them.
I used a different strategy:
546 # The subdirectories that generate shared files in $(common-objpfx)
547 # consumed by the rest of the build without explicit dependencies: csu
548 # provides the gen-as-const headers, and on Hurd the mach and hurd
549 # directories generate the MiG RPC headers (every other subdirectory
550 # otherwise runs a nested make in hurd/ to create them, racing under
551 # parallel recursion; see sysdeps/mach/hurd/Makefile). Run them serially,
552 # in their sorted order (mach, hurd, csu).
553 +subdir-pregen := $(filter mach hurd csu,$(subdirs))
554 +subdir-rest := $(filter-out $(+subdir-pregen),$(subdirs))
555
556 $(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
557 $(addsuffix /$(t),$(+subdir-rest)): $(addsuffix /$(t),$(+subdir-pregen))))
558 +subdir-pregen-prev :=
559 $(foreach d,$(+subdir-pregen),$(foreach t,$(+ordered_parallel_subdir_targets),$(eval \
560 $(d)/$(t): $(addsuffix /$(t),$(+subdir-pregen-prev))))\
561 $(eval +subdir-pregen-prev := $(d)))
The idea is 'csu' generates the tree-wide gen-as-const headers that every
subfolder requires, and then make prevents any parallel execution unable to
start until 'csu' has completely finished.
The rules does:
string/subdir_lib: csu/subdir_lib
math/subdir_lib: csu/subdir_lib
... (all ~49) ...
So when you do make -jN lib (the subdir_lib pass):
* csu/subdir_lib is the only subdir_lib target with no subdir prerequisite,
so it's the only one eligible at the start.
* string/subdir_lib, math/subdir_lib, etc. all list csu/subdir_lib as a
prerequisite, so they are not eligible while csu is still building.
So it is essentially:
[ csu/subdir_lib sub-make ]
* generates abi-versions.h, gen-as-const headers, etc.
* compiles csu's own objects
|___ exits ___
|
[ string/subdir_lib ] [ math/subdir_lib ] [ ... 49 in parallel ]
each sub-make checks "is abi-versions.h up to date?"
-> yes (csu made it) -> does NOT regenerate it
The flock *might* be a interesting approach because during trying to parallelize
the build I hit two issues where shared file is produced lazily by a non-csu
subdir (csu gen-as-const headers and the catgets locales, handled in the third
patch - and I am continuously running multiple parallel builds to if I missed
something).
It would allow parallelize the 'csu' subfolder itself, and start the subfolders
in parallel.
But I think flock has two main extra complications: it is not POSIX (so Linux
specific, not sure if this is properly support by Hurd), and it leaves the make
graph (the dependencies is defined by writing access). I this the later might
be source of potential issues, I never saw Makefile actively using it.
>
> * it added various cross-directory build dependencies, mostly things
> depending on support/ but elf->csu and support->elf. I don't know if
> gen-sorted handles this.
The 'csu' is special, but the extra dependencies is expressed by the extra
subdir-deps* from the first patch. On x86_64-linux-gnu, the sysd-sorted
is now create with there extra definitions:
subdir-deps-assert += iconvdata
subdir-deps-assert += localedata
subdir-deps-catgets += intl
subdir-deps-debug += localedata
subdir-deps-iconvdata += iconv
subdir-deps-iconvdata += localedata
subdir-deps-intl += iconvdata
subdir-deps-intl += localedata
subdir-deps-libio += localedata
subdir-deps-localedata += locale
subdir-deps-malloc += dlfcn
subdir-deps-malloc += nptl
subdir-deps-malloc += htl
subdir-deps-malloc += rt
subdir-deps-mathvec += math
subdir-deps-posix += localedata
subdir-deps-rt += nptl
subdir-deps-rt += htl
subdir-deps-stdio-common += localedata
subdir-deps-stdlib += localedata
subdir-deps-string += localedata
subdir-deps-support += elf
subdir-deps-time += timezone
subdir-deps-wcsmbs += localedata
subdir-deps-resolv += nptl
subdir-deps-resolv += htl
subdir-deps-hesiod += nss
subdir-deps-hesiod += resolv
subdir-deps-nis += nss
subdir-deps-nscd += nptl
subdir-deps-nscd += htl
subdir-deps-nss += dlfcn
subdir-deps-nss += resolv
>
>> 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.
>
> The time needed to build the testroot was a concern back when I added
> it, and the compromise is that we only build it once - it lacks
> dependencies that would cause lots of spurious rebuilds. Making this
> happen even less often makes sense.
>
> It can, however, be built in parallel with any non-container test.
> It's disk-heavy, not cpu or ram.
I think we can add some extra parallelization for run-built-tests=yes,
similar on how csu is done. I will take a look.
More information about the Libc-alpha
mailing list