Skip to content

Commit 43da769

Browse files
committed
add --max-parallel configuration option to control maximum number of cores to use, set to 16 by default
1 parent eaa6205 commit 43da769

File tree

5 files changed

+92
-13
lines changed

5 files changed

+92
-13
lines changed

easybuild/framework/easyblock.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2447,7 +2447,22 @@ def set_parallel(self):
24472447
else:
24482448
par = min(int(par), int(cfg_par))
24492449

2450-
par = det_parallelism(par=par, maxpar=self.cfg['max_parallel'])
2450+
# --max-parallel specifies global maximum for parallelism
2451+
max_par_cfg = int(build_option('max_parallel'))
2452+
# note: 'max_parallel' and 'maxparallel; are the same easyconfig parameter,
2453+
# since 'max_parallel' is an alternative name for 'maxparallel'
2454+
max_par = self.cfg['max_parallel']
2455+
# take into account that False is a valid value for max_parallel
2456+
if max_par is False:
2457+
max_par = 1
2458+
# if max_parallel is not specified in easyconfig, we take the global value
2459+
if max_par is None:
2460+
max_par = max_par_cfg
2461+
# take minimum value if both are specified
2462+
else:
2463+
max_par = min(int(max_par), max_par_cfg)
2464+
2465+
par = det_parallelism(par=par, maxpar=max_par)
24512466
self.log.info(f"Setting parallelism: {par}")
24522467
self.cfg.parallel = par
24532468

easybuild/tools/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
DEFAULT_JOB_EB_CMD = 'eb'
101101
DEFAULT_LOGFILE_FORMAT = ("easybuild", "easybuild-%(name)s-%(version)s-%(date)s.%(time)s.log")
102102
DEFAULT_MAX_FAIL_RATIO_PERMS = 0.5
103+
DEFAULT_MAX_PARALLEL = 16
103104
DEFAULT_MINIMAL_BUILD_ENV = 'CC:gcc,CXX:g++'
104105
DEFAULT_MNS = 'EasyBuildMNS'
105106
DEFAULT_MODULE_SYNTAX = 'Lua'
@@ -395,6 +396,9 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
395396
DEFAULT_MAX_FAIL_RATIO_PERMS: [
396397
'max_fail_ratio_adjust_permissions',
397398
],
399+
DEFAULT_MAX_PARALLEL: [
400+
'max_parallel',
401+
],
398402
DEFAULT_MINIMAL_BUILD_ENV: [
399403
'minimal_build_env',
400404
],

easybuild/tools/options.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,15 @@
6767
from easybuild.tools.config import DEFAULT_ENV_FOR_SHEBANG, DEFAULT_ENVVAR_USERS_MODULES
6868
from easybuild.tools.config import DEFAULT_FORCE_DOWNLOAD, DEFAULT_INDEX_MAX_AGE, DEFAULT_JOB_BACKEND
6969
from easybuild.tools.config import DEFAULT_JOB_EB_CMD, DEFAULT_LOGFILE_FORMAT, DEFAULT_MAX_FAIL_RATIO_PERMS
70-
from easybuild.tools.config import DEFAULT_MINIMAL_BUILD_ENV, DEFAULT_MNS, DEFAULT_MODULE_SYNTAX, DEFAULT_MODULES_TOOL
70+
from easybuild.tools.config import DEFAULT_MAX_PARALLEL, DEFAULT_MINIMAL_BUILD_ENV, DEFAULT_MNS
71+
from easybuild.tools.config import DEFAULT_MOD_SEARCH_PATH_HEADERS, DEFAULT_MODULE_SYNTAX, DEFAULT_MODULES_TOOL
7172
from easybuild.tools.config import DEFAULT_MODULECLASSES, DEFAULT_PATH_SUBDIRS, DEFAULT_PKG_RELEASE, DEFAULT_PKG_TOOL
72-
from easybuild.tools.config import DEFAULT_MOD_SEARCH_PATH_HEADERS, MOD_SEARCH_PATH_HEADERS
7373
from easybuild.tools.config import DEFAULT_PKG_TYPE, DEFAULT_PNS, DEFAULT_PREFIX, DEFAULT_EXTRA_SOURCE_URLS
7474
from easybuild.tools.config import DEFAULT_REPOSITORY, DEFAULT_WAIT_ON_LOCK_INTERVAL, DEFAULT_WAIT_ON_LOCK_LIMIT
7575
from easybuild.tools.config import DEFAULT_PR_TARGET_ACCOUNT, DEFAULT_FILTER_RPATH_SANITY_LIBS
7676
from easybuild.tools.config import EBROOT_ENV_VAR_ACTIONS, ERROR, FORCE_DOWNLOAD_CHOICES, GENERAL_CLASS, IGNORE
7777
from easybuild.tools.config import JOB_DEPS_TYPE_ABORT_ON_ERROR, JOB_DEPS_TYPE_ALWAYS_RUN, LOADED_MODULES_ACTIONS
78-
from easybuild.tools.config import LOCAL_VAR_NAMING_CHECK_WARN, LOCAL_VAR_NAMING_CHECKS
78+
from easybuild.tools.config import LOCAL_VAR_NAMING_CHECK_WARN, LOCAL_VAR_NAMING_CHECKS, MOD_SEARCH_PATH_HEADERS
7979
from easybuild.tools.config import OUTPUT_STYLE_AUTO, OUTPUT_STYLES, WARN, build_option
8080
from easybuild.tools.config import get_pretend_installpath, init, init_build_options, mk_full_default_path
8181
from easybuild.tools.config import BuildOptions, ConfigurationVariables
@@ -475,6 +475,8 @@ def override_options(self):
475475
None, 'store_true', True),
476476
'max-fail-ratio-adjust-permissions': ("Maximum ratio for failures to allow when adjusting permissions",
477477
'float', 'store', DEFAULT_MAX_FAIL_RATIO_PERMS),
478+
'max-parallel': ("Specify maximum level of parallelism that should be used during build procedure",
479+
'int', 'store', DEFAULT_MAX_PARALLEL),
478480
'minimal-build-env': ("Minimal build environment to define when using system toolchain, "
479481
"specified as a comma-separated list that defines a mapping between name of "
480482
"environment variable and its value separated by a colon (':')",
@@ -496,9 +498,10 @@ def override_options(self):
496498
'output-style': ("Control output style; auto implies using Rich if available to produce rich output, "
497499
"with fallback to basic colored output",
498500
'choice', 'store', OUTPUT_STYLE_AUTO, OUTPUT_STYLES),
499-
'parallel': ("Specify (maximum) level of parallelism used during build procedure "
500-
"(actual value is determined by available cores + 'max_parallel' easyconfig parameter)",
501-
'int', 'store', 16),
501+
'parallel': ("Specify level of parallelism that should be used during build procedure, "
502+
"(bypasses auto-detection of number of available cores; "
503+
"actual value is determined by this value + 'max_parallel' easyconfig parameter)",
504+
'int', 'store', None),
502505
'parallel-extensions-install': ("Install list of extensions in parallel (if supported)",
503506
None, 'store_true', False),
504507
'pre-create-installdir': ("Create installation directory before submitting build jobs",

test/framework/easyblock.py

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from easybuild.framework.extensioneasyblock import ExtensionEasyBlock
5050
from easybuild.tools import LooseVersion, config
5151
from easybuild.tools.build_log import EasyBuildError
52-
from easybuild.tools.config import get_module_syntax, update_build_option
52+
from easybuild.tools.config import get_module_syntax
5353
from easybuild.tools.environment import modify_env
5454
from easybuild.tools.filetools import change_dir, copy_dir, copy_file, mkdir, read_file, remove_dir, remove_file
5555
from easybuild.tools.filetools import symlink, verify_checksum, write_file
@@ -2529,7 +2529,7 @@ def test_parallel(self):
25292529
write_file(toy_ec5, toytxt + "\nmaxparallel = False")
25302530

25312531
# default: parallelism is derived from # available cores + ulimit
2532-
# Note that maxparallel has a default of 16, so we need a lower auto_parallel value here
2532+
# Note that --max-parallel has a default of 16, so we need a lower auto_parallel value here
25332533
auto_parallel = 16 - 4 # Using + 3 below which must still be less
25342534
st.det_parallelism._default_parallelism = auto_parallel
25352535

@@ -2565,7 +2565,10 @@ def test_parallel(self):
25652565
buildopt_parallel = 11
25662566
# When build option is given the auto-parallelism is ignored. Verify by setting it very low
25672567
st.det_parallelism._default_parallelism = 2
2568-
init_config(build_options={'parallel': str(buildopt_parallel), 'validate': False})
2568+
init_config(build_options={
2569+
'parallel': str(buildopt_parallel),
2570+
'validate': False,
2571+
})
25692572

25702573
test_cases = {
25712574
'': buildopt_parallel,
@@ -2583,6 +2586,61 @@ def test_parallel(self):
25832586
'parallel = 8\nmaxparallel = False': 1,
25842587
}
25852588

2589+
for txt, expected in test_cases.items():
2590+
with self.subTest(ec_params=txt):
2591+
self.contents = toytxt + '\n' + txt
2592+
self.writeEC()
2593+
with self.temporarily_allow_deprecated_behaviour(), self.mocked_stdout_stderr():
2594+
test_eb = EasyBlock(EasyConfig(self.eb_file))
2595+
test_eb.post_init()
2596+
self.assertEqual(test_eb.cfg.parallel, expected)
2597+
with self.temporarily_allow_deprecated_behaviour(), self.mocked_stdout_stderr():
2598+
self.assertEqual(test_eb.cfg['parallel'], expected)
2599+
2600+
# re-check when --max-parallel is used instead
2601+
buildopt_max_parallel = 8
2602+
st.det_parallelism._default_parallelism = 16
2603+
init_config(build_options={
2604+
'max_parallel': buildopt_max_parallel,
2605+
'validate': False,
2606+
})
2607+
2608+
test_cases = {
2609+
'': buildopt_max_parallel,
2610+
'parallel = False': 1,
2611+
'parallel = 1': 1,
2612+
'parallel = 6': 6,
2613+
# --max-parallel value limits max. parallelism, so only 8 cores will be used when 'parallel = 10' is used
2614+
f'parallel = {buildopt_max_parallel + 2}': buildopt_max_parallel,
2615+
'maxparallel = False': 1,
2616+
'maxparallel = 1': 1,
2617+
'maxparallel = 6': 6,
2618+
# minimum of 'maxparallel' easyconfig parameter and --max-parallel configuration option is used
2619+
f'maxparallel = {buildopt_max_parallel + 2}': buildopt_max_parallel,
2620+
'parallel = 8\nmaxparallel = 6': 6,
2621+
'parallel = 8\nmaxparallel = 9': 8,
2622+
'parallel = False\nmaxparallel = 6': 1,
2623+
'parallel = 8\nmaxparallel = False': 1,
2624+
}
2625+
2626+
for txt, expected in test_cases.items():
2627+
with self.subTest(ec_params=txt):
2628+
self.contents = toytxt + '\n' + txt
2629+
self.writeEC()
2630+
with self.temporarily_allow_deprecated_behaviour(), self.mocked_stdout_stderr():
2631+
test_eb = EasyBlock(EasyConfig(self.eb_file))
2632+
test_eb.post_init()
2633+
self.assertEqual(test_eb.cfg.parallel, expected)
2634+
with self.temporarily_allow_deprecated_behaviour(), self.mocked_stdout_stderr():
2635+
self.assertEqual(test_eb.cfg['parallel'], expected)
2636+
2637+
# re-check when both --max-parallel and --parallel are used (--max-parallel wins)
2638+
init_config(build_options={
2639+
'max_parallel': buildopt_max_parallel,
2640+
'parallel': buildopt_parallel,
2641+
'validate': False,
2642+
})
2643+
25862644
for txt, expected in test_cases.items():
25872645
with self.subTest(ec_params=txt):
25882646
self.contents = toytxt + '\n' + txt
@@ -2617,13 +2675,13 @@ def test_parallel(self):
26172675
self.writeEC()
26182676
with self.temporarily_allow_deprecated_behaviour(), self.mocked_stdout_stderr():
26192677
test_eb = EasyBlock(EasyConfig(self.eb_file))
2620-
parallel = buildopt_parallel - 2
2678+
parallel = buildopt_max_parallel - 2
26212679
test_eb.cfg['parallel'] = parallel # Old Easyblocks might change that before the ready step
26222680
test_eb.post_init()
26232681
self.assertEqual(test_eb.cfg.parallel, parallel)
26242682
self.assertEqual(test_eb.cfg['parallel'], parallel)
26252683
# Afterwards it also gets reflected directly ignoring maxparallel
2626-
parallel = buildopt_parallel * 3
2684+
parallel = buildopt_max_parallel * 3
26272685
test_eb.cfg['parallel'] = parallel
26282686
self.assertEqual(test_eb.cfg.parallel, parallel)
26292687
self.assertEqual(test_eb.cfg['parallel'], parallel)

test/framework/systemtools.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939

4040
import easybuild.tools.systemtools as st
4141
from easybuild.tools.build_log import EasyBuildError
42-
from easybuild.tools.config import update_build_option
4342
from easybuild.tools.filetools import adjust_permissions, read_file, symlink, which, write_file
4443
from easybuild.tools.run import RunShellCmdResult, run_shell_cmd
4544
from easybuild.tools.systemtools import CPU_ARCHITECTURES, AARCH32, AARCH64, POWER, X86_64

0 commit comments

Comments
 (0)