Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions reframe/core/launchers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
# SPDX-License-Identifier: BSD-3-Clause

import abc

import reframe.core.fields as fields
import reframe.utility.typecheck as typ
from reframe.core.meta import RegressionTestMeta
from reframe.core.warnings import user_deprecation_warning


class _JobLauncherMeta(RegressionTestMeta, abc.ABCMeta):
'''Job launcher metaclass.'''

class JobLauncher(abc.ABC):

class JobLauncher(metaclass=_JobLauncherMeta):
'''Abstract base class for job launchers.

A job launcher is the executable that actually launches a distributed
Expand All @@ -30,7 +34,28 @@ class JobLauncher(abc.ABC):
#:
#: :type: :class:`List[str]`
#: :default: ``[]``
options = fields.TypedField(typ.List[str])
options = variable(typ.List[str], value=[])

#: Optional modifier of the launcher command.
#:
#: This will be combined with the :attr:`modifier_options` and prepended to
#: the parallel launch command.
#:
#: :type: :class:`str`
#: :default: ``''``
#:
#: .. versionadded:: 4.6.0
modifier = variable(str, value='')

#: Options to be passed to the launcher :attr:`modifier`.
#:
#: If the modifier is empty, these options will be ignored.
#:
#: :type: :clas:`List[str]`
#: :default: ``[]``
#:
#: :versionadded:: 4.6.0
modifier_options = variable(typ.List[str], value=[])

def __init__(self):
self.options = []
Expand All @@ -53,7 +78,13 @@ def run_command(self, job):
:param job: a job descriptor.
:returns: the launcher command as a string.
'''
return ' '.join(self.command(job) + self.options)
cmd_tokens = []
if self.modifier:
cmd_tokens.append(self.modifier)
cmd_tokens += self.modifier_options

cmd_tokens += self.command(job) + self.options
return ' '.join(cmd_tokens)


class LauncherWrapper(JobLauncher):
Expand Down Expand Up @@ -90,8 +121,13 @@ def set_launcher(self):

'''

def __init__(self, target_launcher, wrapper_command, wrapper_options=[]):
def __init__(self, target_launcher, wrapper_command, wrapper_options=None):
super().__init__()
user_deprecation_warning("'LauncherWrapper is deprecated; "
"please use the launcher's 'modifier' and "
"'modifier_options' instead")

wrapper_options = wrapper_options or []
self.options = target_launcher.options
self._target_launcher = target_launcher
self._wrapper_command = [wrapper_command] + wrapper_options
Expand Down
8 changes: 7 additions & 1 deletion reframe/core/launchers/rsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,11 @@ def command(self, job):
return ['ssh', '-o BatchMode=yes'] + ssh_opts + [hostname]

def run_command(self, job):
cmd_tokens = []
if self.modifier:
cmd_tokens.append(self.modifier)
cmd_tokens += self.modifier_options

# self.options is processed specially above
return ' '.join(self.command(job))
cmd_tokens += self.command(job)
return ' '.join(cmd_tokens)
48 changes: 32 additions & 16 deletions unittests/test_launchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import reframe.core.launchers as launchers
from reframe.core.backends import getlauncher
from reframe.core.schedulers import Job, JobScheduler
from reframe.core.warnings import ReframeDeprecationWarning


@pytest.fixture(params=[
Expand All @@ -20,9 +21,10 @@ def launcher(request):
# convenience for the rest of the unit tests
wrapper_cls = launchers.LauncherWrapper
wrapper_cls.registered_name = 'launcherwrapper'
return wrapper_cls(
getlauncher('alps')(), 'ddt', ['--offline']
)
with pytest.warns(ReframeDeprecationWarning):
return wrapper_cls(
getlauncher('alps')(), 'ddt', ['--offline']
)

return getlauncher(request.param)()

Expand Down Expand Up @@ -154,38 +156,52 @@ def test_run_command(job):
assert command == 'lrun -N 2 -T 2 -M "-gpu" --foo'


def test_run_command_minimal(minimal_job):
@pytest.fixture(params=['modifiers', 'plain'])
def use_modifiers(request):
return request.param == 'modifiers'


def test_run_command_minimal(minimal_job, use_modifiers):
launcher_name = type(minimal_job.launcher).registered_name
# This is relevant only for the srun launcher, because it may
# run in different platforms with older versions of Slurm
minimal_job.launcher.use_cpus_per_task = True
if use_modifiers and launcher_name != 'launcherwrapper':
minimal_job.launcher.modifier = 'ddt'
minimal_job.launcher.modifier_options = ['--offline']
prefix = 'ddt --offline'
if launcher_name != 'local':
prefix += ' '
else:
prefix = ''

command = minimal_job.launcher.run_command(minimal_job)
if launcher_name == 'alps':
assert command == 'aprun -n 1 --foo'
assert command == f'{prefix}aprun -n 1 --foo'
elif launcher_name == 'launcherwrapper':
assert command == 'ddt --offline aprun -n 1 --foo'
elif launcher_name == 'local':
assert command == ''
assert command == f'{prefix}'
elif launcher_name == 'mpiexec':
assert command == 'mpiexec -n 1 --foo'
assert command == f'{prefix}mpiexec -n 1 --foo'
elif launcher_name == 'mpirun':
assert command == 'mpirun -np 1 --foo'
assert command == f'{prefix}mpirun -np 1 --foo'
elif launcher_name == 'srun':
assert command == 'srun --foo'
assert command == f'{prefix}srun --foo'
elif launcher_name == 'srunalloc':
assert command == ('srun '
assert command == (f'{prefix}srun '
'--job-name=fake_job '
'--ntasks=1 '
'--foo')
elif launcher_name == 'ssh':
assert command == 'ssh -o BatchMode=yes --foo host'
assert command == f'{prefix}ssh -o BatchMode=yes --foo host'
elif launcher_name in ('clush', 'pdsh'):
assert command == f'{launcher_name} -w host --foo'
assert command == f'{prefix}{launcher_name} -w host --foo'
elif launcher_name == 'upcrun':
assert command == 'upcrun -n 1 --foo'
assert command == f'{prefix}upcrun -n 1 --foo'
elif launcher_name == 'upcxx-run':
assert command == 'upcxx-run -n 1 --foo'
assert command == f'{prefix}upcxx-run -n 1 --foo'
elif launcher_name == 'lrun':
assert command == 'lrun -N 1 -T 1 --foo'
assert command == f'{prefix}lrun -N 1 -T 1 --foo'
elif launcher_name == 'lrun-gpu':
assert command == 'lrun -N 1 -T 1 -M "-gpu" --foo'
assert command == f'{prefix}lrun -N 1 -T 1 -M "-gpu" --foo'