Repository: reframe-hpc/reframe

Issue:
Change of behaviour in Slurm version 22.05
From the release notes: https://slurm.schedmd.com/news.html
```
RELEASE NOTES FOR SLURM VERSION 22.05
...
-- srun will no longer read in SLURM_CPUS_PER_TASK. This means you will
    implicitly have to specify --cpus-per-task on your srun calls, or set the
    new SRUN_CPUS_PER_TASK env var to accomplish the same thing.
```

To achieve the same behavior as before we need either to pass explicitly `--cpus-per-task=$SLURM_CPUS_PER_TASK` or set the new `SRUN_CPUS_PER_TASK` env var.
```
export SRUN_CPUS_PER_TASK=$SLURM_CPUS_PER_TASK
```

As far as I understand we can pass the option for older version of slurm as well so there is no need to check for the version.

Discussion:

Patch:
diff --git a/reframe/core/launchers/mpi.py b/reframe/core/launchers/mpi.py
index 633a1c05..1a936c99 100644
--- a/reframe/core/launchers/mpi.py
+++ b/reframe/core/launchers/mpi.py
@@ -3,15 +3,52 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
+import semver
+import re
+
+import reframe.utility.osext as osext
 from reframe.core.backends import register_launcher
 from reframe.core.launchers import JobLauncher
+from reframe.core.logging import getlogger
 from reframe.utility import seconds_to_hms
 
 
 @register_launcher('srun')
 class SrunLauncher(JobLauncher):
+    def __init__(self):
+        self.options = []
+        self.use_cpus_per_task = True
+        try:
+            out = osext.run_command('srun --version')
+            match = re.search('slurm (\d+)\.(\d+)\.(\d+)', out.stdout)
+            if match:
+                # We cannot pass to semver strings like 22.05.1 directly
+                # because it is not a valid version string for semver. We
+                # need to remove all the leading zeros.
+                slurm_version = (
+                    semver.VersionInfo(
+                        match.group(1), match.group(2), match.group(3)
+                    )
+                )
+                if slurm_version < semver.VersionInfo(22, 5, 0):
+                    self.use_cpus_per_task = False
+            else:
+                getlogger().warning(
+                    'could not get version of Slurm, --cpus-per-task will be '
+                    'set according to the num_cpus_per_task attribute'
+                )
+        except Exception:
+            getlogger().warning(
+                'could not get version of Slurm, --cpus-per-task will be set '
+                'according to the num_cpus_per_task attribute'
+            )
+
     def command(self, job):
-        return ['srun']
+        ret = ['srun']
+        if self.use_cpus_per_task and job.num_cpus_per_task:
+            ret.append(f'--cpus-per-task={job.num_cpus_per_task}')
+
+        return ret
 
 
 @register_launcher('ibrun')


Test patch:
diff --git a/unittests/test_launchers.py b/unittests/test_launchers.py
index 66cd9753..987517b0 100644
--- a/unittests/test_launchers.py
+++ b/unittests/test_launchers.py
@@ -104,6 +104,9 @@ def minimal_job(make_job, launcher):
 
 def test_run_command(job):
     launcher_name = type(job.launcher).registered_name
+    # This is relevant only for the srun launcher, because it may
+    # run in different platforms with older versions of Slurm
+    job.launcher.use_cpus_per_task = True
     command = job.launcher.run_command(job)
     if launcher_name == 'alps':
         assert command == 'aprun -n 4 -N 2 -d 2 -j 0 --foo'
@@ -116,7 +119,7 @@ def test_run_command(job):
     elif launcher_name == 'mpirun':
         assert command == 'mpirun -np 4 --foo'
     elif launcher_name == 'srun':
-        assert command == 'srun --foo'
+        assert command == 'srun --cpus-per-task=2 --foo'
     elif launcher_name == 'srunalloc':
         assert command == ('srun '
                            '--job-name=fake_job '
@@ -147,6 +150,9 @@ def test_run_command(job):
 
 def test_run_command_minimal(minimal_job):
     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
     command = minimal_job.launcher.run_command(minimal_job)
     if launcher_name == 'alps':
         assert command == 'aprun -n 1 --foo'