Skip to content

Commit 95731ba

Browse files
author
Vasileios Karakasis
authored
Merge branch 'master' into sanity_slurm_tests
2 parents 14cb915 + 69dff6d commit 95731ba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1020
-588
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
[![Slack](https://reframe-slack.herokuapp.com/badge.svg)](https://reframe-slack.herokuapp.com/)<br/>
1414
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
1515
[![DOI](https://zenodo.org/badge/89384186.svg)](https://zenodo.org/badge/latestdoi/89384186)<br/>
16-
![Twitter Follow](https://img.shields.io/twitter/follow/ReFrameHPC?style=social)
16+
[![Twitter Follow](https://img.shields.io/twitter/follow/ReFrameHPC?style=social)](https://twitter.com/ReFrameHPC)
1717

1818
# ReFrame in a Nutshell
1919

bootstrap.sh

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
# Bootstrap script for running ReFrame from source
1010
#
1111

12-
BLUE='\033[0;34m'
13-
GREEN='\033[0;32m'
14-
YELLOW='\033[0;33m'
15-
NC='\033[0m'
12+
if [ -t 1 ]; then
13+
BLUE='\033[0;34m'
14+
GREEN='\033[0;32m'
15+
YELLOW='\033[0;33m'
16+
NC='\033[0m'
17+
fi
1618

1719
CMD()
1820
{
@@ -70,15 +72,16 @@ fi
7072
# Check if ensurepip is installed
7173
$python -m ensurepip --version &> /dev/null
7274

75+
export PATH=$(pwd)/external/usr/bin:$PATH
76+
7377
# Install pip for Python 3
7478
if [ $? -eq 0 ]; then
75-
CMD $python -m ensurepip --root external/ --default-pip
79+
CMD $python -m ensurepip --root $(pwd)/external/ --default-pip
7680
fi
7781

78-
# ensurepip installs pip in `external/usr/` whereas the --target option installs
82+
# ensurepip installs pip in `external/usr/` whereas the `--root` option installs
7983
# everything under `external/`. That's why we include both in the PYTHONPATH
8084

81-
export PATH=$(pwd)/external/usr/bin:$PATH
8285
export PYTHONPATH=$(pwd)/external:$(pwd)/external/usr/lib/python$pyver/site-packages:$PYTHONPATH
8386

8487
CMD $python -m pip install --no-cache-dir -q --upgrade pip --target=external/

cscs-checks/prgenv/cuda-fortran/cuda_fortran_check.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ def __init__(self):
1313
self.valid_systems = ['daint:gpu', 'dom:gpu']
1414
self.valid_prog_environs = ['PrgEnv-pgi']
1515
self.sourcepath = 'vecAdd_cuda.cuf'
16-
17-
# FIXME: PGI 20.x does not support CUDA 11, see case #275674
18-
self.modules = ['craype-accel-nvidia60',
19-
'cudatoolkit/10.2.89_3.29-7.0.2.1_3.5__g67354b4']
16+
self.modules = ['craype-accel-nvidia60']
2017
self.build_system = 'SingleSource'
2118
self.build_system.fflags = ['-ta=tesla:cc60']
2219
self.num_gpus_per_node = 1
@@ -25,3 +22,13 @@ def __init__(self):
2522
self.sanity_patterns = sn.assert_reference(result, 1., -1e-5, 1e-5)
2623
self.maintainers = ['TM', 'AJ']
2724
self.tags = {'production', 'craype'}
25+
26+
# FIXME: PGI 20.x does not support CUDA 11, see case #275674
27+
@rfm.run_before('compile')
28+
def cudatoolkit_pgi_20x_workaround(self):
29+
if self.current_system.name == 'daint':
30+
cudatoolkit_version = '10.2.89_3.29-7.0.2.1_3.5__g67354b4'
31+
else:
32+
cudatoolkit_version = '10.2.89_3.29-7.0.2.1_3.27__g67354b4'
33+
34+
self.modules += [f'cudatoolkit/{cudatoolkit_version}']

docs/_static/img/favicon.png

-1.01 KB
Loading

docs/regression_test_api.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ Regression Test Class Decorators
2929
Pipeline Hooks
3030
--------------
3131

32+
.. versionadded:: 2.20
33+
34+
35+
Pipeline hooks is an easy way to perform operations while the test traverses the execution pipeline.
36+
You can attach arbitrary functions to run before or after any pipeline stage, which are called *pipeline hooks*.
37+
Multiple hooks can be attached before or after the same pipeline stage, in which case the order of execution will match the order in which the functions are defined in the class body of the test.
38+
A single hook can also be applied to multiple stages and it will be executed multiple times.
39+
All pipeline hooks of a test class are inherited by its subclasses.
40+
Subclasses may override a pipeline hook of their parents by redefining the hook function and re-attaching it at the same pipeline stage.
41+
There are seven pipeline stages where you can attach test methods: ``init``, ``setup``, ``compile``, ``run``, ``sanity``, ``performance`` and ``cleanup``.
42+
The ``init`` stage is not a real pipeline stage, but it refers to the test initialization.
43+
44+
Hooks attached to any stage will run exactly before or after this stage executes.
45+
So although a "post-init" and a "pre-setup" hook will both run *after* a test has been initialized and *before* the test goes through the first pipeline stage, they will execute in different times:
46+
the post-init hook will execute *right after* the test is initialized.
47+
The framework will then continue with other activities and it will execute the pre-setup hook *just before* it schedules the test for executing its setup stage.
48+
3249
.. autodecorator:: reframe.core.decorators.run_after(stage)
3350

3451
.. autodecorator:: reframe.core.decorators.run_before(stage)

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
jsonschema==3.2.0
22
semver==2.13.0
3-
Sphinx==3.5.2
3+
Sphinx==3.5.3
44
sphinx-rtd-theme==0.5.1

docs/tutorial_advanced.rst

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,3 +790,63 @@ Therefore, the ``release.txt`` file can now be used in the subsequent sanity che
790790
791791
For a complete list of the available attributes of a specific container platform, please have a look at the :ref:`container-platforms` section of the :doc:`regression_test_api` guide.
792792
On how to configure ReFrame for running containerized tests, please have a look at the :ref:`container-platform-configuration` section of the :doc:`config_reference`.
793+
794+
795+
Writing reusable tests
796+
----------------------
797+
798+
.. versionadded:: 3.5.0
799+
800+
So far, all the examples shown above were tight to a particular system or configuration, which makes reusing these tests in other systems not straightforward.
801+
However, the introduction of the :py:func:`~reframe.core.pipeline.RegressionTest.parameter` and :py:func:`~reframe.core.pipeline.RegressionTest.variable` ReFrame built-ins solves this problem, eliminating the need to specify any of the test variables in the :func:`__init__` method.
802+
Hence, these parameters and variables can be treated as simple class attributes, which allows us to leverage Python's class inheritance and write more modular tests.
803+
For simplicity, we illustrate this concept with the above :class:`ContainerTest` example, where the goal here is to re-write this test as a library that users can simply import from and derive their tests without having to rewrite the bulk of the test.
804+
Also, for illustrative purposes, we parameterize this library test on a few different image tags (the above example just used ``ubuntu:18.04``) and throw the container commands into a separate bash script just to create some source files.
805+
Thus, removing all the system and configuration specific variables, and moving as many assignments as possible into the class body, the system agnostic library test looks as follows:
806+
807+
.. code-block:: console
808+
809+
cat tutorials/advanced/library/lib/__init__.py
810+
811+
812+
.. literalinclude:: ../tutorials/advanced/library/lib/__init__.py
813+
:lines: 6-
814+
:emphasize-lines: 8-17
815+
816+
Note that the class :class:`ContainerBase` is not decorated since it does not specify the required variables ``valid_systems`` and ``valid_prog_environs``, and it declares the ``platform`` parameter without any defined values assigned.
817+
Hence, the user can simply derive from this test and specialize it to use the desired container platforms.
818+
Since the parameters are defined directly in the class body, the user is also free to override or extend any of the other parameters in a derived test.
819+
In this example, we have parametrized the base test to run with the ``ubuntu:18.04`` and ``ubuntu:20.04`` images, but these values from ``dist`` (and also the ``dist_name`` variable) could be modified by the derived class if needed.
820+
821+
On the other hand, the rest of the test depends on the values from the test parameters, and a parameter is only assigned a specific value after the class has been instantiated.
822+
Thus, the rest of the test is expressed as hooks, without the need to write anything in the :func:`__init__` method.
823+
In fact, writing the test in this way permits having hooks that depend on undefined variables or parameters.
824+
This is the case with the :func:`set_container_platform` hook, which depends on the undefined parameter ``platform``.
825+
Hence, the derived test **must** define all the required parameters and variables; otherwise ReFrame will notice that the test is not well defined and will raise an error accordingly.
826+
827+
Before moving onwards to the derived test, note that the :class:`ContainerBase` class takes the additional argument ``pin_prefix=True``, which locks the prefix of all derived tests to this base test.
828+
This will allow the retrieval of the sources located in the library by any derived test, regardless of what their containing directory is.
829+
830+
.. code-block:: console
831+
832+
cat tutorials/advanced/library/lib/src/get_os_release.sh
833+
834+
835+
.. literalinclude:: ../tutorials/advanced/library/lib/src/get_os_release.sh
836+
:lines: 1-
837+
838+
Now from the user's perspective, the only thing to do is to import the above base test and specify the required variables and parameters.
839+
For consistency with the above example, we set the ``platform`` parameter to use Sarus and Singularity, and we configure the test to run on Piz Daint with the built-in programming environment.
840+
Hence, the above :class:`ContainerTest` is now reduced to the following:
841+
842+
.. code-block:: console
843+
844+
cat tutorials/advanced/library/usr/container_test.py
845+
846+
847+
.. literalinclude:: ../tutorials/advanced/library/usr/container_test.py
848+
:lines: 6-
849+
850+
In a similar fashion, any other user could reuse the above :class:`ContainerBase` class and write the test for their own system with a few lines of code.
851+
852+
*Happy test sharing!*

docs/tutorial_basics.rst

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ We extend our C++ "Hello, World!" example to print the greetings from multiple t
417417
:language: cpp
418418
:lines: 6-
419419

420-
This program takes as argument the number of threads it will create and it uses ``std::thread``, which is C++11 addition, meaning that we will need to pass ``-std=c++11`` to our compilers.
420+
This program takes as argument the number of threads it will create and it uses ``std::thread``, which is a C++11 addition, meaning that we will need to pass ``-std=c++11`` to our compilers.
421421
Here is the corresponding ReFrame test, where the new concepts introduced are highlighted:
422422

423423
.. code-block:: console
@@ -429,12 +429,30 @@ Here is the corresponding ReFrame test, where the new concepts introduced are hi
429429
:lines: 6-
430430
:emphasize-lines: 11-13
431431

432+
433+
In order to compile applications using ``std::thread`` with GCC and Clang, the ``-pthread`` option has to be passed to the compiler.
434+
Since the above option might not be valid for other compilers, we use pipeline hooks to differentiate based on the programming environment as follows:
435+
436+
.. code-block:: python
437+
438+
@rfm.run_before('compile')
439+
def set_threading_flags(self):
440+
environ = self.current_environ.name
441+
if environ in {'clang', 'gnu'}:
442+
self.build_system.cxxflags += ['-pthread']
443+
444+
445+
.. note::
446+
447+
The pipeline hooks, as well as the regression test pipeline itself, are covered in more detail later on in the tutorial.
448+
449+
432450
ReFrame delegates the compilation of a test to a *build system*, which is an abstraction of the steps needed to compile the test.
433451
Build systems take also care of interactions with the programming environment if necessary.
434452
Compilation flags are a property of the build system.
435453
If not explicitly specified, ReFrame will try to pick the correct build system (e.g., CMake, Autotools etc.) by inspecting the test resources, but in cases as the one presented here where we need to set the compilation flags, we need to specify a build system explicitly.
436-
In this example, we instruct ReFrame to compile a single source file using the ``-std=c++11 -Wall`` compilation flags.
437-
Finally, we set the arguments to be passed to the generated executable in :attr:`~reframe.core.pipeline.RegressionTest.executable_opts`.
454+
In this example, we instruct ReFrame to compile a single source file using the ``-std=c++11 -pthread -Wall`` compilation flags.
455+
Finally, we set the arguments to be passed to the generated executable in :attr:`executable_opts <reframe.core.pipeline.RegressionTest.executable_opts>`.
438456

439457

440458
.. code-block:: console
@@ -1075,7 +1093,7 @@ Let's see and comment the changes:
10751093
First of all, we need to add the new programming environments in the list of the supported ones.
10761094
Now there is the problem that each compiler has its own flags for enabling OpenMP, so we need to differentiate the behavior of the test based on the programming environment.
10771095
For this reason, we define the flags for each compiler in a separate dictionary (``self.flags``) and we set them in the :func:`setflags` pipeline hook.
1078-
Let's explain what is this all about.
1096+
We have first seen the pipeline hooks in the multithreaded "Hello, World!" example and now we explain them in more detail.
10791097
When ReFrame loads a test file, it instantiates all the tests it finds in it.
10801098
Based on the system ReFrame runs on and the supported environments of the tests, it will generate different test cases for each system partition and environment combination and it will finally send the test cases for execution.
10811099
During its execution, a test case goes through the *regression test pipeline*, which is a series of well defined phases.

reframe/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import sys
88

9-
VERSION = '3.6.0-dev.1'
9+
VERSION = '3.6.0-dev.2'
1010
INSTALL_PREFIX = os.path.normpath(
1111
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
1212
)

reframe/core/buildsystems.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ def post_build(self, buildjob):
147147
Build systems may use this information to do some post processing and
148148
provide additional, build system-specific, functionality to the users.
149149
150+
This function will always be executed from the test's stage directory.
151+
150152
.. versionadded:: 3.5.0
153+
.. versionchanged:: 3.5.2
154+
The function is executed from the stage directory.
151155
152156
:meta private:
153157
@@ -741,7 +745,6 @@ def __init__(self):
741745
self.package_opts = {}
742746
self.prefix = 'easybuild'
743747
self._eb_modules = []
744-
self._prefix_save = None
745748

746749
def emit_build_commands(self, environ):
747750
if not self.easyconfigs:
@@ -755,7 +758,6 @@ def emit_build_commands(self, environ):
755758

756759
prefix = os.path.join(os.getcwd(), self.prefix)
757760
options = ' '.join(self.options)
758-
self._prefix_save = prefix
759761
return [f'export EASYBUILD_BUILDPATH={prefix}/build',
760762
f'export EASYBUILD_INSTALLPATH={prefix}',
761763
f'export EASYBUILD_PREFIX={prefix}',
@@ -765,7 +767,8 @@ def emit_build_commands(self, environ):
765767
def post_build(self, buildjob):
766768
# Store the modules generated by EasyBuild
767769

768-
modulesdir = os.path.join(self._prefix_save, 'modules', 'all')
770+
modulesdir = os.path.join(os.getcwd(), self.prefix,
771+
'modules', 'all')
769772
with open(buildjob.stdout) as fp:
770773
out = fp.read()
771774

0 commit comments

Comments
 (0)