From 0c10798ef42c5fbe0b371ecc12f49bfd84946d17 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Wed, 14 Oct 2026 16:15:01 +0200 Subject: [PATCH] [CI] Build the Windows solution on more than one MSBuild node (#7379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmake --build only passes a job count to MSBuild when it is asked for one, and .ci/compile.sh never asked, so every Visual Studio generator build ran single-node: projects were built one after another and MTT only ever parallelized the files of whichever project happened to be building. Ask for one node per core, overridable with BUILD_PARALLEL_LEVEL, and fall back to a single node when the core count is not exposed. Alongside it set EnforceProcessCountAcrossBuilds and CL_MPCount, the knobs Microsoft's build throughput write-up pairs with MTT: without them the node count and MTT multiply into more cl.exe processes than the runner has cores for. Co-authored-by: Lukas BrĂ¼bach --- .ci/compile.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.ci/compile.sh b/.ci/compile.sh index eb850a88b..4aa189bc7 100755 --- a/.ci/compile.sh +++ b/.ci/compile.sh @@ -18,7 +18,7 @@ # --cmake-generator sets CMAKE_GENERATOR as used by cmake # --target-macos-version sets the min os version - only used for macOS builds # --profile writes an MSBuild performance summary and binary log, Windows only -# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION MAKE_SANITIZE MAKE_COVERAGE VCPKG_TARGET_MACOS_VERSION BUILD_PROFILE +# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION MAKE_SANITIZE MAKE_COVERAGE VCPKG_TARGET_MACOS_VERSION BUILD_PARALLEL_LEVEL BUILD_PROFILE # (correspond to args: --debug/--release --install --package --suffix --server --test --sanitize --coverage --ccache --dir --profile) # exitcode: 1 for failure, 3 for invalid arguments @@ -314,9 +314,20 @@ if [[ $RUNNER_OS == macOS ]]; then fi elif [[ $RUNNER_OS == Windows ]]; then + # cmake only hands MSBuild a job count when one is asked for, and without it + # MSBuild builds a single node: one project at a time, whatever MTT does inside + # it. Ask for a node per core. + if [[ ! $BUILD_PARALLEL_LEVEL ]]; then + BUILD_PARALLEL_LEVEL="${NUMBER_OF_PROCESSORS:-1}" + fi + buildflags+=(--parallel "$BUILD_PARALLEL_LEVEL") + # Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/ # and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt - buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true) + # EnforceProcessCountAcrossBuilds makes the CL_MPCount ceiling apply across all + # the projects the nodes are building, instead of each node running its own + # cl.exe processes and /m and MTT multiplying into an oversubscribed machine. + buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true -p:EnforceProcessCountAcrossBuilds=true -p:CL_MPCount="$BUILD_PARALLEL_LEVEL") if [[ $BUILD_PROFILE ]]; then # A performance summary says which projects and tasks cost what, the binary log # keeps the full timeline; both are far too noisy to always produce. The files