Build all SubProcesses in parallel from a single make jobserver - #67
Merged
oliviermattelaer merged 3 commits intoAug 18, 2026
Merged
Conversation
'make -j 18' in SubProcesses now spreads 18 concurrent compilations over ALL the P* directories at once, instead of building one directory at a time with 18 jobs (or giving each directory 18/N). The parallelism comes from GNU make's jobserver: SubProcesses/makefile becomes a plain recursive dispatcher that fans out with '+$(MAKE) -C <dir>', so its -j slots are shared with every sub-make and a directory that runs out of work immediately hands its slots to the others. That name used to hold the per-process build rules themselves (symlinked into each P*), so the files are rearranged: SubProcesses/makefile the dispatcher (new madmatrix_subprocesses.mk) SubProcesses/madmatrix.mk the build rules, linked as P*/makefile SubProcesses/madmatrix_standalone.mk ditto for standalone_mg7 The dispatcher owns no build logic: it even builds the common library *through* a representative P* directory, so the BACKEND/'cppauto' resolution, the compiler flags and the src/ and lib/ paths stay defined in madmatrix.mk only. Building the common library once, up front, is also what makes the fan-out safe: every P* makefile used to recurse into src/ on its own, which N parallel sub-makes would all have done at the same time on the same objects. The dispatcher now passes MADMATRIX_COMMONLIB_EXTERNAL=1 to say it owns that step; a P* directory built on its own is unaffected. The bldall backend list is collapsed into a single BLDBACKENDS variable so multi-backend builds can be driven from the dispatcher without duplicating the platform logic. On the Python side, mg7 compiled one subprocess per MadgraphSubprocess; it now resolves 'cppauto' once and makes a single 'make -jN' call on SubProcesses (N = cpu_thread_pool_size, -1 meaning the CPU count). find_output_type told standalone_mg7 apart by the presence of SubProcesses/madmatrix.mk, which the regular mg7 export now also has; the discriminator moves to madmatrix_standalone.mk. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
|
Nice! I think the only thing that is missing would be a progress indicator of the status of the compilation, if we are still interested in adding it (see #6), of course. |
The build output was captured by misc.compile and thrown away on success, so there was nothing to look at while the subprocesses compiled and nothing left afterwards. Run make directly instead, redirecting the whole build into Events/<run>/compile_subprocesses.log, and frame it with Start compilation of SubProcesses for device 'cppnone' (4 subprocess(es), 18 parallel job(s)), see log detail in Events/run_01/compile_subprocesses.log Compilation of SubProcesses done in 2.0 s On failure the raised error points at the same log, which now holds the compiler diagnostics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Author
|
Ok I added some log for the compilation of the SubProcesses (with information where more detailled log are kept). Let's merge? |
oliviermattelaer
pushed a commit
that referenced
this pull request
Aug 17, 2026
a1afe9d made the mg7 launcher compile subprocesses concurrently with a ThreadPoolExecutor. That is unsafe: every P* makefile builds the shared common library by recursing into the shared src/, and nothing serialises them, so N concurrent subprocess builds means N processes compiling src/build.<backend>/ Parameters.o and read_slha.o to the same paths and linking the same lib<...>_common.so. It broke check_xsec_processes (ttx1j) on CI: p p > t t~ j is the only entry in that section with more than one subprocess, so it is the only one that took the concurrent path, and it failed with a compilation error in P0_QQx_ttxg. The same commit passed a re-run minutes later, which is the giveaway. The race does not reproduce on macOS (0/6 at -j4, 0/10 at -j1 with 18 cores): src/ has two objects and the window is short. Widening it with a sleep in the src rules shows it plainly -- four concurrent writers to each of Parameters.o and read_slha.o. Two further reasons to drop rather than patch this: - PR #61 proposed the same ThreadPoolExecutor design and was closed unmerged. This commit reintroduced it without knowing. - PR #67 does it properly, at the make level: SubProcesses/makefile becomes a jobserver dispatcher, the common library is built once up front, and P* directories are told so with MADMATRIX_COMMONLIB_EXTERNAL=1. Its jobserver also shares slots dynamically, where the static build_jobs // len(pending) split here gave -j1 per make on a 4-core CI runner -- neutralising the parallel-make win (3.4x, the larger half) while keeping the racy half. Removes compile_subprocesses, build_subprocess, resolve_api_path, build_jobs and the concurrent.futures import; MadgraphSubprocess's compile loop and init_subprocesses are byte-identical to main again, so this file no longer conflicts with #67 (verified with git merge-tree). Everything else a1afe9d added is unrelated to the build and stays: the decay-phase timing split, and on this branch the mg7 decay mode, clean_pids, drop_closed_channels and skipping systematics for decays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Member
|
Good for me! |
oliviermattelaer
deleted the
claude/subprocesses-parallelization-f86837
branch
August 18, 2026 08:45
Contributor
Author
|
Thanks !!! |
oliviermattelaer
added a commit
that referenced
this pull request
Aug 19, 2026
main brought 8 commits: the SubProcesses parallel build (#67), the dead CI test names and the test_manager change that makes a name matching nothing an error (#70), the aloha TMP eval namespace (#69), a more robust cppauto resolution and a compile log for the mg7 SubProcesses build. Four conflicts, all resolved towards main where it restructured something and towards this branch where it only renamed: - mg7/launch.py: main moved the per-device resolution out of the loop into resolve_cppauto_backend(), with real error handling, and builds the libraries up front. Its version is taken whole; the inline quick fix this branch had renamed no longer exists. - aloha.yml: this branch renamed the launcher, main fixed the test selector (dropping a testIO_aloha.* that never existed and a missing space that made the -e exclusion inert). Both kept. - acceptancetest.yml: main deletes three jobs naming tests that no longer exist; this branch had only renamed the launcher inside them. Deletion kept, which matters now that a name matching nothing is an error. - madgraph_interface.py: main changed the detection file from madmatrix.mk to madmatrix_standalone.mk, because after its restructure both exporters write madmatrix.mk and only the standalone one writes the other. Its file name with this branch's format name, otherwise a plain mg7 output is detected as standalone. main is written in the backend vocabulary this branch renames, and two of those files merged without a conflict: - launch.py arrived with seventeen cppauto references (the function and its name, the make invocation, the regex, the messages), translated to cpu. - madmatrix.mk gained BLDAVXS = cppnone cppsse4 ... from the parallel build. The bldavxs target happened to survive, since $(subst cpp,,cppnone) still gives bldnone, but BLDBACKENDS feeds commonlib.% which runs BACKEND=$* directly, so bldcommonlib died with Invalid backend BACKEND='cppnone': supported backends are ... 'cpu' that is, the dispatcher the parallel build routes through. BLDAVXS now holds the new names and the bld* targets are mapped explicitly, because they keep their historical short names (bldnone, not bldcpu_scalar) and three tests invoke make bldnone directly. Checked: bldall and bldcommonlib resolve to cpu_scalar and cpu_128b on this host with no invalid backend, and a full mg7 run goes from devices = ["cpu"] through "Device 'cpu' resolved as 'cpu_128b'" to events, with main's new compile_subprocesses.log in place. Unit suite 901 tests with only the two known pre-existing failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Running
make -j 18inSubProcesses/now spreads 18 concurrent compilations over all theP*directories at once — instead of building one directory at a time with 18 jobs, or giving each directory18/N.This is the make-level counterpart of #61, which did the same thing with a
ThreadPoolExecutorinmg7/madevent.py.Mechanism
The parallelism comes from GNU make's jobserver.
SubProcesses/makefilebecomes a plain recursive dispatcher that fans out with+$(MAKE) -C <dir>, so its-jslots are shared with every sub-make: a directory that runs out of work immediately hands its slots to the others.File layout
SubProcesses/makefileused to be the per-process build rules (symlinked into eachP*). That name is now the dispatcher, so the files are rearranged:SubProcesses/makefilemadmatrix_subprocesses.mk)SubProcesses/madmatrix.mkP*/makefileSubProcesses/madmatrix_standalone.mkstandalone_mg7(itincludesmadmatrix.mk)The dispatcher owns no build logic of its own. It even builds the common library through a representative
P*directory, so theBACKEND/cppautoresolution, the compiler flags and thesrc/,lib/paths stay defined inmadmatrix.mkonly.The race that had to be fixed first
Every
P*makefile recursed intosrc/to build the shared common library. With N directories running at once they would all have done that simultaneously, on the same objects. The dispatcher builds it once, up front, and passesMADMATRIX_COMMONLIB_EXTERNAL=1to say it owns that step; aP*directory built on its own is unaffected.The
bldallbackend list is collapsed into a singleBLDBACKENDSvariable, so multi-backend builds can be driven from the dispatcher without duplicating the platform logic.Python side
mg7compiled one subprocess perMadgraphSubprocess. It now resolvescppautoonce and makes a singlemake -jNcall onSubProcesses/(N=cpu_thread_pool_size,-1meaning the CPU count). Onemakeinvocation replaces the per-subprocess loop.Incidental
find_output_typetoldstandalone_mg7apart by the presence ofSubProcesses/madmatrix.mk, which the regularmg7export now also has; the discriminator moves tomadmatrix_standalone.mk.Testing
p p > e+ e-+p p > e+ e- j(4 subprocesses), bothmg7andstandalone_mg7:-j112.3s →-j44.0s →-j182.1s; the common library is compiled exactly onceclean,cleanall,bldall(2 backends, one common lib each),make P2_gQ_epemQ,BACKEND=… USEBUILDDIR=1, plainmake, incremental no-op, and a plainmakeinside a singleP*directorymake: *** [build@P2_gQ_epemQ] Error 2, so the failing directory is still namedcheck_sa.exeruns; fullbin/generate_eventscompletes in 5.2s including the buildtest_standalone_mg7_goodhel_filter,test_standalone_mg7_vs_cpp,test_output_mg7_directorypass (test_group_subprocess_mg7skips)Note: the
systematics computation failedmessage at the end ofgenerate_eventsis pre-existing — reproduced on a stashed baseline.🤖 Generated with Claude Code