diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..0e8db89 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,55 @@ +name: Lint and syntax checks + +on: [push, pull_request] + +jobs: + pylint: + runs-on: ubuntu-latest + name: pylint + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + pip install reframe-hpc + - name: Analysing the code with pylint + run: | + pylint $(git ls-files 'tests/*.py') + + flake8-lint: + runs-on: ubuntu-latest + name: flake8 + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: + - name: Check out source repository + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: flake8 Lint + uses: py-actions/flake8@v2 + with: + max-line-length: "120" + path: "tests" + plugins: "flake8-bugbear flake8-pyproject" + + python-black: + name: Python Black + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Python Black + uses: cytopia/docker-black@0.8 + with: + path: 'tests/' diff --git a/configuration/archer2-4c_settings.py b/configuration/archer2-4c_settings.py deleted file mode 100644 index 538ca01..0000000 --- a/configuration/archer2-4c_settings.py +++ /dev/null @@ -1,117 +0,0 @@ -site_configuration = { - 'systems': [ - { - 'name': 'archer2', - 'descr': 'ARCHER2 4-cabinet', - 'hostnames': ['uan','ln'], - 'modules_system': 'tmod4', - 'partitions': [ - { - 'name': 'login', - 'descr': 'Login nodes', - 'scheduler': 'local', - 'launcher': 'local', - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - }, - { - 'name': 'compute', - 'descr': 'Compute nodes', - 'scheduler': 'slurm', - 'launcher': 'srun', -# 'access': ['--partition=standard','--qos=standard','--distribution=block:block'], - 'access': [ - '--hint=nomultithread', - '--distribution=block:block', - '--partition=standard', - '--qos=short', - '--reservation=shortqos' - ], - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - 'max_jobs': 16 - } - ] - } - ], - 'environments': [ - { - 'name': 'PrgEnv-gnu', - 'modules': [ - { - 'name': '/etc/cray-pe.d/PrgEnv-gnu', - 'path': '/etc/cray-pe.d/PrgEnv-gnu', - 'collection': True - } - ], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-cray', - 'modules': [ - { - 'name': '/etc/cray-pe.d/PrgEnv-cray', - 'path': '/etc/cray-pe.d/PrgEnv-cray', - 'collection': True - } - ], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-aocc', - 'modules': [ - { - 'name': '/etc/cray-pe.d/PrgEnv-aocc', - 'path': '/etc/cray-pe.d/PrgEnv-aocc', - 'collection': True - } - ], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - ], - 'logging': [ - { - 'level': 'debug', - 'handlers': [ - { - 'type': 'stream', - 'name': 'stdout', - 'level': 'info', - 'format': '%(message)s' - }, - { - 'type': 'file', - 'name': 'reframe.log', - 'level': 'debug', - 'format': '[%(asctime)s] %(levelname)s: %(check_info)s: %(message)s', # noqa: E501 - 'append': False - } - ], - 'handlers_perflog': [ - { - 'type': 'filelog', - 'prefix': '%(check_system)s/%(check_partition)s', - 'level': 'info', - 'format': ( - '%(check_job_completion_time)s|reframe %(version)s|' - '%(check_info)s|jobid=%(check_jobid)s|' - '%(check_perf_var)s=%(check_perf_value)s|' - 'ref=%(check_perf_ref)s ' - '(l=%(check_perf_lower_thres)s, ' - 'u=%(check_perf_upper_thres)s)|' - '%(check_perf_unit)s' - ), - 'append': True - } - ] - } - ], -} - diff --git a/configuration/archer2-tds_settings.py b/configuration/archer2-tds_settings.py deleted file mode 100644 index 037291b..0000000 --- a/configuration/archer2-tds_settings.py +++ /dev/null @@ -1,106 +0,0 @@ -site_configuration = { - 'systems': [ - { - 'name': 'archer2', - 'descr': 'ARCHER2 TDS', - 'hostnames': ['uan','ln','dvn'], - 'modules_system': 'lmod', - 'partitions': [ - { - 'name': 'login', - 'descr': 'Login nodes', - 'scheduler': 'local', - 'launcher': 'local', - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - }, - { - 'name': 'compute', - 'descr': 'Compute nodes', - 'scheduler': 'slurm', - 'launcher': 'srun', - 'access': ['--hint=nomultithread','--distribution=block:block','--partition=workq','--qos=normal'], - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - 'max_jobs': 16 - } - ] - } - ], - 'environments': [ - { - 'name': 'PrgEnv-gnu', - 'modules': ['PrgEnv-gnu'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-cray', - 'modules': ['PrgEnv-cray'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-aocc', - 'modules': ['PrgEnv-aocc'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - ], - 'logging': [ - { - 'level': 'debug', - 'handlers': [ - { - 'type': 'stream', - 'name': 'stdout', - 'level': 'info', - 'format': '%(message)s' - }, - { - 'type': 'file', - 'name': 'reframe.out', - 'level': 'info', - 'format': '[%(asctime)s] %(check_info)s: %(message)s', - 'append': True - }, - { - 'type': 'file', - 'name': 'reframe.log', - 'level': 'debug', - 'format': '[%(asctime)s] %(levelname)s %(levelno)s: %(check_info)s: %(message)s', # noqa: E501 - 'append': False - } - ], - 'handlers_perflog': [ - { - 'type': 'file', - 'name': 'reframe_perf.out', - 'level': 'info', - 'format': '[%(asctime)s] %(check_info)s: %(check_perf_var)s=%(check_perf_value)s (ref=%(check_perf_ref)s;l=%(check_perf_lower_thres)s;u=%(check_perf_upper_thres)s)) %(check_perf_unit)s', - 'append': True - }, - { - 'type': 'filelog', - 'prefix': '%(check_system)s/%(check_partition)s', - 'level': 'info', - 'format': ( - '%(check_job_completion_time)s|reframe %(version)s|' - '%(check_info)s|jobid=%(check_jobid)s|' - '%(check_perf_var)s=%(check_perf_value)s|' - 'ref=%(check_perf_ref)s ' - '(l=%(check_perf_lower_thres)s, ' - 'u=%(check_perf_upper_thres)s)|' - '%(check_perf_unit)s' - ), - 'append': True - } - ] - } - ], -} - diff --git a/configuration/archer2.py b/configuration/archer2.py new file mode 100644 index 0000000..1ec2203 --- /dev/null +++ b/configuration/archer2.py @@ -0,0 +1,208 @@ +"""ARCHER2 settings""" + +from reframe.core.backends import register_launcher +from reframe.core.launchers import JobLauncher + + +@register_launcher("torchrun") +class TorchRunLauncher(JobLauncher): + """Launcher for Torch run""" + + def command(self, job): + return ["torchrun", "--nproc_per_node=4"] + + +site_configuration = { + "systems": [ + { + "name": "archer2", + "descr": "ARCHER2", + "hostnames": ["uan", "ln", "dvn"], + "modules_system": "lmod", + "partitions": [ + { + "name": "login", + "descr": "Login nodes", + "scheduler": "local", + "launcher": "local", + "environs": ["Default", "PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + }, + { + "name": "compute", + "descr": "Compute nodes", + "scheduler": "slurm", + "launcher": "srun", + "access": [ + "--hint=nomultithread", + "--distribution=block:block", + "--partition=standard", + "--qos=standard", + ], + "environs": ["PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + "max_jobs": 16, + "processor": { + "num_cpus": 128, + "num_cpus_per_socket": 64, + "num_sockets": 2, + }, + }, + { + "name": "compute-gpu", + "descr": "Compute nodes with AMD GPUs", + "features": ["gpu"], + "scheduler": "slurm", + "launcher": "srun", + "access": ["--partition=gpu"], + "environs": [ + "rocm-PrgEnv-gnu", + "rocm-PrgEnv-cray", + "rocm-PrgEnv-aocc", + ], + "resources": [ + {"name": "qos", "options": ["--qos={qos}"]}, + { + "name": "gpu", + "options": ["--gres=gpu:{num_gpus_per_node}"], + }, + ], + }, + { + "name": "compute-gpu-torch", + "descr": "Compute nodes with AMD GPUs", + "features": ["gpu"], + "scheduler": "slurm", + "launcher": "torchrun", + "access": ["--partition=gpu"], + "environs": [ + "rocm-PrgEnv-gnu", + "rocm-PrgEnv-cray", + "rocm-PrgEnv-aocc", + ], + "resources": [ + {"name": "qos", "options": ["--qos={qos}"]}, + { + "name": "gpu", + "options": ["--gres=gpu:{num_gpus_per_node}"], + }, + ], + }, + ], + } + ], + "environments": [ + { + "name": "PrgEnv-gnu", + "modules": ["PrgEnv-gnu"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-cray", + "modules": ["PrgEnv-cray"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-aocc", + "modules": ["PrgEnv-aocc"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "rocm-PrgEnv-gnu", + "modules": [ + "PrgEnv-gnu", + "rocm", + "craype-accel-amd-gfx90a", + "craype-x86-milan", + ], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "rocm-PrgEnv-cray", + "modules": ["PrgEnv-cray"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "rocm-PrgEnv-aocc", + "modules": ["PrgEnv-aocc"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "Default", + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + ], + "logging": [ + { + "level": "debug", + "perflog_compat": True, + "handlers": [ + { + "type": "stream", + "name": "stdout", + "level": "info", + "format": "%(message)s", + }, + { + "type": "file", + "name": "reframe.out", + "level": "info", + "format": "[%(asctime)s] %(check_info)s: %(message)s", + "append": True, + }, + { + "type": "file", + "name": "reframe.log", + "level": "debug", + "format": ("[%(asctime)s] %(levelname)s %(levelno)s: %(check_info)s: %(message)s"), + "append": False, + }, + ], + "handlers_perflog": [ + { + "type": "file", + "name": "reframe_perf.out", + "level": "info", + "perflog_compat": True, + "format": ( + "[%(asctime)s] %(check_info)s: %(check_perf_var)s=%(check_perf_value)s " + "(ref=%(check_perf_ref)s;l=%(check_perf_lower_thres)s;u=%(check_perf_upper_thres)s)) " + "%(check_perf_unit)s" + ), + "append": True, + }, + { + "type": "filelog", + "prefix": "%(check_system)s/%(check_partition)s", + "level": "info", + "format": ( + "%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|" + "%(check_perf_var)s|" + "%(check_perf_value)s %(check_perf_unit)s|" + "(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|" + ), + "append": True, + }, + ], + } + ], +} diff --git a/configuration/archer2_4c.py b/configuration/archer2_4c.py new file mode 100644 index 0000000..0d4ae1f --- /dev/null +++ b/configuration/archer2_4c.py @@ -0,0 +1,117 @@ +"""ARCHER2 4 cabinet""" + +site_configuration = { + "systems": [ + { + "name": "archer2", + "descr": "ARCHER2 4-cabinet", + "hostnames": ["uan", "ln"], + "modules_system": "tmod4", + "partitions": [ + { + "name": "login", + "descr": "Login nodes", + "scheduler": "local", + "launcher": "local", + "environs": ["PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + }, + { + "name": "compute", + "descr": "Compute nodes", + "scheduler": "slurm", + "launcher": "srun", + "access": [ + "--hint=nomultithread", + "--distribution=block:block", + "--partition=standard", + "--qos=short", + "--reservation=shortqos", + ], + "environs": ["PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + "max_jobs": 16, + }, + ], + } + ], + "environments": [ + { + "name": "PrgEnv-gnu", + "modules": [ + { + "name": "/etc/cray-pe.d/PrgEnv-gnu", + "path": "/etc/cray-pe.d/PrgEnv-gnu", + "collection": True, + } + ], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-cray", + "modules": [ + { + "name": "/etc/cray-pe.d/PrgEnv-cray", + "path": "/etc/cray-pe.d/PrgEnv-cray", + "collection": True, + } + ], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-aocc", + "modules": [ + { + "name": "/etc/cray-pe.d/PrgEnv-aocc", + "path": "/etc/cray-pe.d/PrgEnv-aocc", + "collection": True, + } + ], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + ], + "logging": [ + { + "level": "debug", + "handlers": [ + { + "type": "stream", + "name": "stdout", + "level": "info", + "format": "%(message)s", + }, + { + "type": "file", + "name": "reframe.log", + "level": "debug", + "format": "[%(asctime)s] %(levelname)s: %(check_info)s: %(message)s", # noqa: E501 + "append": False, + }, + ], + "handlers_perflog": [ + { + "type": "filelog", + "prefix": "%(check_system)s/%(check_partition)s", + "level": "info", + "format": ( + "%(check_job_completion_time)s|reframe %(version)s|" + "%(check_info)s|jobid=%(check_jobid)s|" + "%(check_perf_var)s=%(check_perf_value)s|" + "ref=%(check_perf_ref)s " + "(l=%(check_perf_lower_thres)s, " + "u=%(check_perf_upper_thres)s)|" + "%(check_perf_unit)s" + ), + "append": True, + } + ], + } + ], +} diff --git a/configuration/archer2_settings.py b/configuration/archer2_settings.py deleted file mode 100644 index 5ff74f0..0000000 --- a/configuration/archer2_settings.py +++ /dev/null @@ -1,174 +0,0 @@ -from reframe.core.backends import register_launcher -from reframe.core.launchers import JobLauncher - - -@register_launcher('torchrun') -class TorchRunLauncher(JobLauncher): - def command(self, job): - return ['torchrun', f'--nproc_per_node=4'] - -site_configuration = { - 'systems': [ - { - 'name': 'archer2', - 'descr': 'ARCHER2', - 'hostnames': ['uan','ln','dvn'], - 'modules_system': 'lmod', - 'partitions': [ - { - 'name': 'login', - 'descr': 'Login nodes', - 'scheduler': 'local', - 'launcher': 'local', - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - }, - { - 'name': 'compute', - 'descr': 'Compute nodes', - 'scheduler': 'slurm', - 'launcher': 'srun', - 'access': ['--hint=nomultithread','--distribution=block:block','--partition=standard','--qos=standard'], - 'environs': ['PrgEnv-gnu','PrgEnv-cray','PrgEnv-aocc'], - 'max_jobs': 16, - "processor": { - "num_cpus": 128, - "num_cpus_per_socket": 64, - "num_sockets": 2, - }, - }, - { - "name": "compute-gpu", - "descr": "Compute nodes with AMD GPUs", - "scheduler": "slurm", - 'launcher': 'srun', - 'access': ['--partition=gpu'], - 'environs': ['rocm-PrgEnv-gnu','rocm-PrgEnv-cray','rocm-PrgEnv-aocc'], - "resources": [ - {"name": "qos", "options": ["--qos={qos}"]}, - { - "name": "gpu", - "options": ["--gres=gpu:{num_gpus_per_node}"], - }, - ], - }, - { - "name": "compute-gpu-torch", - "descr": "Compute nodes with AMD GPUs", - "scheduler": "slurm", - 'launcher': 'torchrun', - 'access': ['--partition=gpu'], - 'environs': ['rocm-PrgEnv-gnu','rocm-PrgEnv-cray','rocm-PrgEnv-aocc'], - "resources": [ - {"name": "qos", "options": ["--qos={qos}"]}, - { - "name": "gpu", - "options": ["--gres=gpu:{num_gpus_per_node}"], - }, - ], - } - ] - } - ], - 'environments': [ - { - 'name': 'PrgEnv-gnu', - 'modules': ['PrgEnv-gnu'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-cray', - 'modules': ['PrgEnv-cray'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'PrgEnv-aocc', - 'modules': ['PrgEnv-aocc'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'rocm-PrgEnv-gnu', - 'modules': ['PrgEnv-gnu', "rocm", "craype-accel-amd-gfx90a", "craype-x86-milan"], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'rocm-PrgEnv-cray', - 'modules': ['PrgEnv-cray'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - { - 'name': 'rocm-PrgEnv-aocc', - 'modules': ['PrgEnv-aocc'], - 'cc': 'cc', - 'cxx': 'CC', - 'ftn': 'ftn', - 'target_systems': ['archer2'] - }, - ], - 'logging': [ - { - 'level': 'debug', - "perflog_compat": True, - 'handlers': [ - { - 'type': 'stream', - 'name': 'stdout', - 'level': 'info', - 'format': '%(message)s' - }, - { - 'type': 'file', - 'name': 'reframe.out', - 'level': 'info', - 'format': '[%(asctime)s] %(check_info)s: %(message)s', - 'append': True - }, - { - 'type': 'file', - 'name': 'reframe.log', - 'level': 'debug', - 'format': '[%(asctime)s] %(levelname)s %(levelno)s: %(check_info)s: %(message)s', # noqa: E501 - 'append': False - } - ], - 'handlers_perflog': [ - { - 'type': 'file', - 'name': 'reframe_perf.out', - 'level': 'info', - "perflog_compat": True, - 'format': '[%(asctime)s] %(check_info)s: %(check_perf_var)s=%(check_perf_value)s (ref=%(check_perf_ref)s;l=%(check_perf_lower_thres)s;u=%(check_perf_upper_thres)s)) %(check_perf_unit)s', - 'append': True - }, - { - 'type': 'filelog', - 'prefix': '%(check_system)s/%(check_partition)s', - 'level': 'info', - 'format': ( - '%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|' - '%(check_perf_var)s|' - '%(check_perf_value)s %(check_perf_unit)s|' - '(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|' - ), - - 'append': True - }, - ] - } - ], -} - diff --git a/configuration/archer2_tds.py b/configuration/archer2_tds.py new file mode 100644 index 0000000..3157351 --- /dev/null +++ b/configuration/archer2_tds.py @@ -0,0 +1,116 @@ +"""ARCHER2 TDS settings""" + +site_configuration = { + "systems": [ + { + "name": "archer2", + "descr": "ARCHER2 TDS", + "hostnames": ["uan", "ln", "dvn"], + "modules_system": "lmod", + "partitions": [ + { + "name": "login", + "descr": "Login nodes", + "scheduler": "local", + "launcher": "local", + "environs": ["PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + }, + { + "name": "compute", + "descr": "Compute nodes", + "scheduler": "slurm", + "launcher": "srun", + "access": [ + "--hint=nomultithread", + "--distribution=block:block", + "--partition=workq", + "--qos=normal", + ], + "environs": ["PrgEnv-gnu", "PrgEnv-cray", "PrgEnv-aocc"], + "max_jobs": 16, + }, + ], + } + ], + "environments": [ + { + "name": "PrgEnv-gnu", + "modules": ["PrgEnv-gnu"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-cray", + "modules": ["PrgEnv-cray"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + { + "name": "PrgEnv-aocc", + "modules": ["PrgEnv-aocc"], + "cc": "cc", + "cxx": "CC", + "ftn": "ftn", + "target_systems": ["archer2"], + }, + ], + "logging": [ + { + "level": "debug", + "handlers": [ + { + "type": "stream", + "name": "stdout", + "level": "info", + "format": "%(message)s", + }, + { + "type": "file", + "name": "reframe.out", + "level": "info", + "format": "[%(asctime)s] %(check_info)s: %(message)s", + "append": True, + }, + { + "type": "file", + "name": "reframe.log", + "level": "debug", + "format": "[%(asctime)s] %(levelname)s %(levelno)s: %(check_info)s: %(message)s", + "append": False, + }, + ], + "handlers_perflog": [ + { + "type": "file", + "name": "reframe_perf.out", + "level": "info", + "format": ( + "[%(asctime)s] %(check_info)s: %(check_perf_var)s=%(check_perf_value)s " + "(ref=%(check_perf_ref)s;l=%(check_perf_lower_thres)s;u=%(check_perf_upper_thres)s)) " + "%(check_perf_unit)s" + ), + "append": True, + }, + { + "type": "filelog", + "prefix": "%(check_system)s/%(check_partition)s", + "level": "info", + "format": ( + "%(check_job_completion_time)s|reframe %(version)s|" + "%(check_info)s|jobid=%(check_jobid)s|" + "%(check_perf_var)s=%(check_perf_value)s|" + "ref=%(check_perf_ref)s " + "(l=%(check_perf_lower_thres)s, " + "u=%(check_perf_upper_thres)s)|" + "%(check_perf_unit)s" + ), + "append": True, + }, + ], + } + ], +} diff --git a/configuration/cirrus_settings.py b/configuration/cirrus.py similarity index 89% rename from configuration/cirrus_settings.py rename to configuration/cirrus.py index 41722e6..3fa1475 100644 --- a/configuration/cirrus_settings.py +++ b/configuration/cirrus.py @@ -1,5 +1,4 @@ -from reframe.core.backends import register_launcher -from reframe.core.launchers import JobLauncher +"""Cirrus Settings""" site_configuration = { "systems": [ @@ -14,7 +13,7 @@ "descr": "Login nodes", "scheduler": "local", "launcher": "local", - "environs": ["gnu", "intel"], + "environs": ["Default", "gcc", "intel"], }, { "name": "compute", @@ -27,7 +26,7 @@ "--partition=standard", ], "max_jobs": 16, - "environs": ["gnu", "intel"], + "environs": ["gcc", "intel"], "resources": [ { "name": "qos", @@ -118,7 +117,7 @@ ], "environments": [ { - "name": "gnu", + "name": "gcc", "modules": ["gcc", "mpt"], "cc": "mpicc", "cxx": "mpicxx", @@ -191,17 +190,16 @@ "append": True, }, { - 'type': 'filelog', - 'prefix': '%(check_system)s/%(check_partition)s', - 'level': 'info', - 'format': ( - '%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|' - '%(check_perf_var)s|' - '%(check_perf_value)s %(check_perf_unit)s|' - '(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|' + "type": "filelog", + "prefix": "%(check_system)s/%(check_partition)s", + "level": "info", + "format": ( + "%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|" + "%(check_perf_var)s|" + "%(check_perf_value)s %(check_perf_unit)s|" + "(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|" ), - - 'append': True + "append": True, }, ], } diff --git a/configuration/eidf_settings.py b/configuration/eidf.py similarity index 84% rename from configuration/eidf_settings.py rename to configuration/eidf.py index bc1c6dc..09e6a6b 100644 --- a/configuration/eidf_settings.py +++ b/configuration/eidf.py @@ -1,3 +1,5 @@ +"""EIDF settings""" + import socket site_configuration = { @@ -35,7 +37,7 @@ "options": ["--gres=cs:{num_csx}"], }, ], - } + }, ], } ], @@ -88,19 +90,18 @@ "append": True, }, { - 'type': 'filelog', - 'prefix': '%(check_system)s/%(check_partition)s', - 'level': 'info', - 'format': ( - '%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|' - '%(check_perf_var)s|' - '%(check_perf_value)s %(check_perf_unit)s|' - '(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|' + "type": "filelog", + "prefix": "%(check_system)s/%(check_partition)s", + "level": "info", + "format": ( + "%(check_display_name)s|%(check_result)s|%(check_job_completion_time)s|" + "%(check_perf_var)s|" + "%(check_perf_value)s %(check_perf_unit)s|" + "(%(check_perf_ref)s, %(check_perf_lower_thres)s, %(check_perf_upper_thres)s)|" ), - - 'append': True + "append": True, }, ], } ], -} \ No newline at end of file +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d390283 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,578 @@ +[tool.black] +line-length = 120 + +[tool.flake8] +max-line-length = 120 +extend-ignore = ["E203", "W503"] +builtins=[ + "bind", + "deferrable", + "env_vars", + "fixture", + "loggable_as", + "loggable", + "parameter", + "performance_function", + "reference", + "require_deps", + "run_after", + "run_before", + "sanity_function", + "variable", +] + +[tool.pylint.main] +# Analyse import fallback blocks. This can be used to support both Python 2 and 3 +# compatible code, which means that the block might have code that exists only in +# one or another interpreter, leading to false positives when analysed. +# analyse-fallback-blocks = + +# Clear in-memory caches upon conclusion of linting. Useful if running pylint in +# a server-like mode. +# clear-cache-post-run = + +# Always return a 0 (non-error) status code, even if lint errors are found. This +# is primarily useful in continuous integration scripts. +# exit-zero = + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +# extension-pkg-allow-list = + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +# extension-pkg-whitelist = + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +# fail-on = + +# Specify a score threshold under which the program will exit with error. +fail-under = 10.0 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +# from-stdin = + +# Files or directories to be skipped. They should be base names, not paths. +ignore = ["CVS"] + +# Add files or directories matching the regular expressions patterns to the +# ignore-list. The regex matches against paths and can be in Posix or Windows +# format. Because '\\' represents the directory delimiter on Windows systems, it +# can't be used as an escape character. +# ignore-paths = + +# Files or directories matching the regular expression patterns are skipped. The +# regex matches against base names, not paths. The default value ignores Emacs +# file locks +# ignore-patterns = + +# List of module names for which member attributes should not be checked (useful +# for modules/projects where namespaces are manipulated during runtime and thus +# existing member attributes cannot be deduced by static analysis). It supports +# qualified module names, as well as Unix pattern matching. +# ignored-modules = + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +# init-hook = + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. +# jobs = + +# Control the amount of potential inferred values when inferring a single object. +# This can help the performance when dealing with large functions or complex, +# nested conditions. +limit-inference-results = 100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +# load-plugins = + +# Pickle collected data for later comparisons. +persistent = true + +# Minimum Python version to use for version dependent checks. Will default to the +# version used to run pylint. +py-version = "3.10" + +# Discover python modules and packages in the file system subtree. +# recursive = + +# Add paths to the list of the source roots. Supports globbing patterns. The +# source root is an absolute path or a path relative to the current working +# directory used to determine a package namespace for modules located under the +# source root. +# source-roots = + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode = true + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +# unsafe-load-any-extension = + +[tool.pylint.basic] +# Naming style matching correct argument names. +argument-naming-style = "snake_case" + +# Regular expression matching correct argument names. Overrides argument-naming- +# style. If left empty, argument names will be checked with the set naming style. +# argument-rgx = + +# Naming style matching correct attribute names. +attr-naming-style = "snake_case" + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +# attr-rgx = + +# Bad variable names which should always be refused, separated by a comma. +bad-names = ["foo", "bar", "baz", "toto", "tutu", "tata"] + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +# bad-names-rgxs = + +# Naming style matching correct class attribute names. +class-attribute-naming-style = "any" + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +# class-attribute-rgx = + +# Naming style matching correct class constant names. +class-const-naming-style = "UPPER_CASE" + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +# class-const-rgx = + +# Naming style matching correct class names. +class-naming-style = "PascalCase" + +# Regular expression matching correct class names. Overrides class-naming-style. +# If left empty, class names will be checked with the set naming style. +# class-rgx = + +# Naming style matching correct constant names. +const-naming-style = "UPPER_CASE" + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming style. +# const-rgx = + +# Minimum line length for functions/classes that require docstrings, shorter ones +# are exempt. +docstring-min-length = -1 + +# Naming style matching correct function names. +function-naming-style = "snake_case" + +# Regular expression matching correct function names. Overrides function-naming- +# style. If left empty, function names will be checked with the set naming style. +# function-rgx = + +# Good variable names which should always be accepted, separated by a comma. +good-names = ["df", "dx", "dy", "f", "i", "j", "k", "l", "m", "n", "q", "p", "t", "up", "x", "y", "w", "z", "ex", "Run", "_"] + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +# good-names-rgxs = + +# Include a hint for the correct naming format with invalid-name. +# include-naming-hint = + +# Naming style matching correct inline iteration names. +inlinevar-naming-style = "any" + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +# inlinevar-rgx = + +# Naming style matching correct method names. +method-naming-style = "snake_case" + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +# method-rgx = + +# Naming style matching correct module names. +module-naming-style = "snake_case" + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +# module-rgx = + +# Colon-delimited sets of names that determine each other's naming style when the +# name regexes allow several styles. +# name-group = + +# Regular expression which should only match function or class names that do not +# require a docstring. +no-docstring-rgx = "^_" + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. These +# decorators are taken in consideration only for invalid-name. +property-classes = ["abc.abstractproperty"] + +# Regular expression matching correct type alias names. If left empty, type alias +# names will be checked with the set naming style. +# typealias-rgx = + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +# typevar-rgx = + +# Naming style matching correct variable names. +variable-naming-style = "snake_case" + +# Regular expression matching correct variable names. Overrides variable-naming- +# style. If left empty, variable names will be checked with the set naming style. +# variable-rgx = + +[tool.pylint.classes] +# Warn about protected attribute access inside special methods +# check-protected-access-in-special-methods = + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods = ["__init__", "__new__", "setUp", "__post_init__"] + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected = ["_asdict", "_fields", "_replace", "_source", "_make"] + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg = ["cls"] + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg = ["cls"] + +[tool.pylint.design] +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +# exclude-too-few-public-methods = + +# List of qualified class names to ignore when counting class parents (see R0901) +# ignored-parents = + +# Maximum number of arguments for function / method. +max-args = 5 + +# Maximum number of attributes for a class (see R0902). +max-attributes = 7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr = 5 + +# Maximum number of branch for function / method body. +max-branches = 12 + +# Maximum number of locals for function / method body. +max-locals = 15 + +# Maximum number of parents for a class (see R0901). +max-parents = 7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods = 20 + +# Maximum number of return / yield for function / method body. +max-returns = 6 + +# Maximum number of statements in function / method body. +max-statements = 50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods = 2 + +[tool.pylint.exceptions] +# Exceptions that will emit a warning when caught. +overgeneral-exceptions = ["builtins.BaseException", "builtins.Exception"] + +[tool.pylint.format] +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +# expected-line-ending-format = + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines = "^\\s*(# )??$" + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren = 4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string = " " + +# Maximum number of characters on a single line. +max-line-length = 120 + +# Maximum number of lines in a module. +max-module-lines = 1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +# single-line-class-stmt = + +# Allow the body of an if to be on the same line as the test if there is no else. +# single-line-if-stmt = + +[tool.pylint.imports] +# List of modules that can be imported at any level, not just the top level one. +# allow-any-import-level = + +# Allow explicit reexports by alias from a package __init__. +# allow-reexport-from-package = + +# Allow wildcard imports from modules that define __all__. +# allow-wildcard-with-all = + +# Deprecated modules which should not be used, separated by a comma. +# deprecated-modules = + +# Output a graph (.gv or any supported image format) of external dependencies to +# the given file (report RP0402 must not be disabled). +# ext-import-graph = + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be disabled). +# import-graph = + +# Output a graph (.gv or any supported image format) of internal dependencies to +# the given file (report RP0402 must not be disabled). +# int-import-graph = + +# Force import order to recognize a module as part of the standard compatibility +# libraries. +# known-standard-library = + +# Force import order to recognize a module as part of a third party library. +known-third-party = ["enchant"] + +# Couples of modules and preferred modules, separated by a comma. +# preferred-modules = + +[tool.pylint.logging] +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style = "old" + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules = ["logging"] + +[tool.pylint."messages control"] +# Only show warnings with the listed confidence levels. Leave empty to show all. +# Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence = ["HIGH", "CONTROL_FLOW", "INFERENCE", "INFERENCE_FAILURE", "UNDEFINED"] + +# Disable the message, report, category or checker with the given id(s). You can +# either give multiple identifiers separated by comma (,) or put this option +# multiple times (only on the command line, not in the configuration file where +# it should appear only once). You can also use "--disable=all" to disable +# everything first and then re-enable specific checks. For example, if you want +# to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable = ["raw-checker-failed", "bad-inline-option", "locally-disabled", "file-ignored", "suppressed-message", "useless-suppression", "deprecated-pragma", "use-implicit-booleaness-not-comparison-to-string", "use-implicit-booleaness-not-comparison-to-zero", "use-symbolic-message-instead", "unspecified-encoding", "duplicate-code", "too-few-public-methods"] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where it +# should appear only once). See also the "--disable" option for examples. +enable = ["c-extension-no-member"] + +[tool.pylint.method_args] +# List of qualified names (i.e., library.method) which require a timeout +# parameter e.g. 'requests.api.get,requests.api.post' +timeout-methods = ["requests.api.delete", "requests.api.get", "requests.api.head", "requests.api.options", "requests.api.patch", "requests.api.post", "requests.api.put", "requests.api.request"] + +[tool.pylint.miscellaneous] +# List of note tags to take in consideration, separated by a comma. +notes = ["FIXME", "XXX", "TODO", "BROKEN"] + +# Regular expression of note tags to take in consideration. +# notes-rgx = + +[tool.pylint.refactoring] +# Maximum number of nested blocks for function / method body +max-nested-blocks = 5 + +# Complete name of functions that never returns. When checking for inconsistent- +# return-statements if a never returning function is called then it will be +# considered as an explicit return statement and no message will be printed. +never-returning-functions = ["sys.exit", "argparse.parse_error"] + +# Let 'consider-using-join' be raised when the separator to join on would be non- +# empty (resulting in expected fixes of the type: ``"- " + " - ".join(items)``) +suggest-join-with-non-empty-separator = true + +[tool.pylint.reports] +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each category, +# as well as 'statement' which is the total number of statements analyzed. This +# score is used by the global evaluation report (RP0004). +evaluation = "10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)" + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +# msg-template = + +# Set the output format. Available formats are: text, parseable, colorized, json2 +# (improved json format), json (old json format) and msvs (visual studio). You +# can also give a reporter class, e.g. mypackage.mymodule.MyReporterClass. +# output-format = + +# Tells whether to display a full report or only the messages. +# reports = + +# Activate the evaluation score. +score = true + +[tool.pylint.similarities] +# Comments are removed from the similarity computation +ignore-comments = true + +# Docstrings are removed from the similarity computation +ignore-docstrings = true + +# Imports are removed from the similarity computation +# ignore-imports = + +# Signatures are removed from the similarity computation +# ignore-signatures = + +# Minimum lines number of a similarity. +min-similarity-lines = 4 + +[tool.pylint.spelling] +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions = 4 + +# Spelling dictionary name. No available dictionaries : You need to install both +# the python package and the system dependency for enchant to work. +# spelling-dict = + +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives = "fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:" + +# List of comma separated words that should not be checked. +# spelling-ignore-words = + +# A path to a file that contains the private dictionary; one word per line. +# spelling-private-dict-file = + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +# spelling-store-unknown-words = + +[tool.pylint.typecheck] +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators = ["contextlib.contextmanager"] + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +# generated-members = + +# Tells whether missing members accessed in mixin class should be ignored. A +# class is considered mixin if its name matches the mixin-class-rgx option. +# Tells whether to warn about missing members when the owner of the attribute is +# inferred to be None. +ignore-none = true + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference can +# return multiple potential results while evaluating a Python object, but some +# branches might not be evaluated, which results in partial inference. In that +# case, it might be useful to still emit no-member and other checks for the rest +# of the inferred objects. +ignore-on-opaque-inference = true + +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins = ["no-member", "not-async-context-manager", "not-context-manager", "attribute-defined-outside-init"] + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes = ["optparse.Values", "thread._local", "_thread._local"] + +# Show a hint with possible names when a member name was not found. The aspect of +# finding the hint is based on edit distance. +missing-member-hint = true + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance = 1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices = 1 + +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx = ".*[Mm]ixin" + +# List of decorators that change the signature of a decorated function. +# signature-mutators = + +[tool.pylint.variables] +# List of additional names supposed to be defined in builtins. Remember that you +# should avoid defining new builtins when possible. +additional-builtins = [ + "bind", + "deferrable", + "env_vars", + "fixture", + "loggable_as", + "loggable", + "parameter", + "performance_function", + "reference", + "require_deps", + "run_after", + "run_before", + "sanity_function", + "variable", +] + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables = true + +# List of names allowed to shadow builtins +# allowed-redefined-builtins = + +# List of strings which can identify a callback function by name. A callback name +# must start or end with one of those strings. +callbacks = ["cb_", "_cb"] + +# A regular expression matching the name of dummy variables (i.e. expected to not +# be used). +dummy-variables-rgx = "_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_" + +# Argument names that match this expression will be ignored. +ignored-argument-names = "_.*|^ignored_|^unused_" + +# Tells whether we should check for unused import in __init__ files. +# init-import = + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules = ["six.moves", "past.builtins", "future.builtins", "builtins", "io"] diff --git a/tests/affinity/affinity_check.py b/tests/affinity/affinity_check.py index 0375e80..15df7be 100644 --- a/tests/affinity/affinity_check.py +++ b/tests/affinity/affinity_check.py @@ -1,155 +1,192 @@ +#!/usr/bin/env python3 + +"""Test process/thread affinity. Based on test from CSCS.""" + import reframe as rfm import reframe.utility.sanity as sn -# Test process/thread affinity. Based on test from CSCS. class AffinityTestBase(rfm.RegressionTest): - - def __init__(self, variant): - self.valid_systems = ['archer2:compute','cirrus:compute'] - self.valid_prog_environs = ['*'] - self.build_system = "SingleSource" - self.build_system.cflags = ['-fopenmp'] - self.sourcepath = 'affinity.c' - self.cflags = ['-fopenmp'] - self.maintainers = ['a.turner@epcc.ed.ac.uk'] - self.tags = {'functionality','short'} - - @run_before('sanity') + """Base class for the affinity tests""" + + valid_systems = ["archer2:compute", "cirrus:compute"] + valid_prog_environs = ["*"] + build_system = "SingleSource" + sourcepath = "affinity.c" + maintainers = ["a.turner@epcc.ed.ac.uk"] + tags = {"functionality", "short"} + aff_cores = None + ref_cores = None + + @run_before("compile") + def prepare_build(self): + """Setup build environment""" + self.build_system.cflags = ["-fopenmp"] + + @run_before("sanity") def set_sanity(self): + """Extracts affinity results""" def parse_cpus(x): return sorted(x) - re_aff_cores = r'affinity = \s+(?P\d+:\d+:(?:[\d+,]*|[\d+-]*)\d+)' - self.aff_cores = sn.extractall( - re_aff_cores, self.stdout, 'cpus', parse_cpus) - ref_key = 'ref_' + self.current_partition.fullname - self.ref_cores = sn.extractall( - re_aff_cores, self.cases[self.variant][ref_key], - 'cpus', parse_cpus) + re_aff_cores = r"affinity = \s+(?P\d+:\d+:(?:[\d+,]*|[\d+-]*)\d+)" + self.aff_cores = sn.extractall(re_aff_cores, self.stdout, "cpus", parse_cpus) + ref_key = "ref_" + self.current_partition.fullname + self.ref_cores = sn.extractall(re_aff_cores, self.cases[self.variant][ref_key], "cpus", parse_cpus) # Ranks and threads can be extracted into lists in order to compare # them since the affinity programm prints them in ascending order. - self.sanity_patterns = sn.all([ - sn.assert_eq(sn.sorted(self.aff_cores), sn.sorted(self.ref_cores)) - ]) + self.sanity_patterns = sn.all([sn.assert_eq(sn.sorted(self.aff_cores), sn.sorted(self.ref_cores))]) @rfm.simple_test class AffinityOMPTest(AffinityTestBase): + """OMP bind threads test""" + + variant = parameter(["omp_bind_threads"]) - variant = parameter(['omp_bind_threads']) + descr = "Checking core affinity for OMP threads." + cases = {} - def __init__(self): - super().__init__(self.variant) - self.descr = 'Checking core affinity for OMP threads.' - if (self.current_system.name in ['archer2']): + @run_after("init") + def setup_environment(self): + """Setup environment""" + if self.current_system.name in ["archer2"]: self.cases = { - 'omp_bind_threads': { - 'ref_archer2:compute': 'archer2_numa_omp.txt', - 'num_cpus_per_task_archer2:compute': 16, - 'num_tasks': 8, - 'num_tasks_per_node': 8, - 'num_cpus_per_task': 16, - 'OMP_PLACES': 'cores', + "omp_bind_threads": { + "ref_archer2:compute": "archer2_numa_omp.txt", + "num_cpus_per_task_archer2:compute": 16, + "num_tasks": 8, + "num_tasks_per_node": 8, + "num_cpus_per_task": 16, + "OMP_PLACES": "cores", }, } # Each 18-core processor is a single NUMA region. - if (self.current_system.name in ['cirrus']): + if self.current_system.name in ["cirrus"]: self.cases = { - 'omp_bind_threads': { - 'ref_cirrus:compute': 'cirrus_numa_omp.txt', - 'num_cpus_per_task_cirrus:compute': 18, - 'num_tasks': 2, - 'num_tasks_per_node': 2, - 'num_cpus_per_task': 18, - 'OMP_PLACES': 'cores', + "omp_bind_threads": { + "ref_cirrus:compute": "cirrus_numa_omp.txt", + "num_cpus_per_task_cirrus:compute": 18, + "num_tasks": 2, + "num_tasks_per_node": 2, + "num_cpus_per_task": 18, + "OMP_PLACES": "cores", }, } - self.num_tasks = self.cases[self.variant]['num_tasks'] - self.num_tasks_per_node = self.cases[self.variant]['num_tasks_per_node'] - self.num_cpus_per_task = self.cases[self.variant]['num_cpus_per_task'] - self.extra_resources = {'qos': {'qos': 'standard'}} + self.num_tasks = self.cases[self.variant]["num_tasks"] + self.num_tasks_per_node = self.cases[self.variant]["num_tasks_per_node"] + self.num_cpus_per_task = self.cases[self.variant]["num_cpus_per_task"] + self.extra_resources = {"qos": {"qos": "standard"}} - @run_before('run') + @run_before("run") def set_tasks_per_core(self): + """Setup tasks""" partname = self.current_partition.fullname - self.num_cpus_per_task = self.cases[self.variant]['num_cpus_per_task_%s' % partname] + self.num_cpus_per_task = self.cases[self.variant][f"num_cpus_per_task_{partname}"] self.num_tasks = 1 self.env_vars = { - 'OMP_NUM_THREADS': str(self.num_cpus_per_task), - 'OMP_PLACES': self.cases[self.variant]['OMP_PLACES'] + "OMP_NUM_THREADS": str(self.num_cpus_per_task), + "OMP_PLACES": self.cases[self.variant]["OMP_PLACES"], } @rfm.simple_test class AffinityMPITestARCHER2(AffinityTestBase): - - variant = parameter(['fully_populated_nosmt','fully_populated_smt','single_process_per_numa']) - - def __init__(self): - super().__init__(self.variant) - self.descr = 'Checking core affinity for MPI processes.' - self.valid_systems = ['archer2:compute'] - self.cases = { - 'fully_populated_nosmt': { - 'ref_archer2:compute': 'archer2_fully_populated_nosmt.txt', - 'runopts_archer2:compute': ['--hint=nomultithread', '--distribution=block:block'], - 'num_tasks': 128, - 'num_tasks_per_node': 128, - 'num_cpus_per_task': 1, - }, - 'fully_populated_smt': { - 'ref_archer2:compute': 'archer2_fully_populated_smt.txt', - 'runopts_archer2:compute': ['--ntasks=256', '--ntasks-per-node=256', '--hint=multithread', '--distribution=block:block'], - 'num_tasks': 128, - 'num_tasks_per_node': 128, - 'num_cpus_per_task': 1, - }, - 'single_process_per_numa': { - 'ref_archer2:compute': 'archer2_single_process_per_numa.txt', - 'runopts_archer2:compute': ['--hint=nomultithread', '--distribution=block:block'], - 'num_tasks': 8, - 'num_tasks_per_node': 8, - 'num_cpus_per_task': 16, - }, - } - self.num_tasks = self.cases[self.variant]['num_tasks'] - self.num_tasks_per_node = self.cases[self.variant]['num_tasks_per_node'] - self.num_cpus_per_task = self.cases[self.variant]['num_cpus_per_task'] - self.extra_resources = {'qos': {'qos': 'standard'}} - - @run_before('run') + """MPI affinity test for ARCHER2""" + + variant = parameter( + [ + "fully_populated_nosmt", + "fully_populated_smt", + "single_process_per_numa", + ] + ) + + descr = "Checking core affinity for MPI processes." + valid_systems = ["archer2:compute"] + cases = { + "fully_populated_nosmt": { + "ref_archer2:compute": "archer2_fully_populated_nosmt.txt", + "runopts_archer2:compute": [ + "--hint=nomultithread", + "--distribution=block:block", + ], + "num_tasks": 128, + "num_tasks_per_node": 128, + "num_cpus_per_task": 1, + }, + "fully_populated_smt": { + "ref_archer2:compute": "archer2_fully_populated_smt.txt", + "runopts_archer2:compute": [ + "--ntasks=256", + "--ntasks-per-node=256", + "--hint=multithread", + "--distribution=block:block", + ], + "num_tasks": 128, + "num_tasks_per_node": 128, + "num_cpus_per_task": 1, + }, + "single_process_per_numa": { + "ref_archer2:compute": "archer2_single_process_per_numa.txt", + "runopts_archer2:compute": [ + "--hint=nomultithread", + "--distribution=block:block", + ], + "num_tasks": 8, + "num_tasks_per_node": 8, + "num_cpus_per_task": 16, + }, + } + + @run_after("init") + def setup_variant(self): + """sets up variants""" + self.num_tasks = self.cases[self.variant]["num_tasks"] + self.num_tasks_per_node = self.cases[self.variant]["num_tasks_per_node"] + self.num_cpus_per_task = self.cases[self.variant]["num_cpus_per_task"] + self.extra_resources = {"qos": {"qos": "standard"}} + + @run_before("run") def set_launcher(self): + """Sets launcher""" partname = self.current_partition.fullname - self.job.launcher.options = self.cases[self.variant]['runopts_%s' % partname] + self.job.launcher.options = self.cases[self.variant][f"runopts_{partname}"] @rfm.simple_test class AffinityMPITestCirrus(AffinityTestBase): - - variant = parameter(['fully_populated_nosmt']) - - def __init__(self): - super().__init__(self.variant) - self.descr = 'Checking core affinity for MPI processes.' - self.valid_systems = ['cirrus:compute'] - self.cases = { - 'fully_populated_nosmt': { - 'ref_cirrus:compute': 'cirrus_fully_populated_nosmt.txt', - 'runopts_cirrus:compute': ['--hint=nomultithread', '--distribution=block:block'], - 'num_tasks': 36, - 'num_tasks_per_node': 36, - 'num_cpus_per_task': 1, - }, - } - self.num_tasks = self.cases[self.variant]['num_tasks'] - self.num_tasks_per_node = self.cases[self.variant]['num_tasks_per_node'] - self.num_cpus_per_task = self.cases[self.variant]['num_cpus_per_task'] - self.extra_resources = {'qos': {'qos': 'standard'}} - - @run_before('run') + """MPI affinity test for Cirrus""" + + variant = parameter(["fully_populated_nosmt"]) + + descr = "Checking core affinity for MPI processes." + valid_systems = ["cirrus:compute"] + cases = { + "fully_populated_nosmt": { + "ref_cirrus:compute": "cirrus_fully_populated_nosmt.txt", + "runopts_cirrus:compute": [ + "--hint=nomultithread", + "--distribution=block:block", + ], + "num_tasks": 36, + "num_tasks_per_node": 36, + "num_cpus_per_task": 1, + }, + } + + @run_after("init") + def setup_variant(self): + """sets up variants""" + self.num_tasks = self.cases[self.variant]["num_tasks"] + self.num_tasks_per_node = self.cases[self.variant]["num_tasks_per_node"] + self.num_cpus_per_task = self.cases[self.variant]["num_cpus_per_task"] + self.extra_resources = {"qos": {"qos": "standard"}} + + @run_before("run") def set_launcher(self): + """Sets launcher""" partname = self.current_partition.fullname - self.job.launcher.options = self.cases[self.variant]['runopts_%s' % partname] + self.job.launcher.options = self.cases[self.variant][f"runopts_{partname}"] diff --git a/tests/apps/castep/castep_check.py b/tests/apps/castep/castep_check.py index 6e14820..2376da9 100644 --- a/tests/apps/castep/castep_check.py +++ b/tests/apps/castep/castep_check.py @@ -1,80 +1,79 @@ -import itertools -import os +#!/usr/bin/env python3 +"""Reframe tests for CASTEP""" import reframe as rfm import reframe.utility.sanity as sn class CASTEPBaseCheck(rfm.RunOnlyRegressionTest): - def __init__(self, output_file): - super().__init__() + """Base class for the CASTEP checks""" - self.valid_prog_environs = ['PrgEnv-gnu','intel'] - self.executable = 'castep.mpi' + tags = {"applications", "performance"} + valid_prog_environs = ["PrgEnv-gnu", "intel"] + executable = "castep.mpi" - self.keep_files = [output_file] + maintainers = ["a.turner@epcc.ed.ac.uk"] + strict_check = False + use_multithreading = False + extra_resources = {"qos": {"qos": "standard"}} - energy = sn.extractsingle(r'Final energy, E\s+=\s+(?P\S+)', - output_file, 'energy', float, item=-1) - energy_reference = -77705.21093039 + output_file = "al3x3.castep" + keep_files = [output_file] - self.sanity_patterns = sn.all([ - sn.assert_found('Total time', output_file), - sn.assert_reference(energy, energy_reference, -1.0, 1.0) - ]) + energy_reference = -77705.21093039 - self.perf_patterns = { - 'runtime': sn.extractsingle(r'Total time\s+=\s+(?P\S+)', - output_file, 'runtime', float), + reference = { + "cirrus:compute": {"energy": (energy_reference, -0.01, 0.01, "eV")}, + "archer2:compute": {"energy": (energy_reference, -0.01, 0.01, "eV")}, + } - 'calctime': sn.extractsingle(r'Calculation time\s+=\s+(?P\S+)', - output_file, 'calctime', float) - } + @sanity_function + def assert_finished(self): + """Sanity check that simulation finished successfully""" + return sn.assert_found("Total time", self.keep_files[0]) + + @performance_function("eV", perf_key="energy") + def extract_energy(self): + """Extract value of system energy for performance check""" + return sn.extractsingle(r"Final energy, E\s+=\s+(?P\S+)", self.keep_files[0], "energy", float, item=-1) + + @performance_function("s", perf_key="runtime") + def extract_runtime(self): + """Extract total runtime to compare with reference value""" + return sn.extractsingle(r"Total time\s+=\s+(?P\S+)", self.keep_files[0], "runtime", float) + + @performance_function("s", perf_key="calctime") + def extract_calctime(self): + """Extract calctime to compare with reference value""" + return sn.extractsingle(r"Calculation time\s+=\s+(?P\S+)", self.keep_files[0], "calctime", float) - self.maintainers = ['a.turner@epcc.ed.ac.uk'] - self.strict_check = False - self.use_multithreading = False - self.extra_resources = { - 'qos': {'qos': 'standard'} - } - self.tags = {'applications','performance'} @rfm.simple_test class CASTEPCPUCheck(CASTEPBaseCheck): - def __init__(self): - super().__init__('al3x3.castep') - - self.valid_systems = ['archer2:compute','cirrus:compute'] - self.descr = 'CASTEP corrctness and performance test' - self.executable_opts = ['al3x3'] - - if (self.current_system.name in ['archer2']): - self.modules = ['castep'] - self.num_tasks = 512 - self.num_tasks_per_node = 128 - self.num_cpus_per_task = 1 - self.time_limit = '20m' - self.env_vars= { - 'OMP_NUM_THREADS': str(self.num_cpus_per_task) - } - - if (self.current_system.name in ['cirrus']): - self.modules = ['castep/22.1.1'] - self.num_tasks = 216 - self.num_tasks_per_node = 36 - self.num_cpus_per_task = 1 - self.time_limit = '20m' - self.env_vars= { - 'OMP_NUM_THREADS': str(self.num_cpus_per_task) - } - - self.reference = { - 'archer2:compute': { - 'calctime': (126, -0.1, 0.1, 's'), - 'runtime': (132, -0.1, 0.1, 's') - }, - 'cirrus:compute': { - 'calctime': (325.9, -1.65, 1.65, 's'), - 'runtime': (328.2, -1.55, 1.55, 's') - } - } + """CASTEP Check for CPU""" + + valid_systems = ["archer2:compute", "cirrus:compute"] + descr = "CASTEP corrctness and performance test" + executable_opts = ["al3x3"] + + time_limit = "20m" + num_cpus_per_task = 1 + env_vars = {"OMP_NUM_THREADS": str(num_cpus_per_task)} + + reference["archer2:compute"]["calctime"] = (126, -0.1, 0.1, "s") + reference["archer2:compute"]["runtime"] = (132, -0.1, 0.1, "s") + reference["cirrus:compute"]["calctime"] = (325.9, -0.1, 0.1, "s") + reference["cirrus:compute"]["runtime"] = (328.2, -0.1, 0.1, "s") + + @run_after("init") + def setup_environment(self): + """Setup environment""" + if self.current_system.name in ["archer2"]: + self.modules = ["castep"] + self.num_tasks = 512 + self.num_tasks_per_node = 128 + + if self.current_system.name in ["cirrus"]: + self.modules = ["castep/22.1.1"] + self.num_tasks = 216 + self.num_tasks_per_node = 36 diff --git a/tests/apps/cp2k/cp2k_check.py b/tests/apps/cp2k/cp2k_check.py index 913bb6e..9c5568d 100644 --- a/tests/apps/cp2k/cp2k_check.py +++ b/tests/apps/cp2k/cp2k_check.py @@ -1,159 +1,129 @@ -import itertools -import os +#!/usr/bin/env python3 + +"""ReFrame test for cp2k""" import reframe as rfm import reframe.utility.sanity as sn class CP2KBaseCheck(rfm.RunOnlyRegressionTest): - def __init__(self, output_file): - super().__init__() - - #self.cpufreq = rfm.core.builtins.parameter(['1500000','2000000','2250000']) - - - # Set Programming Environment - self.valid_prog_environs = ['PrgEnv-gnu'] - - # Identify the executable - self.executable = 'cp2k.psmp' - - # Output files to be retained - self.keep_files = [output_file] - - # REGEX to extract key information from output file - energy = sn.extractsingle(r'ENERGY\| Total FORCE_EVAL \( QS \) energy \[a.u.\]:' - r'\s+(?P\S+)', - output_file, 'energy', float) - - # Reference value to validate run with - energy_reference = -870.934788 + """ReFrame CP2K test base class""" + + # Which modules to load in test + modules = ["cp2k"] + # Identify the executable + executable = "cp2k.psmp" + # Additional Slurm parameters. Requires adding to config file first. + extra_resources = {"qos": {"qos": "standard"}} + # Output files to be retained + keep_files = ["cp2k.out"] + + maintainers = ["j.richings@epcc.ed.ac.uk"] + use_multithreading = False + tags = {"applications", "performance"} + + # Reference value to validate run with + energy_reference = -870.934788 + + reference = { + "*": {"energy": (energy_reference, -0.01, 0.01, "a.u.")}, + "cirrus:compute": {"performance": (1300, -0.05, 0.05, "seconds")}, + } + + reference_performance = { + "2000000": (350, -0.1, 0.1, "seconds"), + "2250000": (250, -0.1, 0.1, "seconds"), + } + + @sanity_function + def assert_finished(self): + """Sanity check that simulation finished successfully""" + return sn.assert_found("CP2K ", self.keep_files[0]) + + @performance_function("a.u.", perf_key="energy") + def extract_energy(self): + """Extract value of system energy for performance check""" + return sn.extractsingle( + r"ENERGY\| Total FORCE_EVAL \( QS \) energy \[a.u.\]:\s+(?P\S+)", + self.keep_files[0], + "energy", + float, + ) + + @performance_function("seconds", perf_key="performance") + def extract_perf(self): + """Extract performance value to compare with reference value""" + return sn.extractsingle( + r"\s+CP2K(?:\s+\d+\.?\d*){5}\s+(?P\S+)", + self.keep_files[0], + "perf", + float, + ) - # Sanity check to confirm test is correct - self.sanity_patterns = sn.all([ - sn.assert_found('CP2K ', output_file), - sn.assert_reference(energy, energy_reference, -1.E-06, +1.0E-06) - ]) - - # REGEX to extract performance figures from test - self.perf_patterns = { - 'perf': sn.extractsingle(r'\s+CP2K ' - r'(\s+\S+){5}\s+(?P\S+)', - output_file, 'perf', float) - } - - self.maintainers = ['j.richings@epcc.ed.ac.uk'] - self.strict_check = False - self.use_multithreading = False - - # Additional Slurm parameters. Requires adding to config file first. - self.extra_resources = { - 'qos': {'qos': 'standard'} - } - self.tags = {'applications','performance'} - -# 2 Ghz test - @rfm.simple_test -class CP2KCPUCheck2GHz(CP2KBaseCheck): - def __init__(self): - super().__init__('cp2k.out') - - - # Select system to use - self.valid_systems = ['archer2:compute'] - - # Description of test - self.descr = 'CP2K check 2Ghz check' - # Command line options for executable - self.executable_opts = ('-i input_bulk_HFX_3.inp -o cp2k.out ').split() - - if (self.current_system.name in ['archer2']): - # Which modules to load in test - self.modules = ['cp2k'] - # Total number of tasks in slurm - self.num_tasks = 384 - # Task per node in slurm - self.num_tasks_per_node = 16 - # CPU's per task in slurm - self.num_cpus_per_task = 8 - # Slurm job time limit - self.time_limit = '1h' - # Other Environment parameters to set - self.env_vars = { - 'OMP_NUM_THREADS': str(self.num_cpus_per_task), - 'OMP_PLACES': 'cores', - 'SLURM_CPU_FREQ_REQ': '2000000' - } - # Performance test reference values - self.reference = { - 'archer2:compute': {'perf': (335, 12, 'seconds'), - } +class CP2KARCHER2(CP2KBaseCheck): + """CP2K test""" + + # Select system to use + valid_systems = ["archer2:compute"] + # Set Programming Environment + valid_prog_environs = ["PrgEnv-gnu"] + # Description of test + descr = "CP2K " + # Command line options for executable + executable_opts = ("-i input_bulk_HFX_3.inp -o cp2k.out ").split() + # different cpu frequencies + freq = parameter(["2250000", "2000000"]) + # slurm parameters + num_tasks = 384 + num_tasks_per_node = 16 + num_cpus_per_task = 8 + time_limit = "10m" + + reference_performance = { + "2000000": (350, -0.1, 0.1, "seconds"), + "2250000": (250, -0.1, 0.1, "seconds"), + } + + @run_after("init") + def setup_params(self): + """sets up extra parameters""" + self.descr += self.freq + if self.current_system.name in ["archer2"]: + self.env_vars = { + "OMP_NUM_THREADS": str(self.num_cpus_per_task), + "OMP_PLACES": "cores", + "SLURM_CPU_FREQ_REQ": self.freq, } - # Additiona - @run_before('run') - def set_task_distribution(self): - self.job.options = ['--distribution=block:block'] + @run_before("performance") + def set_reference(self): + """Changes reference values""" + if self.current_system.name in ["archer2"]: + # https://reframe-hpc.readthedocs.io/en/stable/utility_functions_reference.html#reframe.utility.ScopedDict + self.reference["archer2:compute:performance"] = self.reference_performance[self.freq] -# 2.25 Ghz test @rfm.simple_test -class CP2KCPUCheck2_25GHz(CP2KBaseCheck): - def __init__(self): - super().__init__('cp2k.out') - - self.valid_systems = ['archer2:compute'] - self.descr = 'CP2K 2.25Ghz check' - self.executable_opts = ('-i input_bulk_HFX_3.inp -o cp2k.out ').split() - - if (self.current_system.name in ['archer2']): - self.modules = ['cp2k'] - self.num_tasks = 384 - self.num_tasks_per_node = 16 - self.num_cpus_per_task = 8 - self.time_limit = '1h' - self.env_vars = { - 'OMP_NUM_THREADS': str(self.num_cpus_per_task), - 'OMP_PLACES': 'cores', - 'SLURM_CPU_FREQ_REQ': '2250000' - } - - self.reference = { - 'archer2:compute': {'perf': (250, -12, 12, 'seconds'), - } - } - - @run_before('run') - def set_task_distribution(self): - self.job.options = ['--distribution=block:block'] - -# Cirrus default CPUfreq -# @rfm.simple_test -# class CP2KCPUCheckCirrus(CP2KBaseCheck): -# def __init__(self): -# super().__init__('cp2k.out') -# -# # Select system to use -# self.valid_systems = ['cirrus:compute'] -# -# # Description of test -# self.descr = 'CP2K check Cirrus' -# # Command line options for executable -# self.executable_opts = ('-i input_bulk_HFX_3.inp -o cp2k.out ').split() -# -# if (self.current_system.name in ['cirrus']): -# self.modules = ['cp2k'] -# self.num_tasks = 360 -# self.num_tasks_per_node = 18 -# self.num_cpus_per_task = 2 -# self.time_limit = '1h' -# self.env_vars = { -# 'OMP_NUM_THREADS': str(self.num_cpus_per_task), -# 'OMP_PLACES': 'cores', -# } -# -# @run_before('run') -# def set_task_distribution(self): -# self.job.options = ['--distribution=block:block'] +class CP2KCPUCirrus(CP2KBaseCheck): + """CP2K test for Cirrus""" + + # Select system to use + valid_systems = ["cirrus:compute"] + # Set Programming Environment + valid_prog_environs = ["gcc"] + # Description of test + descr = "CP2K test" + # Command line options for executable + executable_opts = ("-i input_bulk_HFX_3.inp -o cp2k.out ").split() + # slurm parameters + num_tasks = 360 + num_tasks_per_node = 18 + num_cpus_per_task = 2 + time_limit = "1h" + + env_vars = { + "OMP_NUM_THREADS": str(num_cpus_per_task), + "OMP_PLACES": "cores", + } diff --git a/tests/apps/gromacs/gmx_1400k_atoms.py b/tests/apps/gromacs/gmx_1400k_atoms.py index 6731497..a491107 100644 --- a/tests/apps/gromacs/gmx_1400k_atoms.py +++ b/tests/apps/gromacs/gmx_1400k_atoms.py @@ -1,3 +1,7 @@ +#!/usr/bin/env python3 + +"""Gromacs 1400k atom HECBioSim benchmark""" + import reframe as rfm from gromacs_base import GromacsBaseCheck @@ -41,6 +45,8 @@ class Gromacs1400kAtomsBase(GromacsBaseCheck): @rfm.simple_test class GromacsCPUCheck(Gromacs1400kAtomsBase): + """Gromacs CPU checks""" + valid_systems = ["archer2:compute", "cirrus:compute"] modules = ["gromacs"] descr = Gromacs1400kAtomsBase.descr + " -- CPU" @@ -50,36 +56,21 @@ class GromacsCPUCheck(Gromacs1400kAtomsBase): num_cpus_per_task = 1 env_vars = {"OMP_NUM_THREADS": str(num_cpus_per_task)} - reference["archer2:compute"]["performance"] = ( - 22.4, - -0.1, - 0.1, - "ns/day", - ) - reference["archer2-tds:compute"]["performance"] = ( - 22.4, - -0.1, - 0.1, - "ns/day", - ) - reference["cirrus:compute"]["performance"] = ( - 5.50, - -0.1, - 0.1, - "ns/day", - ) + reference["archer2:compute"]["performance"] = (24.0, -0.1, None, "ns/day") + reference["archer2-tds:compute"]["performance"] = (22.4, -0.1, None, "ns/day") + reference["cirrus:compute"]["performance"] = (5.50, -0.1, None, "ns/day") @run_before("run") def setup_resources(self): """sets up number of tasks""" - self.num_tasks_per_node = self.cores.get( - self.current_partition.fullname, 1 - ) + self.num_tasks_per_node = self.cores.get(self.current_partition.fullname, 1) self.num_tasks = self.n_nodes * self.num_tasks_per_node @rfm.simple_test class GromacsGPUCheck(Gromacs1400kAtomsBase): + """Gromacs GPU checks""" + valid_systems = ["cirrus:compute-gpu"] modules = ["gromacs/2023.4-gpu"] descr = Gromacs1400kAtomsBase.descr + " -- GPU" @@ -96,12 +87,7 @@ class GromacsGPUCheck(Gromacs1400kAtomsBase): num_tasks = None num_cpus_per_tasks = None - reference["cirrus:compute-gpu"]["performance"] = ( - 11.5, - -0.05, - 0.05, - "ns/day", - ) + reference["cirrus:compute-gpu"]["performance"] = (11.5, -0.05, None, "ns/day") @run_after("setup") def setup_gpu_options(self): diff --git a/tests/apps/gromacs/gromacs_base.py b/tests/apps/gromacs/gromacs_base.py index 4d717e6..65d6d70 100644 --- a/tests/apps/gromacs/gromacs_base.py +++ b/tests/apps/gromacs/gromacs_base.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +"""Base class for gromacs checks""" + import reframe as rfm import reframe.utility.sanity as sn @@ -5,7 +8,7 @@ class GromacsBaseCheck(rfm.RunOnlyRegressionTest): """ReFrame base class for GROMACS tests""" - valid_prog_environs = ["PrgEnv-gnu", "gnu", "nvidia-mpi"] + valid_prog_environs = ["PrgEnv-gnu", "gcc", "nvidia-mpi"] executable = "gmx_mpi" extra_resources = {"qos": {"qos": "standard"}} @@ -18,10 +21,12 @@ class GromacsBaseCheck(rfm.RunOnlyRegressionTest): @sanity_function def assert_finished(self): + """Sanity check that simulation finished successfully""" return sn.assert_found(r"Finished mdrun", self.keep_files[0]) @performance_function("kJ/mol", perf_key="energy") - def assert_energy(self): + def extract_energy(self): + """Extract value of system energy for performance check""" return sn.extractsingle( r"\s+Potential\s+Kinetic En\.\s+Total Energy" r"\s+Conserved En\.\s+Temperature\n" @@ -35,6 +40,7 @@ def assert_energy(self): @performance_function("ns/day", perf_key="performance") def extract_perf(self): + """Extract value of system energy for performance check""" return sn.extractsingle( r"Performance:\s+(?P\S+)", self.keep_files[0], diff --git a/tests/apps/lammps/dipole_large.py b/tests/apps/lammps/dipole_large.py index 3f14f2a..ba69579 100644 --- a/tests/apps/lammps/dipole_large.py +++ b/tests/apps/lammps/dipole_large.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 """ReFrame script for lammps dipole test""" import reframe as rfm @@ -40,6 +41,4 @@ def setup_nnodes(self): @run_before("run") def setup_resources(self): """sets up number of tasks""" - self.num_tasks = self.n_nodes * self.cores.get( - self.current_partition.fullname, 1 - ) + self.num_tasks = self.n_nodes * self.cores.get(self.current_partition.fullname, 1) diff --git a/tests/apps/lammps/ethanol.py b/tests/apps/lammps/ethanol.py index fc0307d..5bc3f62 100644 --- a/tests/apps/lammps/ethanol.py +++ b/tests/apps/lammps/ethanol.py @@ -30,41 +30,23 @@ class LAMMPSBaseEthanol(LAMMPSBase): ethanol_energy_reference = 537394.35 reference = { - "cirrus:compute": { - "energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol") - }, - "cirrus:compute-gpu": { - "energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol") - }, - "archer2:compute": { - "energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol") - }, - "archer2-tds:compute": { - "energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol") - }, + "cirrus:compute": {"energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol")}, + "cirrus:compute-gpu": {"energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol")}, + "archer2:compute": {"energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol")}, + "archer2-tds:compute": {"energy": (ethanol_energy_reference, -0.01, 0.01, "kJ/mol")}, } @rfm.simple_test -class LAMMPSARCHER2EthanolCPU(LAMMPSBaseEthanol): +class LAMMPSEthanolCPU(LAMMPSBaseEthanol): """ReFrame LAMMPS Ethanol test for performance checks""" valid_systems = ["archer2:compute", "cirrus:compute"] descr = LAMMPSBaseEthanol.descr + " -- CPU" - reference["archer2:compute"]["performance"] = ( - 16.800, - -0.05, - 0.05, - "ns/day", - ) - reference["archer2-tds:compute"]["performance"] = ( - 1, - -0.01, - 0.01, - "ns/day", - ) - reference["cirrus:compute"]["performance"] = (4.8, -0.05, 0.05, "ns/day") + reference["archer2:compute"]["performance"] = (16.800, -0.05, None, "ns/day") + reference["archer2-tds:compute"]["performance"] = (16.800, -0.05, None, "ns/day") + reference["cirrus:compute"]["performance"] = (4.8, -0.05, None, "ns/day") @run_after("init") def setup_nnodes(self): @@ -77,40 +59,50 @@ def setup_nnodes(self): @run_before("run") def setup_resources(self): """sets up number of tasks""" - self.num_tasks = self.n_nodes * self.cores.get( - self.current_partition.fullname, 1 - ) + self.num_tasks = self.n_nodes * self.cores.get(self.current_partition.fullname, 1) @rfm.simple_test -class LAMMPSARCHER2EthanolGPU(LAMMPSBaseEthanol): +class LAMMPSEthanolGPU(LAMMPSBaseEthanol): """ReFrame LAMMPS Ethanol test for performance checks""" valid_systems = ["cirrus:compute-gpu"] descr = LAMMPSBaseEthanol.descr + " -- GPU" modules = ["lammps-gpu"] extra_resources = { - "qos": {"qos": "short"}, "gpu": {"num_gpus_per_node": "4"}, } - env_vars["PARAMS"] = '"--exclusive --ntasks=40 --tasks-per-node=40"' + exclusive_access = True + tags = LAMMPSBase.tags.union({"gpu"}) n_nodes = 1 num_tasks = None num_cpus_per_task = None - executable_opts = LAMMPSBaseEthanol.executable_opts + ["-sf gpu -pk gpu 4"] + reference["cirrus:compute-gpu"]["performance"] = (9.4, -0.05, None, "ns/day") - reference["cirrus:compute-gpu"]["performance"] = ( - 9.4, - -0.05, - 0.05, - "ns/day", - ) + @run_after("init") + def setup_nnodes(self): + """sets up number of tasks per node""" + # unfinished + if self.current_system.name in ["archer2"]: + # self.num_tasks_per_node = 32 + self.extra_resources["qos"] = {"qos": "gpu-exc"} + self.executable_opts = LAMMPSBaseEthanol.executable_opts + [ + "-k on g 4 -sf kk -pk kokkos newton on neigh half" + ] + elif self.current_system.name in ["cirrus"]: + self.executable_opts = LAMMPSBaseEthanol.executable_opts + ["-sf gpu -pk gpu 4"] + self.extra_resources["qos"] = {"qos": "short"} + self.num_tasks_per_node = 40 @run_after("setup") def setup_gpu_options(self): """sets up different resources for gpu systems""" - # Cirrus slurm demands it be done this way. + self.env_vars[ + "PARAMS" + ] = f'"--exclusive --ntasks={self.num_tasks_per_node} --tasks-per-node={self.num_tasks_per_node}"' + # Cirru slurm demands it be done this way. # Trying to add $PARAMS directly to job.launcher.options fails. - self.job.launcher.options.append("${PARAMS}") + if self.current_system.name in ["cirrus"]: + self.job.launcher.options.append("${PARAMS}") diff --git a/tests/apps/lammps/exaalt_ref.py b/tests/apps/lammps/exaalt_ref.py index 3c62549..0109ba5 100644 --- a/tests/apps/lammps/exaalt_ref.py +++ b/tests/apps/lammps/exaalt_ref.py @@ -20,7 +20,7 @@ class ExaaltLammpsRef(LAMMPSBase): "-var nx 1024", "-var ny 1024", "-var nz 1024", - "-var nsteps 100" + "-var nsteps 100", ] n_nodes = 1024 @@ -35,7 +35,6 @@ class ExaaltLammpsRef(LAMMPSBase): }, ) - reference = { "archer2:compute": { "performance": (0.004, -0.1, 0.1, "ns/day"), @@ -51,7 +50,4 @@ def setup_nnodes(self): @run_before("run") def setup_resources(self): """sets up number of tasks""" - self.num_tasks = self.n_nodes * self.cores.get( - self.current_partition.fullname, 1 - ) - + self.num_tasks = self.n_nodes * self.cores.get(self.current_partition.fullname, 1) diff --git a/tests/apps/lammps/exaalt_small.py b/tests/apps/lammps/exaalt_small.py index 2ccccc7..234a18d 100644 --- a/tests/apps/lammps/exaalt_small.py +++ b/tests/apps/lammps/exaalt_small.py @@ -17,7 +17,7 @@ class ExaaltLammpsSmall(LAMMPSBase): "-var nx 256", "-var ny 256", "-var nz 256", - "-var nsteps 100" + "-var nsteps 100", ] n_nodes = 16 @@ -32,7 +32,6 @@ class ExaaltLammpsSmall(LAMMPSBase): }, ) - reference = { "archer2:compute": { "performance": (0.009, -0.1, 0.1, "ns/day"), @@ -48,6 +47,4 @@ def setup_nnodes(self): @run_before("run") def setup_resources(self): """sets up number of tasks""" - self.num_tasks = self.n_nodes * self.cores.get( - self.current_partition.fullname, 1 - ) + self.num_tasks = self.n_nodes * self.cores.get(self.current_partition.fullname, 1) diff --git a/tests/apps/lammps/lammps_base.py b/tests/apps/lammps/lammps_base.py index e89749e..2b1236b 100644 --- a/tests/apps/lammps/lammps_base.py +++ b/tests/apps/lammps/lammps_base.py @@ -6,7 +6,7 @@ class LAMMPSBase(rfm.RunOnlyRegressionTest): """ReFrame base class for LAMMPS tests""" - valid_prog_environs = ["PrgEnv-gnu", "intel", "nvidia-mpi"] + valid_prog_environs = ["PrgEnv-gnu", "intel", "nvidia-mpi", "rocm-PrgEnv-cray"] executable = "lmp" extra_resources = {"qos": {"qos": "standard"}} diff --git a/tests/apps/namd/namd_base.py b/tests/apps/namd/namd_base.py index b525bb4..88b36cb 100644 --- a/tests/apps/namd/namd_base.py +++ b/tests/apps/namd/namd_base.py @@ -3,8 +3,6 @@ import reframe as rfm import reframe.utility.sanity as sn -from reframe.core.builtins import performance_function, sanity_function, run_after, run_before, variable - class NAMDBase(rfm.RunOnlyRegressionTest): """ReFrame base class for NAMD tests""" @@ -26,6 +24,7 @@ class NAMDBase(rfm.RunOnlyRegressionTest): @run_after("setup") def setup_resources(self): + """setup resources""" self.num_cpus_per_task = self.num_cores_per_task[self.current_partition.fullname] self.num_tasks_per_node = self.current_partition.processor.num_cpus // self.num_cpus_per_task @@ -40,10 +39,14 @@ def setup_resources(self): pemap.append(f"{self.num_cpus_per_task * i + 1}-{self.num_cpus_per_task * (i + 1) - 1}") commap.append(str(self.num_cpus_per_task * i)) - self.executable_opts = f"+setcpuaffinity +ppn {self.num_cpus_per_task - 1} +pemap {','.join(pemap)} +commap {','.join(commap)}".split() + self.executable_opts = ( + f"+setcpuaffinity +ppn {self.num_cpus_per_task - 1} " + "+pemap {','.join(pemap)} +commap {','.join(commap)}".split() + ) @run_before("run", always_last=True) def set_input_file(self): + """setup input file""" self.executable_opts.append(self.input_file) @sanity_function @@ -75,9 +78,11 @@ def extract_perf(self): class NAMDNoSMPMixin(rfm.RegressionMixin): + """NAMD no SMP test""" @run_after("setup", always_last=True) def remove_smp(self): + """remove smp""" self.modules = ["namd/2.14-nosmp"] proc = self.current_partition.processor @@ -91,11 +96,14 @@ def remove_smp(self): class NAMDGPUMixin(rfm.RegressionMixin): + """NAMD GPU test""" gpus_per_node = variable(int) + executable_opts = [] @run_after("setup", always_last=True) def add_gpu_devices(self): + """GPU devices""" self.modules = ["namd/2022.07.21-gpu"] devices = [str(i) for i in range(self.gpus_per_node)] @@ -104,7 +112,8 @@ def add_gpu_devices(self): # Cannot specify tasks or CPUs as SBATCH options on the GPU partition. # CPUs are assigned based on the number of GPUs requested. self.job.launcher.options.append( - f"--cpus-per-task={self.num_cpus_per_task} --ntasks={self.num_tasks} --tasks-per-node={self.num_tasks_per_node}" + f"--cpus-per-task={self.num_cpus_per_task} --ntasks={self.num_tasks} " + f"--tasks-per-node={self.num_tasks_per_node}" ) self.num_cpus_per_task = None self.num_tasks = None diff --git a/tests/apps/namd/namd_stmv.py b/tests/apps/namd/namd_stmv.py index cbff3aa..9fb8e00 100644 --- a/tests/apps/namd/namd_stmv.py +++ b/tests/apps/namd/namd_stmv.py @@ -1,14 +1,19 @@ +#!/usr/bin/env python3 +"""NAMD stmv tests""" + import reframe as rfm -from reframe.core.builtins import run_after, run_before, variable, fixture -from namd_base import NAMDBase, NAMDNoSMPMixin, NAMDGPUMixin +from namd_base import NAMDBase, NAMDGPUMixin, NAMDNoSMPMixin class DownloadStmvSource(rfm.CompileOnlyRegressionTest): + """Download STVM""" + build_system = "CustomBuild" @run_before("compile") def setup_build(self): + """Setup build""" self.build_system.commands = [ "wget https://www.ks.uiuc.edu/Research/namd/utilities/stmv.tar.gz", "sha256sum -c stmv_sha256sum.txt", @@ -33,21 +38,11 @@ class NAMDStmvBase(NAMDBase): energy_reference = -2451700.0 reference = { - "archer2:compute": { - "energy": (energy_reference, -0.005, 0.005, "kcal/mol"), - }, - "archer2-tds:compute": { - "energy": (energy_reference, -0.005, 0.005, "kcal/mol"), - }, - "cirrus:compute": { - "energy": (energy_reference, -0.005, 0.005, "kcal/mol"), - }, - "cirrus:highmem": { - "energy": (energy_reference, -0.005, 0.005, "kcal/mol"), - }, - "cirrus:compute-gpu": { - "energy": (energy_reference, -0.005, 0.005, "kcal/mol"), - }, + "archer2:compute": {"energy": (energy_reference, -0.005, 0.005, "kcal/mol")}, + "archer2-tds:compute": {"energy": (energy_reference, -0.005, 0.005, "kcal/mol")}, + "cirrus:compute": {"energy": (energy_reference, -0.005, 0.005, "kcal/mol")}, + "cirrus:highmem": {"energy": (energy_reference, -0.005, 0.005, "kcal/mol")}, + "cirrus:compute-gpu": {"energy": (energy_reference, -0.005, 0.005, "kcal/mol")}, } n_nodes = variable( @@ -71,6 +66,7 @@ class NAMDStmvBase(NAMDBase): @run_after("setup") def setup_resources(self): + """Setup resources""" self.sourcesdir = self.build_source_fixture.stagedir self.num_nodes = self.n_nodes[self.current_partition.fullname] super().setup_resources() @@ -78,84 +74,35 @@ def setup_resources(self): @rfm.simple_test class NAMDStmvCPU(NAMDStmvBase): + """NAMD STVM CPU test""" descr = NAMDStmvBase.descr + " -- CPU" - reference["archer2:compute:performance"] = ( - 5.28, - -0.05, - 0.05, - "ns/day", - ) - - reference["archer2-tds:compute:performance"] = ( - 5.28, - -0.05, - 0.05, - "ns/day", - ) - - reference["cirrus:compute:performance"] = ( - 0.389, - -0.05, - 0.05, - "ns/day", - ) - - reference["cirrus:highmem:performance"] = ( - 0.371, - -0.05, - 0.05, - "ns/day", - ) + reference["archer2:compute:performance"] = (5.28, -0.05, 0.05, "ns/day") + reference["archer2-tds:compute:performance"] = (5.28, -0.05, 0.05, "ns/day") + reference["cirrus:compute:performance"] = (0.389, -0.05, 0.05, "ns/day") + reference["cirrus:highmem:performance"] = (0.371, -0.05, 0.05, "ns/day") @rfm.simple_test class NAMDStmvCPUNoSMP(NAMDStmvBase, NAMDNoSMPMixin): + """NAMD STVM CPU no SMP""" descr = NAMDStmvBase.descr + " -- CPU, No SMP" - reference["archer2:compute:performance"] = ( - 5.31, - -0.05, - 0.05, - "ns/day", - ) - - reference["archer2-tds:compute:performance"] = ( - 5.31, - -0.05, - 0.05, - "ns/day", - ) - - reference["cirrus:compute:performance"] = ( - 0.407, - -0.05, - 0.05, - "ns/day", - ) - - reference["cirrus:highmem:performance"] = ( - 0.377, - -0.05, - 0.05, - "ns/day", - ) + reference["archer2:compute:performance"] = (5.31, -0.05, 0.05, "ns/day") + reference["archer2-tds:compute:performance"] = (5.31, -0.05, 0.05, "ns/day") + reference["cirrus:compute:performance"] = (0.407, -0.05, 0.05, "ns/day") + reference["cirrus:highmem:performance"] = (0.377, -0.05, 0.05, "ns/day") @rfm.simple_test class NAMDStmvGPU(NAMDStmvBase, NAMDGPUMixin): - + "NAMD STVM GPU" "" valid_systems = ["cirrus:compute-gpu"] descr = NAMDStmvBase.descr + " -- GPU" gpus_per_node = 4 qos = "short" - reference["cirrus:compute-gpu:performance"] = ( - 4.92, - -0.05, - 0.05, - "ns/day", - ) + reference["cirrus:compute-gpu:performance"] = (4.92, -0.05, 0.05, "ns/day") diff --git a/tests/apps/opensbli/tgv1024.py b/tests/apps/opensbli/tgv1024.py index 7a5ffb3..e1a1c52 100644 --- a/tests/apps/opensbli/tgv1024.py +++ b/tests/apps/opensbli/tgv1024.py @@ -1,52 +1,51 @@ -import itertools -import os +#!/usr/bin/env python3 + +"""ReFrame test for OpenSBLI""" import reframe as rfm import reframe.utility.sanity as sn class OpenSBLIBaseCheck(rfm.RunOnlyRegressionTest): - def __init__(self): - super().__init__() + """Base class for SBLI test""" + + executable = "./OpenSBLI_mpi_openmp" + maintainers = ["a.turner@epcc.ed.ac.uk"] + tags = {"applications", "performance", "largescale"} + strict_check = False + use_multithreading = False + extra_resources = {"qos": {"qos": "standard"}} + + @sanity_function + def assert_finished(self): + """Sanity check that job finished successfully""" + return sn.assert_found("Time taken for 1 iteration", self.stdout) + + @performance_function("s/iter", perf_key="performance") + def extract_perf(self): + """Extract performance value to compare with reference value""" + return ( + sn.extractsingle( + r"Time taken for 1 iteration,\s+(?P