Skip to content

Commit 8bf8e1e

Browse files
author
Vasileios Karakasis
authored
Merge pull request #1363 from teojgo/bugfix/slurm_combined_constraints
[bugfix] Combine access and job options for slurm '--constraint'
2 parents e3ed542 + ffd51c3 commit 8bf8e1e

File tree

3 files changed

+73
-7
lines changed

3 files changed

+73
-7
lines changed

docs/manpage.rst

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,19 @@ Options controlling job submission
337337
.. option:: -J, --job-option=OPTION
338338

339339
Pass ``OPTION`` directly to the job scheduler backend.
340-
The syntax for this option is ``-J key=value``.
341-
If ``key`` starts with ``-`` or ``#``, the option will be passed verbatim to the job script.
342-
Otherwise, ReFrame will add ``-`` or ``--`` as well as the directive corresponding to the current scheduler.
343-
This option will be emitted after any options specified in the :js:attr:`access` system partition configuration parameter.
344-
340+
The syntax of ``OPTION`` is ``-J key=value``.
341+
If ``OPTION`` starts with ``-`` it will be passed verbatim to the backend job scheduler.
342+
If ``OPTION`` starts with ``#`` it will be emitted verbatim in the job script.
343+
Otherwise, ReFrame will pass ``--key=value`` or ``-k value`` (if ``key`` is a single character) to the backend scheduler.
344+
Any job options specified with this command-line option will be emitted after any job options specified in the :js:attr:`access` system partition configuration parameter.
345+
346+
Especially for the Slurm backends, constraint options, such as ``-J constraint=value``, ``-J C=value``, ``-J --constraint=value`` or ``-J -C=value``, are going to be combined with any constraint options specified in the :js:attr:`access` system partition configuration parameter.
347+
For example, if ``-C x`` is specified in the :js:attr:`access` and ``-J C=y`` is passed to the command-line, ReFrame will pass ``-C x,y`` as a constraint to the scheduler.
348+
Notice, however, that if constraint options are specified through multiple :option:`-J` options, only the last one will be considered.
349+
If you wish to completely overwrite any constraint options passed in :js:attr:`access`, you should consider passing explicitly the Slurm directive with ``-J '#SBATCH --constraint=new'``.
350+
351+
.. versionchanged:: 3.0
352+
This option has become more flexible.
345353

346354
------------------------
347355
Flexible node allocation

reframe/core/schedulers/slurm.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,35 @@ def emit_preamble(self, job):
195195
hint = 'multithread' if job.use_smt else 'nomultithread'
196196

197197
for opt in job.sched_access:
198-
preamble.append('%s %s' % (self._prefix, opt))
198+
if not opt.strip().startswith(('-C', '--constraint')):
199+
preamble.append('%s %s' % (self._prefix, opt))
200+
201+
constraints = []
202+
constraint_parser = ArgumentParser()
203+
constraint_parser.add_argument('-C', '--constraint')
204+
parsed_options, _ = constraint_parser.parse_known_args(
205+
job.sched_access)
206+
if parsed_options.constraint:
207+
constraints.append(parsed_options.constraint.strip())
208+
209+
# NOTE: Here last of the passed --constraint job options is taken
210+
# into account in order to respect the behavior of slurm.
211+
parsed_options, _ = constraint_parser.parse_known_args(job.options)
212+
if parsed_options.constraint:
213+
constraints.append(parsed_options.constraint.strip())
214+
215+
if constraints:
216+
preamble.append(
217+
self._format_option(','.join(constraints), '--constraint={0}')
218+
)
199219

200220
preamble.append(self._format_option(hint, '--hint={0}'))
201221
prefix_patt = re.compile(r'(#\w+)')
202222
for opt in job.options:
223+
if opt.strip().startswith(('-C', '--constraint')):
224+
# Constraints are already processed
225+
continue
226+
203227
if not prefix_patt.match(opt):
204228
preamble.append('%s %s' % (self._prefix, opt))
205229
else:

unittests/test_schedulers.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def exec_ctx(temp_runtime, scheduler):
6767
next(rt)
6868
if scheduler.registered_name == 'squeue':
6969
# slurm backend fulfills the functionality of the squeue backend, so
70-
# if squeue is not configured, use slurrm instead
70+
# if squeue is not configured, use slurm instead
7171
partition = (fixtures.partition_by_scheduler('squeue') or
7272
fixtures.partition_by_scheduler('slurm'))
7373
else:
@@ -370,6 +370,40 @@ def test_no_empty_lines_in_preamble(minimal_job):
370370
assert line != ''
371371

372372

373+
def test_combined_access_constraint(make_job, slurm_only):
374+
job = make_job(sched_access=['--constraint=c1'])
375+
job.options = ['-C c2,c3']
376+
prepare_job(job)
377+
with open(job.script_filename) as fp:
378+
script_content = fp.read()
379+
380+
assert re.search(r'(?m)--constraint=c1,c2,c3$', script_content)
381+
assert re.search(r'(?m)--constraint=(c1|c2,c3)$', script_content) is None
382+
383+
384+
def test_combined_access_multiple_constraints(make_job, slurm_only):
385+
job = make_job(sched_access=['--constraint=c1'])
386+
job.options = ['--constraint=c2', '-C c3']
387+
prepare_job(job)
388+
with open(job.script_filename) as fp:
389+
script_content = fp.read()
390+
391+
assert re.search(r'(?m)--constraint=c1,c3$', script_content)
392+
assert re.search(r'(?m)--constraint=(c1|c2|c3)$', script_content) is None
393+
394+
395+
def test_combined_access_verbatim_constraint(make_job, slurm_only):
396+
job = make_job(sched_access=['--constraint=c1'])
397+
job.options = ['#SBATCH --constraint=c2', '#SBATCH -C c3']
398+
prepare_job(job)
399+
with open(job.script_filename) as fp:
400+
script_content = fp.read()
401+
402+
assert re.search(r'(?m)--constraint=c1$', script_content)
403+
assert re.search(r'(?m)^#SBATCH --constraint=c2$', script_content)
404+
assert re.search(r'(?m)^#SBATCH -C c3$', script_content)
405+
406+
373407
def test_guess_num_tasks(minimal_job, scheduler):
374408
minimal_job.num_tasks = 0
375409
if scheduler.registered_name == 'local':

0 commit comments

Comments
 (0)