Překlad a spouštění MPI úloh
----------------------------
MPI je na našich strojích v těchto implementacích:
* default `Open MPI `_ pro `GNU `_ překladače,
* (po ``source load_intel``) `Intel MPI `_ pro Intel a GNU překladače,
* (po ``source load_nv``) `Open MPI `_ pro `Nvidia `_ překladače,
* `MPICH `_ pro GNU překladače,
plus nezávislé MPI implementace v dockerovských obrazech. Je vhodné používat MPI implementaci konzistentní s překladačem programu a volanými numerickými knihovnami.
Při spouštění MPI úlohy na jediném stroji stačí určit počet procesů. Při spouštění MPI úlohy na více strojích je třeba nastavit bezheslový přístup, specifikovat hostitelské počítače a rozložení procesů na nich a specifikovat komunikační hardware a protokol. Vybrat lze rychlý `InfiniBand `_ (při QDR teoretických 32 Gbit/s), dostupný na *geofxyzw* a některých *geof.0*, nebo pomalejší `Ethernet `_ (1 Gbit/s), dostupný všude. Horní hranice přenosové rychlosti (*bandwidth*) může ve sdílené paměti našich strojů dosáhnout 10-20 GB/s, s InfiniBandem 3.5 GB/s a Ethernetem mírně nad 0.1 GB/s; rychlost významně závisí na velikosti předávaných dat, jak lze ověřit pomocí níže zmíněných MPI benchmarků.
Open MPI (default)
^^^^^^^^^^^^^^^^^^
Default implementace MPI v Ubuntu 22.04 je Open MPI v4.1.2 vhodná pro GNU překladače v11. Programy se překládají pomocí *wrapperů* ``mpif90`` (nověji ``mpifort``) a ``mpicc``. Aktuální překladový řádek se odhalí příkazem ``mpif90 -show``, požadovaný překladač lze upřesnit pomocí proměnných prostředí ``OMPI_FC`` a ``OMPI_CC`` a přidat volby pro překlad pomocí proměnných ``OMPI_FCFLAGS`` a ``OMPI_CFLAGS`` nebo rovnou na řádku, např.::
# Open MPI Fortran compilation
export OMPI_FCFLAGS="-Ofast -march=native"
mpif90 file.f90 # using gfortran
mpif90 -Ofast -march=native file.f90 # an alternative
OMPI_FC=gfortran-12 mpif90 file.f90 # using gfortran v12
Úlohy se spouštějí pomocí *loaderu* ``mpirun`` (synonymum ``mpiexec``), obvykle s volbou ``-n`` (též ``-np``) udávající počet procesů. Pro běh procesů na jediném stroji není třeba zadávat víc, komunikace je implicitně vedena ovladačem sdílené paměti z komponenty ``ob1`` (výslovnost *Obi-Wan*, explicitně: ``-mca pml ob1 -mca btl self,vader``). Může být (stojí za test), že komunikace poběží o něco rychleji s užitím komponenty ``ucx`` (pouze na strojích s InfiniBandem)::
# Open MPI local run
mpirun -n 8 -mca pml ob1 a.out # point-to-point message layer: ob1
mpirun -n 8 -mca pml ucx a.out # point-to-point message layer: ucx
mpirun -n 8 a.out # hosts with InfiniBand: ucx, without IB: ob1
Pro běh úloh na více strojích je nutné nastavit bezheslový přístup (viz níže Poznámky) a je vhodné připravit *hostfile* se seznamem hostitelů (co řádek, to jméno hostitele), přičemž stroje by si měly být podobné (např. všechny s InfiniBandem), popsat rozložení procesů na strojích (např. volbou ``-N`` pro počet procesů na každém stroji) a spouštět úlohy ve sdíleném adresáři zadaném absolutní cestou. Místo v *hostfile* lze seznam strojů a počty procesů na nich popsat v rámci volby ``-H``. Pomocí parametru ``-mca pml ucx`` se aktivuje UCX komunikace vhodná pro InfiniBand, komponentu ``ob1`` (píše se ``-mca pml ob1``) je pro InfiniBand možné využít také (v této variantě zvané `IPoIB `_ bývá méně výkonný). Na strojích bez InfiniBandu poskytuje komponenta ``ob1`` komunikaci přes Ethernet. S ``ob1`` je třeba explicitně zadávat jména adaptérů, u nás ``mib0`` pro InfiniBand a ``eno1`` pro Ethernet::
# Open MPI distributed run
cd /AbsolutePath
mpirun -n 16 -N 8 -hostfile hostfile -mca pml ucx a.out # hosts with InfiniBand
mpirun -n 16 -N 8 -hostfile hostfile -mca pml ob1 -mca btl_tcp_if_include mib0 a.out # InfiniBand via IPoIB
mpirun -n 16 -N 8 -hostfile hostfile -mca pml ob1 -mca btl_tcp_if_include eno1 a.out # Ethernet only
MCA (*modular component architecture*) parametry loaderu lze nastavit trvaleji pomocí proměnných prostředí (máme to tak) a úlohy na více strojích pak spouštět jednodušším příkazem, zde včetně výčtu strojů s počty jejich procesů na příkazovém řádku místo v *hostfile*::
# Open MPI distributed run with predefined environment variables
export OMPI_MCA_pml=ucx # hosts with InfiniBand
export OMPI_MCA_pml=ob1 # hosts without InfiniBand
export OMPI_MCA_btl_tcp_if_include=mib0 # hosts with InfiniBand
export OMPI_MCA_btl_tcp_if_include=eno1 # hosts without InfiniBand
cd /opt/osu-benchmarks/open-mpi/mpi/pt2pt # OSU benchmarks of MPI bandwidth, latency etc.
mpirun -n 2 -H geofA:1,geofB:1 osu_bw
Při nestandardním nastavení proměnných prostředí (typicky proměnné ``PATH``) na spouštějícím stroji může být nutné exportovat tyto proměnné poomcí volby ``-x``. Příkladem může být spouštění programu ``aspect``: cesta k němu se lokálně nastavuje voláním ``source load_aspect`` a takto změněnou hodnotu proměnné ``PATH`` je třeba explicitně distribuovat. ::
# Open MPI distributed run with exported environment variables
source load_aspect
cd /AbsolutePath
mpirun -x PATH -n 72 -H geofA:24,geofB:24,geocC:24 aspect file.prm # more variables: -x VAR1 -x VAR2
Pro ujištění, které MCA komponenty jsou aktivní, lze zvýšit *verbosity level* pomocí parametrů jako ``-mca pml_base_verbose 100``, ``-mca btl_base_verbose 100`` aj. Jejich přehled podává příkaz ``ompi_info -a``. Ověřit rozložení procesů na strojích lze volbou ``mpirun -display-map``.
Intel MPI
^^^^^^^^^
Pro aktivaci MPI z Intel oneAPI HPC Toolkitu je určen místní příkaz ``source load_intel`` pro načtení Intel oneAPI konfigurace. Fortranské překladové *wrappery* jsou dva, ``mpiifort`` volající Intel Fortran a ``mpif90`` pro GNU Fortran, pro Intel C jsou určeny ``mpiicc`` a ``mpiicpc`` a pro GNU C ``mpicc`` a ``mpicxx``. Default volby *wrapper* přizná při volbě ``-show``, další volby pro překlad se přidají pomocí proměnných ``I_MPI_FCFLAGS`` a ``I_MPI_CFLAGS`` nebo rovnou na řádek (`více překladových proměnných `_)::
# Intel MPI Fortran compilation
source load_intel
mpiifort file.f90 # using ifort
mpiifort -Ofast -xHost file.f90 # with additional compiler options
mpif90 file.f90 # using gfortran
mpif90 -Ofast -march=native file.f90 # with additional compiler options
Pro spouštění úloh lze použít loadery ``mpirun`` a ``mpiexec``, typicky s volbou ``-n`` (též ``-np``) udávající počet procesů. Volba komunikačního protokolu se provádí pomocí proměnné prostředí ``I_MPI_FABRICS``, její obvyklou hodnotou je ``shm:ofi`` (*shared memory* pro komunikaci uvnitř stroje, jinak ``ofi`` s *libfabric* knihovnou). Dodat proměnné prostředí příkazu lze i touto formou (`více běhových proměnných `_)::
# Intel MPI local run
source load_intel
I_MPI_FABRICS=shm mpirun -n 8 ./a.out # local communication via shared memory
I_MPI_FABRICS=ofi mpirun -n 8 ./a.out # local communication via ofi library
Pro běh úloh na více strojích je nutné nastavit bezheslový přístup (viz níže Poznámky) a je vhodné připravit *hostfile* se seznamem hostitelů (co řádek, to jméno hostitele), popsat rozložení procesů na strojích (např. volbou ``-ppn``, *processes per node*, pro počet procesů na každém stroji) a spouštět úlohy ve sdíleném adresáři zadaném absolutní cestou. Pomocí proměnné ``I_MPI_OFI_PROVIDER`` se nastavuje OFI komunikace buď přes InfiniBand (``mlx`` = Mellanox), `IPoIB `_ (``tcp`` na strojích s InfiniBandem) nebo Ethernet (``tcp`` na strojích bez InfiniBandu)::
# Intel MPI distributed run
source load_intel
cd /AbsolutePath
I_MPI_OFI_PROVIDER=mlx mpirun -n 16 -ppn 8 -f hostfile ./a.out # hosts with InfiniBand
I_MPI_OFI_PROVIDER=tcp mpirun -n 16 -ppn 8 -f hostfile ./a.out # hosts without InfiniBand
S předdefinovanými proměnnými prostředí lze úlohy spouštět jednodušeji, zde včetně výčtu strojů na příkazovém řádku místo v *hostfile*::
# Intel MPI distributed run with predefined environment variables
source load_intel
export I_MPI_FABRICS=shm:ofi # default for both intra- and inter-node communication
export I_MPI_OFI_PROVIDER=mlx # using fast InfiniBand
export I_MPI_OFI_PROVIDER=tcp # using slower IPoIB or slow Ethernet
cd /opt/osu-benchmarks/intel-mpi/mpi/pt2pt # OSU benchmarks of MPI bandwidth, latency etc.
mpirun -n 2 -ppn 1 -hosts geofA,geofB ./osu_bw
Diagnostiku lze vyžádat nastavením proměnné ``I_MPI_DEBUG`` na kladné hodnoty 1--100 (rozumná volba: 5). K dispozici je MPI profiler: nastaví se proměnná ``I_MPI_STATS`` na kladnou hodnotu 1--5 a po skončení běhu se získá statistika navrženým voláním příkazu ``aps`` (*application performance snapshot*).
Open MPI pro Nvidia
^^^^^^^^^^^^^^^^^^^
Nvidia HPC Software Development Kit (SDK) obsahuje MPI implementace v.3 a v.4 vhodné pro Nvidia překladače. Pro aktivaci Open MPI v.4 je určen místní příkaz ``source load_nv``. Jména *wrapperů*, *loaderů* a proměnných odpovídají default Open MPI pro GNU překladače, viz tedy jejich popis výše. Nvidia Open MPI v.3 (místní příkaz ``source load_nv_mpi3``) nemá zabudovanou podporu UCX komunikace, pro InfiniBand (`IPoIB `_) lze použít komponentu ``ob1`` s adaptérem ``mib0``::
# Nvidia Open MPI run with predefined environment variables
source load_nv # activation of Nvidia Open MPI v.4
export OMPI_MCA_pml=ucx # hosts with InfiniBand
export OMPI_MCA_pml=ob1 # hosts without InfiniBand
export OMPI_MCA_btl_tcp_if_include=mib0 # hosts with InfiniBand
export OMPI_MCA_btl_tcp_if_include=eno1 # hosts without InfiniBand
cd /opt/osu-benchmarks/open-mpi/mpi/pt2pt # OSU benchmarks of MPI bandwidth, latency etc.
mpirun -n 2 osu_bw # local run
mpirun -H geofA,geofB osu_bw # distributed run with Open MPI v.4, with and without InfiniBand
source load_nv_mpi3 # activation of Nvidia Open MPI v.3
mpirun -H geofA,geofB -mca pml ob1 osu_bw # distributed run with Open MPI v.3, with InfiniBand
mpirun -H geofA,geofB osu_bw # distributed run with Open MPI v.3, without InfiniBand
MPICH
^^^^^
MPICH je implementace MPI konkurenční k Open MPI. V repozitářích Ubuntu ji lze nalézt a paralelizovaný software bývá nabízen jak pro Open MPI, tak pro MPICH. Na našich strojích je Open MPI nastaveno jako default, a tedy další software máme nachystán pro Open MPI. Ukáže-li se v ojedinělých případech problém s Open MPI, je možné obrátit se k MPICH. (Např. `Coarray Fortran `_ není v Ubuntu 22.04 schopen s Open MPI běhu na více strojích, s MPICH problém není.)
Pro překlad a spouštění samostatných programů lze obdobně jako výše použít *wrappery* ``mpif90.mpich`` a ``mpicc.mpich`` a *loader* ``mpirun.mpich``. Volby těchto skriptů jsou většinou odchylné od voleb skriptů Open MPI; Intel MPI je odvozeno od MPICH, volby MPICH skriptů jsou tedy blízké výše popsaným volbám Intel MPI. Pro spojení s MPI paralelizovanými knihovnami je třeba mít tyto knihovny instalované ve verzi pro MPICH (nikoliv Open MPI). ::
# MPICH Fortran compilation and run
mpif90.mpich file.f90 # compilation using gfortran
mpirun.mpich -n 8 ./a.out # local run
mpirun.mpich -n 16 -ppn 8 -hosts geofA,geofB ./a.out # distributed run
Obdobně jako výše lze volit např. ``mpif90 -show`` pro zjištění použitých voleb *wrapperu*. *Wrapper* ``mpif90.mpich`` je ekvivalentní s ``mpifort.mpich`` a *loader* ``mpirun.mpich`` je totéž co ``mpiexec.mpich``. Na volby *loaderu* se lze ptát příkazem ``mpirun.mpich -help``. Užitečná může být proměnná prostředí ``MPIEXEC_TIMEOUT``. Repozitářová MPICH knihovna je přeložena bez podpory UCX; dostupný komunikační protokol spolupracuje s InfiniBandem jen v podobě `IPoIB `_.
Poznámky
^^^^^^^^
Pro bezheslové spojení mezi stroji je třeba na stroji A vytvořit soukromý a veřejný klíč pomocí ``ssh-keygen -t rsa`` (při potížích ``ssh-keygen -t ecdsa``). Vzniknou soubory ``~/.ssh/id_rsa`` a ``~/.ssh/id_rsa.pub``. Obsah druhého z nich se přidá na stroji B do souboru ``~/.ssh/authorized_keys``, čímž se povolí jednosměrný přístup z A na B. Přenos veřejného klíče je třeba provést všemi směry, které mají volné připojení umožnit. K adresáři ``~/.ssh`` smí mít právo k zápisu jen vlastník, jinak mohou být klíče nefunkční.
Na strojích máme předdefinovány proměnné prostředí ``OMPI_MCA_pml``, ``OMPI_MCA_btl_tcp_if_include``, ``I_MPI_FABRICS`` a ``I_MPI_OFI_PROVIDER`` tak, aby se s Open MPI v.4 a Intel MPI přednostně využívala komunikace pomocí InfiniBandu.
Pro ověření funkčnosti MPI systému a zvolených *runtime* parametrů lze využít sadu *OSU micro-benchmarks (Ohio State University)*, dostupnou v adresáři ``/opt/osu-benchmarks`` jak pro Open MPI, tak Intel MPI. K témuž účelu mohou posloužit také *Intel MPI benchmarks* v ``/opt/intel/oneapi/mpi/latest/benchmarks/imb``.
..
Může být vhodné zrušit omezení na velikost zásobníku (*stack*) stanovenou v bashi: ``ulimit -s unlimited``. Na strojích s InfiniBandem je zrušena horní hranice pro registraci RDMA přístupu do paměti v uživatelských programech.