From 2f988e8ed9940f254c350377b33c9fa7bf958a9d Mon Sep 17 00:00:00 2001 From: Anthony Islas Date: Wed, 29 Jan 2025 15:22:45 -0700 Subject: [PATCH 1/4] Add the environment helper scripts for testing In order to run test scripts outside of a testing framework, handling of the environment setup should not be solely dependent on running within a dedicated test framework. This has the added benefit of compartmentalizing the duties of environment and dependency solving from running the tests. These environment scripts allow for the selection of a particular environment with the default being the fqdn of the current host. From there, arguments are routed using standard POSIX-sh to a respective script. In the case of Derecho (applicable to any system using lmod) all subsequent argument are treated as modules to load into the current session. The hostenv.sh script relies on one "argument" $AS_HOST being passed in via variable setting to facilitate selection. The helpers.sh script provides convenience features for substring checking in sh, delayed environment variable expansion via eval, and quick banner creation. The derecho.sh script is included as the first supported environment. --- .ci/env/derecho.sh | 22 ++++++++++++++++++++++ .ci/env/helpers.sh | 46 ++++++++++++++++++++++++++++++++++++++++++++++ .ci/env/hostenv.sh | 16 ++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100755 .ci/env/derecho.sh create mode 100644 .ci/env/helpers.sh create mode 100644 .ci/env/hostenv.sh diff --git a/.ci/env/derecho.sh b/.ci/env/derecho.sh new file mode 100755 index 0000000000..2feea5c9ee --- /dev/null +++ b/.ci/env/derecho.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +echo "Setting up derecho environment" +workingDirectory=$PWD +. /etc/profile.d/z00_modules.sh +echo "Loading modules : $*" +cmd="module purge" +echo $cmd && eval "${cmd}" + +# We should be handed in the modules to load +while [ $# -gt 0 ]; do + cmd="module load $1" + echo $cmd && eval "${cmd}" + shift +done + +# Go back to working directory if for unknown reason HPC config changing your directory on you +if [ "$workingDirectory" != "$PWD" ]; then + echo "derecho module loading changed working directory" + echo " Moving back to $workingDirectory" + cd $workingDirectory +fi diff --git a/.ci/env/helpers.sh b/.ci/env/helpers.sh new file mode 100644 index 0000000000..2ddd560893 --- /dev/null +++ b/.ci/env/helpers.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Useful string manipulation functions, leaving in for posterity +# https://stackoverflow.com/a/8811800 +# contains(string, substring) +# +# Returns 0 if the specified string contains the specified substring, +# otherwise returns 1. +contains() +{ + string="$1" + substring="$2" + + if [ "${string#*"$substring"}" != "$string" ]; then + echo 0 # $substring is in $string + else + echo 1 # $substring is not in $string + fi +} + +setenvStr() +{ + # Changing IFS produces the most consistent results + tmpIFS=$IFS + IFS="," + string="$1" + for s in $string; do + if [ ! -z $s ]; then + eval "echo export \"$s\"" + eval "export \"$s\"" + fi + done + IFS=$tmpIFS +} + +banner() +{ + lengthBanner=$1 + shift + # https://www.shellscript.sh/examples/banner/ + printf "#%${lengthBanner}s#\n" | tr " " "=" + printf "# %-$(( ${lengthBanner} - 2 ))s #\n" "`date`" + printf "# %-$(( ${lengthBanner} - 2 ))s #\n" " " + printf "# %-$(( ${lengthBanner} - 2 ))s #\n" "$*" + printf "#%${lengthBanner}s#\n" | tr " " "=" +} diff --git a/.ci/env/hostenv.sh b/.ci/env/hostenv.sh new file mode 100644 index 0000000000..208d1e57f3 --- /dev/null +++ b/.ci/env/hostenv.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# Allow selection of hostname, and if none is provided use the current machine +# While this may seem unintuitive at first, it provides the flexibility of using +# "named" configurations without being explicitly tied to fqdn +hostname=$AS_HOST +if [ -z "$hostname" ]; then + hostname=$( python3 -c "import socket; print( socket.getfqdn() )" ) +fi + +if [ $( contains ${hostname} hsn.de.hpc ) -eq 0 ]; then + # Derecho HPC SuSE PBS + . .ci/env/derecho.sh +else + echo "No known environment for '${hostname}', using current" +fi From ce0a5a1219f763d867e00562494eb27c844d1866 Mon Sep 17 00:00:00 2001 From: Anthony Islas Date: Wed, 29 Jan 2025 15:56:14 -0700 Subject: [PATCH 2/4] Add a compilation test script This script will facilitate the first tests. There are only three requirements of any given test script with the planned testing framework If a different testing framework is used in the future, these requirements of the test scripts can and should be re-evaluated. The test script should : 1. Take the intended host / configuration env as the first argument 2. Take the working directory which we cd to as the second argument 3. Output some key phrase at the end of the test to denote success, anything else (non-zero exit code, no phrase but return zero) is considered failure This particular compilation test script satisfies the above while also providing enough flexibility to select core, target, parallel jobs, and other command-line options into the make build. Additionally, for convenience environment variables can be passed in as command-line options to the test script to modularize certain inputs. --- .ci/tests/build.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100755 .ci/tests/build.sh diff --git a/.ci/tests/build.sh b/.ci/tests/build.sh new file mode 100755 index 0000000000..3431007f52 --- /dev/null +++ b/.ci/tests/build.sh @@ -0,0 +1,90 @@ +#!/bin/sh +help() +{ + echo "./build.sh as_host workingdir [options] [-- ]" + echo " as_host First argument must be the host configuration to use for environment loading" + echo " workingdir Second argument must be the working dir to immediate cd to" + echo " -b Additional make arguments passed in" + echo " -c Core to build" + echo " -t Target configuration (gnu, intel, etc)" + echo " -d Debug build" + echo " -e environment variables in comma-delimited list, e.g. var=1,foo,bar=0" + echo " -- Directly pass options to hostenv.sh, equivalent to hostenv.sh " + echo " -h Print this message" + echo "" + echo "If you wish to use an env var in your arg such as '-b core=\$CORE -e CORE=atmosphere', you must" + echo "you will need to do '-b \\\$CORE -e CORE=atmosphere' to delay shell expansion" +} + +echo "Input arguments:" +echo "$*" + +AS_HOST=$1 +shift +if [ $AS_HOST = "-h" ]; then + help + exit 0 +fi + +workingDirectory=$1 +shift + +cd $workingDirectory + +# Get some helper functions, AS_HOST must be set by this point to work +. .ci/env/helpers.sh + +while getopts b:c:t:de:h opt; do + case $opt in + b) + buildCommand="$OPTARG" + ;; + c) + core="$OPTARG" + ;; + t) + target="$OPTARG" + ;; + d) + debug="DEBUG=true" + ;; + e) + envVars="$envVars,$OPTARG" + ;; + h) help; exit 0 ;; + *) help; exit 1 ;; + :) help; exit 1 ;; + \?) help; exit 1 ;; + esac +done + +shift "$((OPTIND - 1))" + +# Everything else goes to our env setup, POSIX does not specify how to pass in +# arguments to sourced script, but all args are already shifted. This is left for +# posterity to "show" what is happening and the assumption of the remaining args +. .ci/env/hostenv.sh $* + +# Now evaluate env vars in case it pulls from hostenv.sh +if [ ! -z "$envVars" ]; then + setenvStr "$envVars" +fi + +# Re-evaluate input values for delayed expansion +eval "core=\"$core\"" +eval "target=\"$target\"" +eval "buildCommand=\"$buildCommand\"" + +make clean CORE=$core + +echo "Compiling with options $target core=$core $debug $buildCommand" +echo "make $target CORE=$core $debug $buildCommand" +make $target CORE=$core $debug $buildCommand +result=$? + +if [ $result -ne 0 ]; then + echo "Failed to compile" + exit 1 +fi + +echo "TEST $(basename $0) PASS" From 11384b19174a2fde525e480389b19fb7124e635f Mon Sep 17 00:00:00 2001 From: Anthony Islas Date: Wed, 29 Jan 2025 16:01:45 -0700 Subject: [PATCH 3/4] Add a framework to easily facilitate testing --- .ci/hpc-workflows | 1 + .gitmodules | 3 +++ 2 files changed, 4 insertions(+) create mode 160000 .ci/hpc-workflows create mode 100644 .gitmodules diff --git a/.ci/hpc-workflows b/.ci/hpc-workflows new file mode 160000 index 0000000000..97ca807b0e --- /dev/null +++ b/.ci/hpc-workflows @@ -0,0 +1 @@ +Subproject commit 97ca807b0e1b7d67a35ab10e938b29774242e48e diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..c96aa594e8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".ci/hpc-workflows"] + path = .ci/hpc-workflows + url = https://github.com/islas/hpc-workflows/ From a6acfcdf6fa0da299c62b6135f3370e9362adcbc Mon Sep 17 00:00:00 2001 From: Anthony Islas Date: Wed, 29 Jan 2025 16:02:19 -0700 Subject: [PATCH 4/4] Add a simple test definition for testing GNU 12.2.0 compilation Following the documentation of the hpc-workflows testing framework and the testing structure found in .ci/, a JSON file for a GNU compilation test was added. This test will compile the atmosphere core using gnu + single precision. If this test is run using the derecho configuration the appropriate modules will attempt to be loaded. For non-derecho environments, per the testing structure under .ci/, if no configuration exists in .ci/hostenv.sh then the current environment will be used verbatim. --- .ci/mpas_compilation.jsonc | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .ci/mpas_compilation.jsonc diff --git a/.ci/mpas_compilation.jsonc b/.ci/mpas_compilation.jsonc new file mode 100644 index 0000000000..31e393e261 --- /dev/null +++ b/.ci/mpas_compilation.jsonc @@ -0,0 +1,48 @@ +// MPAS Compilation tests +{ + "submit_options" : + { + // Default values + "timelimit" : "00:15:00", + "working_directory" : "..", + "arguments" : + { + "base_env_numprocs" : [ "-e", "NUM_PROCS=4" ], + + ".*make.*::args_build_core" : [ "-c", "atmosphere" ], + ".*debug.*::args_build_debug" : [ "-d" ], + ".*make.*::args_build_options" : [ "-b", "-j $NUM_PROCS" ], + ".*make.*gnu.*::args_target" : [ "-t", "gnu" ] + }, + // Derecho-specifics + "hsn.de.hpc" : + { + "submission" : "PBS", + "queue" : "main", + "hpc_arguments" : + { + "node_select" : { "-l " : { "select" : 1, "ncpus" : 16 } }, + "priority" : { "-l " : { "job_priority" : "economy" } } + }, + "arguments" : + { + // We want NUM_PROCS to match ncpus + "base_env_numprocs" : [ "-e", "NUM_PROCS=16" ], + "very_last_modules" : [ "cray-mpich", "parallel-netcdf" ], + ".*gnu.*::test_modules" : [ "gcc/12.2.0" ] + } + } + }, + // Specific GNU compilation test + "make-gnu" : + { + "steps" : + { + // Eventually include debug and other compile modes + "optimized" : + { + "command" : ".ci/tests/build.sh" + } + } + } +}