Skip to content

Commit 1c5fb9b

Browse files
committed
config:build_jobs is capped by the number of cores available
config:build_jobs controls the number of parallel jobs to spawn during builds, but cannot ever exceed the number of cores on the machine. The default is set to 16 or the number of available cores, whatever is lowest.
1 parent 36fda22 commit 1c5fb9b

File tree

4 files changed

+39
-10
lines changed

4 files changed

+39
-10
lines changed

etc/spack/defaults/config.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,12 @@ config:
9999
locks: true
100100

101101

102-
# The default number of jobs to use when running `make` in parallel.
103-
# If set to 4, for example, `spack install` will run `make -j4`.
104-
# If not set, all available cores are used by default.
105-
# build_jobs: 4
102+
# The tentative number of jobs to use when running `make` in parallel,
103+
# always limited by the number of cores available. For instance:
104+
# - If set to 16 on a 4 cores machine `spack install` will run `make -j4`
105+
# - If set to 16 on a 18 cores machine `spack install` will run `make -j16`
106+
# If not set, Spack will use all available cores up to 16.
107+
# build_jobs: 16
106108

107109

108110
# If set to true, Spack will use ccache to cache C compiles.

lib/spack/spack/cmd/common/arguments.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66

77
import argparse
8+
import multiprocessing
89

910
import spack.cmd
1011
import spack.config
@@ -86,6 +87,7 @@ def __call__(self, parser, namespace, jobs, option_string):
8687
'[expected a positive integer, got "{1}"]'
8788
raise ValueError(msg.format(option_string, jobs))
8889

90+
jobs = min(jobs, multiprocessing.cpu_count())
8991
spack.config.set('config:build_jobs', jobs, scope='command_line')
9092

9193
setattr(namespace, 'jobs', jobs)
@@ -94,7 +96,8 @@ def __call__(self, parser, namespace, jobs, option_string):
9496
def default(self):
9597
# This default is coded as a property so that look-up
9698
# of this value is done only on demand
97-
return spack.config.get('config:build_jobs')
99+
return min(spack.config.get('config:build_jobs'),
100+
multiprocessing.cpu_count())
98101

99102
@default.setter
100103
def default(self, value):

lib/spack/spack/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
'verify_ssl': True,
101101
'checksum': True,
102102
'dirty': False,
103-
'build_jobs': multiprocessing.cpu_count(),
103+
'build_jobs': min(16, multiprocessing.cpu_count()),
104104
}
105105
}
106106

lib/spack/spack/test/cmd/common/arguments.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,38 @@ def parser():
2020
yield p
2121
# Cleanup the command line scope if it was set during tests
2222
if 'command_line' in spack.config.config.scopes:
23-
spack.config.config.remove_scope('command_line')
23+
spack.config.config.scopes['command_line'].clear()
2424

2525

26-
@pytest.mark.parametrize('cli_args,expected', [
26+
@pytest.fixture(params=[1, 2, 4, 8, 16, 32])
27+
def ncores(monkeypatch, request):
28+
"""Mocks having a machine with n cores for the purpose of
29+
computing config:build_jobs.
30+
"""
31+
def _cpu_count():
32+
return request.param
33+
34+
# Patch multiprocessing.cpu_count() to return the value we need
35+
monkeypatch.setattr(multiprocessing, 'cpu_count', _cpu_count)
36+
# Patch the configuration parts that have been cached already
37+
monkeypatch.setitem(spack.config.config_defaults['config'],
38+
'build_jobs', min(16, request.param))
39+
monkeypatch.setitem(
40+
spack.config.config.scopes, '_builtin',
41+
spack.config.InternalConfigScope(
42+
'_builtin', spack.config.config_defaults
43+
))
44+
return request.param
45+
46+
47+
@pytest.mark.parametrize('cli_args,requested', [
2748
(['-j', '24'], 24),
28-
([], multiprocessing.cpu_count())
49+
# Here we report the default if we have enough cores, as the cap
50+
# on the available number of cores will be taken care of in the test
51+
([], 16)
2952
])
30-
def test_setting_parallel_jobs(parser, cli_args, expected):
53+
def test_setting_parallel_jobs(parser, cli_args, ncores, requested):
54+
expected = min(requested, ncores)
3155
namespace = parser.parse_args(cli_args)
3256
assert namespace.jobs == expected
3357
assert spack.config.get('config:build_jobs') == expected

0 commit comments

Comments
 (0)