Překlad a spouštění MPI úloh

MPI je na našich strojích v těchto implementacích:

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.mpichloader 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~/.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_FABRICSI_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/opt/intel/oneapi/mpi/latest/benchmarks/imb.