Skip to content

Commit 90dc3a2

Browse files
committed
tests: run MPI integration tests in parallel, sized to the host
Integration tests launched MPIEXEC_MAX_NUMPROCS ranks, which FindMPI sets to the host physical core count -> 96 ranks/test on the Jenkins box, massively oversubscribing and timing out (svo_cthyb_basic_tf). - Introduce SOLID_DMFT_TEST_NUM_PROC = min(4, cores) for the rank count per integration test, use it for all MPI-launched tests, and set the PROCESSORS test property so 'ctest -j' budgets concurrency correctly. - Jenkins: pin SOLID_DMFT_TEST_NUM_PROC=4 (the build pod's cgroup makes nproc misreport as 1), disable OpenMPI binding and allow oversubscribe so concurrent mpiruns don't stack on cores 0-3, and run 'ctest -j2' (the pod's cpuset is only 2 physical cores + HT siblings). macOS m1: 'ctest -j8'.
1 parent f42c0d6 commit 90dc3a2

2 files changed

Lines changed: 42 additions & 8 deletions

File tree

jenkins/Jenkinsfile

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ def runBuild = { String platform, String prefix, List<String> envs ->
3737
envs += [
3838
"OPENBLAS_NUM_THREADS=1",
3939
"MKL_NUM_THREADS=1",
40-
"OMP_NUM_THREADS=1"]
40+
"OMP_NUM_THREADS=1",
41+
/* Tests run concurrently via `ctest -j`, each launching its own mpirun.
42+
OpenMPI binds-to-core by default and every mpirun starts binding at
43+
core 0, so all concurrent tests pile onto the same few cores while the
44+
rest idle (8x slowdowns observed). Disable binding so the scheduler
45+
spreads ranks, and allow oversubscription as a safety net. */
46+
"OMPI_MCA_hwloc_base_binding_policy=none",
47+
"OMPI_MCA_rmaps_base_oversubscribe=yes"]
4148
/* the triqs venv on macOS is built from the brew python, which may differ from the system python3 */
4249
def python3 = macos ? "${env.BREW}/bin/python3" : "python3"
4350
def pythonVer = sh(returnStdout: true, script: """$python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")'""").trim()
@@ -84,13 +91,21 @@ def runBuild = { String platform, String prefix, List<String> envs ->
8491
args += ' -DASAN=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo'
8592
dir(buildDir) {
8693
sh """#!/bin/sh -ex
87-
cmake $WORKSPACE -DCMAKE_INSTALL_PREFIX=$installDir -DTRIQS_ROOT=$triqsDir $args
94+
cmake $WORKSPACE -DCMAKE_INSTALL_PREFIX=$installDir -DTRIQS_ROOT=$triqsDir -DSOLID_DMFT_TEST_NUM_PROC=4 $args
8895
make -j\$PARALLEL || make -j1 VERBOSE=1
8996
"""
9097
catchError(buildResult: 'UNSTABLE', stageResult: 'UNSTABLE') {
9198
try {
92-
/* run tests in a single rank since they use MPI */
93-
sh "ctest --output-on-failure -j1"
99+
/* Tests run 4 MPI ranks each (PROCESSORS property) with binding
100+
disabled (see envs), so ctest -j is a core budget. The Linux build
101+
pod's cpuset (3-4,99-100) is only 2 physical cores + their HT
102+
siblings, so -j2 matches the 2 real cores: integration tests
103+
(PROCESSORS=4 > 2) run one at a time across all 4 logical CPUs,
104+
and unit tests pack 2-up without oversubscribing. Total wall-time
105+
is bounded by the 2 physical cores regardless. macOS m1 nodes have
106+
~10 cores, so -j8 = 2 concurrent 4-rank tests. */
107+
def ctestJobs = macos ? 8 : 2
108+
sh "ctest --output-on-failure -j${ctestJobs}"
94109
} catch (exc) {
95110
archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log')
96111
throw exc

test/python/CMakeLists.txt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ endforeach()
3636

3737
# ------------------------------#
3838

39+
# MPI ranks per integration test = min(4, cores). Not the raw core count:
40+
# FindMPI's MPIEXEC_MAX_NUMPROCS = physical cores would spawn 96 ranks/test on
41+
# the CI box (OOM/timeouts); the cap avoids that, and never exceeding the cores
42+
# keeps mpirun from requesting more slots than exist. The PROCESSORS property
43+
# below lets `ctest -j` schedule concurrently. Override with
44+
# -DSOLID_DMFT_TEST_NUM_PROC=N.
45+
include(ProcessorCount)
46+
ProcessorCount(_solid_dmft_ncores)
47+
if(_solid_dmft_ncores GREATER 0 AND _solid_dmft_ncores LESS 4)
48+
set(_solid_dmft_default_nproc ${_solid_dmft_ncores})
49+
else()
50+
set(_solid_dmft_default_nproc 4)
51+
endif()
52+
set(SOLID_DMFT_TEST_NUM_PROC ${_solid_dmft_default_nproc} CACHE STRING "MPI ranks launched per integration test")
53+
3954
# integration tests
4055
set (integration_tests
4156
svo_hubbardI_basic
@@ -62,12 +77,13 @@ foreach(test ${integration_tests})
6277

6378
add_test(NAME ${test}
6479
# COMMAND bash ${test}.sh
65-
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test.py
80+
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${SOLID_DMFT_TEST_NUM_PROC} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test.py
6681
# COMMAND ${TRIQS_PYTHON_EXECUTABLE} test.py
6782
WORKING_DIRECTORY ${test_dir}
6883
)
6984

7085
set_property(TEST ${test} APPEND PROPERTY ENVIRONMENT PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH})
86+
set_property(TEST ${test} PROPERTY PROCESSORS ${SOLID_DMFT_TEST_NUM_PROC})
7187
endforeach()
7288

7389
# ------------------------------#
@@ -80,11 +96,12 @@ foreach(file test_maxent.py helper.py)
8096
endforeach()
8197

8298
add_test(NAME maxent_${test}
83-
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test_maxent.py
99+
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${SOLID_DMFT_TEST_NUM_PROC} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test_maxent.py
84100
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
85101
)
86102

87103
set_property(TEST maxent_${test} APPEND PROPERTY ENVIRONMENT PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH})
104+
set_property(TEST maxent_${test} PROPERTY PROCESSORS ${SOLID_DMFT_TEST_NUM_PROC})
88105
set_property(TEST maxent_${test} APPEND PROPERTY DEPENDS "svo_hubbardI_basic")
89106

90107
# ------------------------------#
@@ -101,11 +118,12 @@ foreach(test ${restart_integration_test})
101118
endforeach()
102119

103120
add_test(NAME restart_${test}
104-
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test_restart.py
121+
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${SOLID_DMFT_TEST_NUM_PROC} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test_restart.py
105122
WORKING_DIRECTORY ${test_dir}
106123
)
107124

108125
set_property(TEST restart_${test} APPEND PROPERTY ENVIRONMENT PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH})
126+
set_property(TEST restart_${test} PROPERTY PROCESSORS ${SOLID_DMFT_TEST_NUM_PROC})
109127
endforeach()
110128
set_property(TEST maxent_${test} APPEND PROPERTY DEPENDS "svo_hubbardI_basic")
111129

@@ -142,12 +160,13 @@ foreach(test ${gw_emb_integration_tests})
142160

143161
add_test(NAME ${test}
144162
# COMMAND bash ${test}.sh
145-
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test.py
163+
COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${SOLID_DMFT_TEST_NUM_PROC} ${MPIEXEC_PREFLAGS} ${TRIQS_PYTHON_EXECUTABLE} test.py
146164
# COMMAND ${TRIQS_PYTHON_EXECUTABLE} test.py
147165
WORKING_DIRECTORY ${test_dir}
148166
)
149167

150168
set_property(TEST ${test} APPEND PROPERTY ENVIRONMENT PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH})
169+
set_property(TEST ${test} PROPERTY PROCESSORS ${SOLID_DMFT_TEST_NUM_PROC})
151170
endforeach()
152171

153172
endif()

0 commit comments

Comments
 (0)