.. _buildtest_aws: Buildtest Tutorial on AWS ========================= Setup ----- This section of tutorial will be completed in `Amazon Web Services (AWS) `_ environment. Once you have access to system, please :ref:`installing_buildtest` and then proceed to the next section. Once you are done, please run the following commands to ensure you are using the correct configuration file .. code-block:: bash export BUILDTEST_CONFIGFILE=$BUILDTEST_ROOT/buildtest/settings/aws.yml buildtest config path You can verify the configuration is valid by runnning the following:: buildtest config validate If you see no errors, then you are ready to proceed to the next section. Hello World Compilation ----------------------- Let's start off with a simple hello world compilation in C using the GNU compiler. We have the following buildspec that will compile a code source code ``hello.c`` using the ``gcc`` compiler wrapper. .. literalinclude:: ../../aws_tutorial/hello_world/hello.yml :language: yaml :emphasize-lines: 7-8 The source code is the following .. literalinclude:: ../../aws_tutorial/hello_world/hello.c :language: c Let's try building this example and inspect the test results to see what happens. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/hello_world/hello.yml`` .. program-output:: cat aws_examples/hello_build.txt .. program-output:: cat aws_examples/hello_inspect.txt Multi Compiler Test ------------------- Buildtest supports multiple test creation based on compiler selection using ``compilers`` property. This can be useful to test a single test with multiple compilers. In this next example, we will attempt to compile the Hello World test in previous example using 2 versions of GNU compiler. The ``name`` property is used to search for compilers in the configuration file. The :ref:`compilers` section covers in detail how to define compilers in buildtest configuration. .. literalinclude:: ../../aws_tutorial/hello_world/multi_compiler_hello.yml :language: yaml :emphasize-lines: 6-7 Let's try building this example, you will see there are now 2 tests created, one for each compiler. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/hello_world/multi_compiler_hello.yml`` .. program-output:: cat aws_examples/multi_compiler_hello_build.txt Take note in the generated test output, the variables **BUILDTEST_CC**, **BUILDTEST_CXX** and **BUILDTEST_FC** are using the compiler wrappers for each compiler. .. program-output:: cat aws_examples/multi_compiler_hello_inspect.txt We can see the compiler configuration using the command ``buildtest config compilers list --yaml`` which will print the output in YAML format. Shown below is the compiler declaration .. program-output:: cat aws_examples/compiler_list_yaml.txt OpenMP Test with custom compiler configuration ---------------------------------------------- In this next example, we will compile a OpenMP code using GNU compiler and specify custom compiler flags and environment variable. We will work with a Hello World OpenMP code that uses OpenMP pragma to parallelize the code. The source code is the following .. literalinclude:: ../../aws_tutorial/openmp_hello.c :language: c In order to build OpenMP code, we need to use ``-fopenmp`` flag to enable OpenMP support. We will set ``OMP_NUM_THREADS`` environment variable to specify number of OpenMP theads which will differ for each compiler test. We introduce a keyword ``config`` that allows us to specify customize compiler flags and environment variables. The ``env`` property is used to set environment variable for each compiler test and ``cflags`` is used to set compiler flags inorder to compile the test. This value is stored in environment **BUILDTEST_CFLAGS** that will be used in ``run`` section for compiling the source code. .. literalinclude:: ../../aws_tutorial/openmp_example_custom_compiler.yml :language: yaml :emphasize-lines: 6-19 Let's try building this example and inspect the test results to see what happens. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/openmp_example_custom_compiler.yml`` .. program-output:: cat aws_examples/openmp_example_build.txt We will see in the generated test the values ``OMP_NUM_THREADS`` and ``BUILDTEST_CFLAGS`` are set for each compiler test. The ``OMP_NUM_THREADS`` will impact the number of threads used to run code therefore we will see different output for each compiler test. .. program-output:: cat aws_examples/openmp_example_inspect.txt Testing a MPI Code -------------------- This image comes with several MPI flavors such as OpenMPI, mvapich2. In the next example we will run a MPI Proc Name test on login node that will run with 8 processes. The source code is available in the ``$HOME/examples`` directory as part of the image. .. literalinclude:: ../../aws_tutorial/mpiproc.yml :language: yaml :emphasize-lines: 8-9 We can run this test using the following command .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/mpiproc.yml`` .. program-output:: cat aws_examples/mpiproc_build.txt We can see this test prints Hello World message from each process. .. program-output:: cat aws_examples/mpiproc_inspect.txt MPI Job Submission ------------------ This cluster comes with PBS/Torque scheduler. We can run the MPI test to batch scheduler. Shown below is an example buildspec. We will use an executor named a torque executor named ``generic.torque.e4spro-cluster`` that is mapped to a queue named ``e4spro-cluster``. The ``pbs`` property is used to specify PBS directives. We will run this test on a single node using 2 processors with a wall time of 1hr. .. literalinclude:: ../../aws_tutorial/mpi_job_submission.yml :language: yaml :emphasize-lines: 4,6 We can run this test by running the following commands. The ``--pollinterval 10`` will be used to poll job every 10 sec and retrieve job status. Buildtest will keep polling job until job is complete. The ``--display output --display test`` will show content of output, error and generated test files during the build phase. You will notice the generated build script (**_build.sh**) will invoke ``qsub`` command to a generated test. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/mpi_job_submission.yml --pollinterval 10 --display output --display test`` .. program-output:: cat aws_examples/mpi_job_submission_build.txt OSU Microbenchmark ------------------- The `OSU Microbenchmark `_ is a collection of MPI-based benchmarks developed at Ohio State University. This benchmark is used to measure performance of MPI libraries and is a popular benchmark suite for MPI. We will run the ``osu_bw`` test which measures bandwidth. The test requires we specify 2 processes. In this next example, we will run 2 tests, the first is simply invoking the ``osu_bw`` test with 2 processes, and the second test will run the same test and use :ref:`comparison_operators ` to compare the bandwidth result. The ``metrics`` property is used to capture performance metrics that can be used for comparison. We will use the :ref:`assert_ge ` status check that will do a greater than or equal comparison with reference value. The metrics will capture performance results for message length **16384** and perform a comparison with reference value of 10000. If the test result is greater than or equal to 10000, the test will pass otherwise it will fail. .. literalinclude:: ../../aws_tutorial/osu_bandwidth_test.yml :language: yaml :emphasize-lines: 6, 13-24 Let's run the test and see the results. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/aws_tutorial/osu_bandwidth_test.yml`` .. program-output:: cat aws_examples/osu_bandwidth_test_build.txt Take note in the output of the second test, we will see a list of performance metrics captured in table output. If metrics is not captured, the value will be undefined. .. program-output:: cat aws_examples/osu_bandwidth_test_inspect.txt Tensorflow Test --------------- In this next exercise, we provide a tensorflow test in python that train a model and generate a predicition model. We have the following source code .. literalinclude:: ../../aws_tutorial/tensorflow_model.py :language: python The buildspec for this test is the following, where we run the test using ``python3`` interpreter. .. literalinclude:: ../../aws_tutorial/tensorflow.yml :language: yaml Please run the test yourself and inspect the output. You will want to run the following commands:: buildtest build -b $BUILDTEST_ROOT/aws_tutorial/tensorflow.yml buildtest inspect query -o run_tensorflow_model Running Tests in Containers ---------------------------- Buildtest has support for :ref:`running tests in containers ` such as ``docker`` and ``singularity``. In this next examples, we will show how to run a hello world test in ``docker`` and ``singularity`` container. Let's start off with ``docker``, we introduce a new property ``container`` that allows us to specify the container settings. The ``platform`` and ``image`` are required properties that specifies the container platform (e.g., docker, singularity, podman) and the image name. .. literalinclude:: ../tutorials/containers/hello_world.yml :language: yaml :emphasize-lines: 6-8 Let's run the test and inspect the output, you will notice the test output will print a message from the container. This test will run in a docker container, if you look at the generated test content you will see a ``docker run`` invocation. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/tutorials/containers/hello_world.yml`` .. program-output:: cat aws_examples/docker_helloworld_build.txt .. program-output:: cat aws_examples/docker_helloworld_inspect.txt In the next example, we will run the same test in a ``singularity`` container. To do this we will simply change the ``platform`` to ``singularity`` and specify the ``image`` name. Since singularity can pull images from different registries we will specify ``docker:://`` prefix to pull the image from docker hub. .. literalinclude:: ../tutorials/containers/hello_world_singularity.yml :language: yaml :emphasize-lines: 6-8 Buildtest will invoke ``singularity run`` and bind mount the stage directory into the container and execute test from the container. Take note that that singularity will volume mount test into ``/buildtest`` in the container and then run test from that directory. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/tutorials/containers/hello_world_singularity.yml`` .. program-output:: cat aws_examples/singularity_helloworld_build.txt .. program-output:: cat aws_examples/singularity_helloworld_inspect.txt In this last example, we will run a test using a :ref:`container executor ` by defining a custom executor based on a container image. In all of our previous examples, we were running tests using executor ``generic.local.bash`` which is a generic executor that runs tests on the local system using ``bash`` shell. Let's take a look at the executor configuration by running the following command. The ``container`` keyword under ``executors`` section is used to define container executors. We can specify arbitrary name for the executor and specify the container image and platform. .. program-output:: cat aws_examples/container_executor_list.txt We have the following buildspec that will run test using a custom executor ``generic.container.ubuntu``. .. literalinclude:: ../tutorials/containers/container_executor/ubuntu.yml :language: yaml :emphasize-lines: 4 Let's run the test and inspect the output. You will notice the test is run in a ubuntu 20.04 container. In the output of ``df -h`` you will see the filesystem is from the container image with an entry ``/buildtest`` that is bind mounted from the host system. .. dropdown:: ``buildtest build -b $BUILDTEST_ROOT/tutorials/containers/container_executor/ubuntu.yml`` .. program-output:: cat aws_examples/container_executor_build.txt .. program-output:: cat aws_examples/container_executor_inspect.txt