Using uenv to build and run applications on Alps¶
logging in¶
Once you have set up your ssh token, an easy way to simplify login in is by updating your ~/.ssh/config
:
> cat ~/.ssh/config
Host ela
HostName ela.cscs.ch
ForwardAgent yes
User bcumming
Host daint.alps
HostName daint-ln001.cscs.ch
ProxyJump ela
User bcumming
Then log into one of the systems using the alias defined in the config file:
setting up for the first time¶
First, check that uenv has been installed on the system:
Before using uenv, a repository (repo) for storing downloaded (pulled) needs to be created.
e.g. try the following command that lists the downloaded uenv:
Create a repo in the default location
# get help on the repo command
uenv repo --help
# find the status of the default repo
uenv repo status
# create the new repo
uenv repo create
find $SCRATCH/.uenv-images
finding and pulling images¶
To search for the uenv that are provided by CSCS, use the uenv image find
command when logged in:
uenv image find # all uenv on the current system
uenv image find cp2k # all cp2k images on the current system
uenv image find cp2k/2024.2 # refine the search
uenv image find cp2k/2024.2:v1 # refine the search
uenv image find --system=eiger # choose the system
uenv iamge find --uarch=gh200 # choose the uarch
To download an image, use the uenv image pull
command
There might be more than one uenv that matches the description. If so, be more specific:
- use the full disambiguated name
- use the image hash or id
- specify the uarch
uenv image pull editors/24.7:v1
uenv image pull 95fc886e35a3b27f
uenv image pull editors --system=daint
Look at the repository, to see what has been downloaded:
Let's also pull another couple of uenv
inspecting uenv¶
Let's say we have pulled some some uenv, e.g.:
> uenv image ls
uenv/version:tag uarch date id size
prgenv-gnu/24.7:v3 gh200 2024-08-23 b50ca0d101456970 3.8GB
editors/24.7:v1 gh200 2024-09-01 95fc886e35a3b27f 1.2GB
arbor/v0.9:1435230711 gh200 2024-09-01 41fbf21853e82969 3.6GB
To get more information about a uenv, use the uenv image inspect
command
The output can be formatted using Jinja2 templates, (useful for automated workflows):
For example, print all uenv with their views:for id in $(uenv image ls --no-header | awk '{print $4}');
do
meta=$(uenv image inspect --format '{meta}' $id)/env.json;
echo "$id : $(jq -j '.views | keys | join(" ")' $meta)";
done;
You can see a full list of format options:
using uenv¶
starting a uenv¶
start running a uenv
What happened? The squashfs image was mounted:
uenv provides a command for checking whether a uenv is running:
> uenv status
/user-environment:prgenv-gnu
GNU Compiler toolchain with cray-mpich, Python, CMake and other development tools.
views:
default
modules: activate modules
spack: configure spack upstream
Info
The uenv start
and uenv run
commands (see below) create a new process and mount the image so that that process is the only one that can read the mounted image.
This isolates different users and login sessions on the same compute/login node - different users can have their own uenv mounted at the same location without affecting one another.
The software has been mounted, but it is not yet available in the environment:
Python 3.6 is the default provided by SLES - not good enough for the discerning HPC user!On HPC systems, software is usually "loaded" using modules. The software packages are installed in subdirectories, e.g. netcdf
provided by CPE:
bin
, include
, and lib
paths.
module load netcdf
will set environment variables PATH
, LD_LIBRARY_PATH
, etc - making the software available.
uenv views modify the environment¶
# leave the previous uenv session
exit
# start with a view activated
uenv start prgenv-gnu --view=default
# now the software is available
cmake --version
which cmake
python3 --version
which python3
gcc --version
which gcc
nvcc --version
which nvcc
Let's have a closer look at /user-environment/env/default/
Can I mix and use multipe uenv at the same time?¶
A difference between uenv and modules are that setting up the environment is more "declarative" than "imperative":
- the images to mount and views to start are specified at the start of a session
- after they are set, they can't change
- if you use the
modules
view, it is possible toload
,swap
,purge
etc as in the days of yore.
- if you use the
It is not possible to run "uenv inside uenv"
- the first reason is security
- each uenv has a fixed mount point - only one image can be mounted at a location
This can be frustrating compared to using modules, when experimenting and testing on the command line:
- swapping uenv, views, etc requires going back to the start
- when using modules, one can continuously load, unload, swap, purge modules while interacting with the shell.
We might also be used to putting code like this in .bashrc
to set up a "default" environment:
An equivalent approach with uenv
is not possible
# the following starts a new shell
# ... and once loaded, we can't load a different shell
uenv start my-default-environment --view=work
The benefit of this approach is that reproducing a working environment is simpler:
uenv start cp2k/2024.2,editors --view=cp2k:develop,ed
describes the environment
This will hopefully reduce the frequency of one of the main challenges when reproducing issues affecting our users
- long-forgotten module commands in bashrc
- "this worked yesterday when this combination of modules was loaded in this order"
Note
Please report pain points in your workflow.
It is possible to use more than one uenv simultaneously¶
It is possible to mount more than one uenv in the same session, so long as they are both configured "up front" when the session is started.
Examples for this use case include:
- using a profiler or debugger uenv alongside a programming environment or application uenv
- mounting useful utilities (e.g. editors) alongside a programming environment.
# start two uenv in the same session
uenv start prgenv-gnu editors
# provide custom mount points
uenv start prgenv-gnu:/user-tools editors:/user-environment
uenv status
# start two uenv in the same session with views
uenv start prgenv-gnu editors --view=prgenv-gnu:modules,ed
# disambiguate the view name
uenv start prgenv-gnu editors --view=prgenv-gnu:modules,ed
why are there both uenv run
and uenv start
¶
The run
command runs a single command in the configured environment, returning us to the unmodified calling shell.
This is useful to use more than one uenv in a workflow - run each step with a different uenv:
uenv run --view=default prgenv-gnu -- ./pre-process.sh
uenv run --view=cp2k cp2k -- ./cp2k-simulation.sh
uenv run --view=default prgenv-gnu -- ./post-process.sh
Another, slightly irreverant, example is to make emacs available.
Emacs is provided by the editors
uenv (access through the ed
view):
The above command works, but is not very practical for regular use. Instead:
it seems odd, but by adding that alias to your .bashrc
, you now have emacs available without installing any software, or modifying your environment (keep it simple).
building software using uenv¶
a simple application using prgenv-gnu¶
Here we build affinity
, a small MPI+CUDA aware application for reporting CPU+GPU affinity.
A view provides all of the requirements (gcc, MPI, cuda, cmake, ninja)
uenv start prgenv-gnu/24.7 --view=default
git clone git@github.com:bcumming/affinity.git
cd affinity
mkdir build
cd build
which cmake
which mpicc
nvcc --version
CC=mpicc CXX=mpicxx cmake .. -GNinja
ninja
OMP_NUM_THREADS=4 srun -n4 -N1 --gpus-per-task=1 ./affinity.mpi
srun -n4 -N1 --gpus-per-task=1 ./affinity.cuda
The uenv provides cray-mpich, with some key differences:
- the MPI compilers are
mpicc
,mpicxx
,mpifort
- replacing the
CC
,cc
,ftn
compiler wrappers provided by CPE
- replacing the
- dependencies required for GPU-aware MPI are hard coded (no need to load specific modules)
modules are also available in most uenv:
uenv start prgenv-gnu/24.7 --view=modules
module avail
module load cray-mpich cmake cuda gcc ninja
# then run cmake, ninja, as before
The modules
view simply updates MODULEPATH
:
{
"list": {
"MODULEPATH": [
{
"op": "prepend",
"value": [
"/user-environment/modules"
]
}
]
},
"scalar": {}
}
A more complicated example¶
Use a view to build Arbor, a neuroscience application that can optionally use MPI, CUDA and Python.
We use a uenv that was developed for Arbor using a uenv recipe.
git clone --depth=1 --branch=v0.9.0 git@github.com:arbor-sim/arbor.git
mkdir build
cd build
export CC=`which gcc`
export CXX=`which g++`
cmake ../arbor -DARB_GPU=cuda -DARB_WITH_MPI=on -DARB_WITH_PYTHON=on -GNinja -DCMAKE_CUDA_ARCHITECTURES=90
ninja examples pyarb unit
# test the build
./unit
./bin/busyring
export PYTHONPATH=$PWD/python:$PYTHONPATH
python -c 'import arbor; print(arbor.config)'
setting up a Python venv¶
Create a virtual environment that uses the software in a uenv as the starting point:
uenv start arbor --view=develop
# check the version of python that is being used
which python
python --version
# create a venv
python -m venv --system-site-packages env
source env/bin/activate
pip list
building using Spack¶
Spack is a popular tool for installing scientific software:
- configure the software to install
arbor@v0.10.0+mpi+cuda+python
- Spack will build all missing dependencies
Each uenv image provides a standard Spack configuration
- Can be used as the basis for your own spack environment
The spack configuration can be accessed using the spack
view:
>uenv start prgenv-gnu --view=spack
loading the view prgenv-gnu:spack
> printenv | grep UENV_SPACK
UENV_SPACK_COMMIT=bd66dce2d668a6234504594661506cdd1eaca4adc
UENV_SPACK_CONFIG_PATH=/user-environment/config
UENV_SPACK_URL=https://github.com/spack/spack.git
> git clone $UENV_SPACK_URL
> cd spack
> cat /user-environment/meta/recipe/config.yaml
name: prgenv-gnu
spack:
commit: releases/v0.22
repo: https://github.com/spack/spack.git
store: /user-environment
description: GNU Compiler toolchain with cray-mpich, Python, CMake and other development tools.
> git switch releases/v0.22
> ./bin/spack find
> ./bin/spack -C $UENV_SPACK_CONFIG_PATH find
See uenv documentation for how to use the packages installed in a uenv with Spack to install your own software:
https://eth-cscs.github.io/alps-uenv/uenv-compilation-spack/
Applications provided by uenv¶
So far our examples have provided examples of using common CLI tools and compilers provided by uenv to work in the terminal and build scientific software.
Uenv can also provide scientific software and tools like debuggers - no compilation necessary.
There are application uenv provided by CSCS for common scientific codes:
- CP2K
- GROMACS
- NAMD
- LAMMPS
- ICON
- VASP
- quantumespresso
- and more ...
Scientific software is diverse, so there is no hard and fast rule for which views will be provided.
quantumespresso : default develop modules spack
namd : namd namd-single-node develop develop-single-node modules spack
cp2k : cp2k develop modules spack
arbor : arbor develop modules spack
Typically, the uenv provide two types of view:
- an
application view
that provides the application- "ready to run"
- like
module load <application>
- use this to directly use the version of the software provided by CSCS
- a
development view
that provides all of the application's dependencies- use this to build your own version of the software
- e.g. if you need a different version or configuration
slurm¶
So far we have looked at using uenv start
and uenv run
to interact with uenv.
Both of these approaches load the uenv on the node that the command is run on.
This is an important detail - the uenv is not mounted on compute nodes, and is only visible to the current process.
We can test that:
# by default, nothing mounted on the compute node
srun -n1 ls /user-environment
# start a uenv on the login node and try again
uenv start prgenv-gnu
srun -n1 ls /user-environment/
The image was mounted on the compute node - what is going on?
There is a uenv slurm plugin that will handle mounting uenv on compute nodes. By default, if
- no
--uenv
flag is passed - a uenv was mounted on the login node when srun was called
The plugin will mount the image automatically on the login node
- related: why are the modules loaded when calling sbatch on a login node loaded on all the compute nodes?
Using uenv start
and uenv run
inside an sbatch job script has downsides:
- it increases the complexity of the job script
- it may be inefficient in some cases
- e.g. 128 ranks on a single node all mount the same uenv image
The uenv Slurm plugin automates the process of starting uenv
- the uenv to load is provided using a
--uenv
option - the plugin then:
- validates the request on the login node (when srun or sbatch is called)
- mounts the uenv on each compute node before the individual MPI ranks are created
- the uenv is automatically removed when each
srun
command finishes.
From the perspective of the script running on the compute node, the uenv is always mounted.
A simple example using srun
# start a shell on a compute node with the uenv mounted
srun -n1 --uenv=prgenv-gnu/24.7:v3 --pty bash
# run a command on a compute node with the uenv mounted
srun -n1 --uenv=prgenv-gnu/24.7:v3 bash -c 'uenv view modules; module avail'
using uenv in sbatch jobs¶
The --uenv
flag can also be used in slurm batch jobs:
#!/bin/bash
#SBATCH --uenv=prgenv-gnu/24.7:v3
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=4
#SBATCH --output=job%j.out
#SBATCH --error=job%j.out
# load the view
uenv view default
exe=/capstor/scratch/cscs/bcumming/demo/affinity/build/affinity.cuda
# the uenv is available inside the script
which nvcc
uenv status
# and also automatically mounted on the compute nodes:
srun -n4 -N1 $exe
# note: within this week the following will be possible
#srun -n4 -N1 --uenv=prgenv-gnu --uenv-view=default affinity.gpu
Sometimes a job will require multiple uenv, e.g. pre-processing and post-processing stages might use one uenv, and the simulation runs would use an application uenv.
The uenv specified in the #SBATCH --uenv=
comment can be overriden in individual calls to srun
inside the script.
For example, run a job that first uses the affinity application that we built earlier with prgenv-gnu
, then run an arbor benchmark that was built with the arbor
uenv.
#!/bin/bash
#SBATCH --uenv=prgenv-gnu/24.7:v3
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=4
#SBATCH --output=job%j.out
#SBATCH --error=job%j.out
# load the view
uenv view default
exe=/capstor/scratch/cscs/bcumming/demo/affinity/build/affinity.cuda
srun -n4 -N1 $exe
arbor=/capstor/scratch/cscs/bcumming/demo/arbor/build/bin/busyring
srun --uenv=arbor/v0.9 -n4 -N1 --gpus-per-task=1 $arbor
Note
The --uenv
slurm flag is a little awkward to use at the moment because there is no corresponding --view
flag.
This forces us th use uenv view
command separately, which is messy and can create significant complexity in scripts.
A new version of the slurm plugin will be deployed on Daint and Todi very soon - hopefully this week - that will provide the --uenv-view
flag.