Message Passing Interface

Einführung

Das „Message Passing Interface“ (MPI) ist eine API zur Parallelisierung von Programmen auf mehreren Knoten und existiert seit 1994 (1). MPI kann auch zur Parallelisierung auf SMP-Maschinen eingesetzt werden und gilt dort als sehr effizient (nahezu 100 % Skalierung bei parallelisierbarem Code im Vergleich zu den üblicherweise mit Threads erreichten ca. 80 % aufgrund suboptimaler Speicherverwaltung auf NUMA-Maschinen). Vor MPI verwendete nahezu jeder Supercomputerhersteller seine eigene Programmiersprache; MPI vereinfachte die Softwareportierung erheblich.

Es gibt viele MPI-Implementierungen, wie zum Beispiel Open MPI (der Standard-MPI-Compiler in Fedora und der in RHEL verwendete MPI-Compiler), MPICH (in Fedora und RHEL) und MVAPICH1 und MVAPICH2 (in RHEL, aber noch nicht in Fedora).

Da manche MPI-Bibliotheken auf bestimmter Hardware besser funktionieren als auf anderer und manche Software am besten mit bestimmten MPI-Bibliotheken harmoniert, muss die Auswahl der verwendeten Bibliothek benutzerbezogen und sitzungsspezifisch erfolgen. Anwender im Bereich High Performance Computing benötigen möglicherweise effizientere Compiler als den in Fedora standardmäßig verwendeten (gcc). Daher muss es möglich sein, mehrere Versionen des MPI-Compilers gleichzeitig mit jeweils einem anderen Compiler kompilieren zu können. Dies muss beim Schreiben von Spec-Dateien berücksichtigt werden.

Paketierung von MPI-Compilern

Die Dateien der MPI-Compiler MÜSSEN in den folgenden Verzeichnissen installiert werden:

File type Placement

Binaries

%{_libdir}/%{name}/bin

Libraries

%{_libdir}/%{name}/lib

[[PackagingDrafts/Fortran

Fortran modules]]

%{_fmoddir}/%{name}

[[Packaging/Python

Python modules]]

%{python2_sitearch}/%{name} %{python3_sitearch}/%{name}

Config files

%{_sysconfdir}/%{name}-%{_arch}

Da sich Include-Dateien und Handbuchseiten bei verschiedenen MPI-Implementierungen zwangsläufig überschneiden, MÜSSEN sie ebenfalls außerhalb der normalen Verzeichnisse abgelegt werden. Es ist möglich, dass einige Handbuchseiten oder Include-Dateien (entweder die des MPI-Compilers selbst oder die einer im Compilerverzeichnis installierten MPI-Software) architekturspezifisch sind (z. B. unterscheidet sich eine Definition auf einer 32-Bit-Architektur von der auf einer 64-Bit-Architektur). Folgende Verzeichnisse MÜSSEN verwendet werden:

Dateityp Ort

Handbuchseiten

%{_mandir}/%{name}-%{_arch}

Include -Dateien

%{_includedir}/%{name}-%{_arch}

Architekturunabhängige Teile (mit Ausnahme von Headern, die in -devel gehören) MÜSSEN in einem -common-Teilpaket platziert werden, das als BuildArch: noarch markiert ist.

Die Laufzeitumgebung der MPI-Compiler (mpirun, die Bibliotheken, die Handbücher usw.) MUSS in %{name} paketiert werden, und die Entwicklungs-Header und -Bibliotheken in %{name}-devel.

Da der Compiler außerhalb von PATH installiert ist, müssen die entsprechenden Variablen geladen werden, bevor der Compiler verwendet oder MPI-Programme ausgeführt werden können. Dies geschieht mithilfe von Umgebungsmodulen.

Die Moduldatei MUSS unter %{_sysconfdir}/modulefiles/mpi installiert werden. Dies ermöglicht es einem Benutzer, der nur eine MPI-Implementierung installiert hat, das Modul wie folgt zu laden:

module load mpi

Die Moduldatei MUSS folgende Zeile enthalten:

conflict mpi

… um das gleichzeitige Laden mehrerer MPI-Module zu verhindern.

Die Moduldatei MUSS $MPI_BIN dem PATH-Pfad des Benutzers und $MPI_LIB dem LD_LIBRARY_PATH-Pfad voranstellen. Die Moduldatei MUSS außerdem einige Hilfsvariablen setzen (hauptsächlich zur Verwendung in Spec-Dateien):

Variable Value Explanation

MPI_BIN

%{_libdir}/%{name}/bin

Binaries compiled against the MPI stack

MPI_SYSCONFIG

%{_sysconfdir}/%{name}-%{_arch}

MPI stack specific configuration files

MPI_FORTRAN_MOD_DIR

%{_fmoddir}/%{name}

MPI stack specific Fortran module directory

MPI_INCLUDE

%{_includedir}/%{name}-%{_arch}

MPI stack specific headers

MPI_LIB

%{_libdir}/%{name}/lib

Libraries compiled against the MPI stack

MPI_MAN

%{_mandir}/%{name}-%{_arch}

MPI stack specific man pages

MPI_PYTHON2_SITEARCH

%{python2_sitearch}/%{name}

MPI stack specific Python 2 modules

MPI_PYTHON3_SITEARCH

%{python3_sitearch}/%{name}

MPI stack specific Python 3 modules

MPI_COMPILER

%{name}-%{_arch}

Name of compiler package, for use in e.g. spec files

MPI_SUFFIX

_%{name}

The suffix used for programs compiled against the MPI stack

Da diese Verzeichnisse von Software, die den MPI-Stack verwendet, genutzt werden können, MUSS das MPI-Laufzeitpaket Eigentümer aller dieser Verzeichnisse sein.

MUSS: Standardmäßig werden KEINE Dateien in /etc/ld.so.conf.d abgelegt. Wenn der Paketierer Unterstützung für Alternativen bereitstellen möchte, MUSS diese in einem Unterpaket zusammen mit der Datei ld.so.conf.d abgelegt werden, damit die Unterstützung für alternative Pakete nicht zusätzlich installiert werden muss, falls sie nicht gewünscht ist.

WICHTIG: Wenn der Betreuer möchte, dass das Umgebungsmodul automatisch über ein Skript in /etc/profile.d oder über einen anderen Mechanismus geladen wird, MUSS dies in einem Teilpaket erfolgen.

MUSS: Das MPI-Compilerpaket MUSS ein RPM-Makro bereitstellen, das das Laden und Entladen der Unterstützung in Spec-Dateien vereinfacht, z. B. durch Platzieren des Folgenden in /etc/rpm/macros.openmpi

%_openmpi_load \
 . /etc/profile.d/modules.sh; \
 module load mpi/openmpi-%{_arch}; \
 export CFLAGS="$CFLAGS %{optflags}";
%_openmpi_unload \
 . /etc/profile.d/modules.sh; \
 module unload mpi/openmpi-%{_arch};

Das Laden und Entladen des Compilers in Spec-Dateien ist so einfach wie %{_openmpi_load} und %{_openmpi_unload}.

Automatic setting of the module loading path in python interpreters is done using a .pth file placed in one of the directories normally searched for modules (%{python2_sitearch}, %{python3_sitearch}). Those .pth files should append the directory specified with $MPI_PYTHON2_SITEARCH or $MPI_PYTHON3_SITEARCH environment variable, depending on the interpreter version, to sys.path, and do nothing if those variables are unset. Module files MUST NOT set PYTHONPATH directly, since it cannot be set for both Python versions at the same time.

If the environment module sets compiler flags such as CFLAGS (thus overriding the ones exported in %configure, the RPM macro MUST make them use the Fedora optimization flags %{optflags} once again (as in the example above in which the openmpi-%{_arch} module sets CFLAGS).

Paketierung von MPI-Software

Software that supports MPI MUST be packaged also in serial mode [i.e. no MPI], if it is supported by upstream. (for instance: foo).

If possible, the packager MUST package versions for each MPI compiler in Fedora (e.g. if something can only be built with mpich and mvapich2, then mvapich1 and openmpi packages do not need to be made).

MPI implementation specific files MUST be installed in the directories used by the used MPI compiler ($MPI_BIN, $MPI_LIB and so on).

The binaries MUST be suffixed with $MPI_SUFFIX (e.g. _openmpi for Open MPI, _mpich for MPICH and _mvapich2 for MVAPICH2). This is for two reasons: the serial version of the program can still be run when an MPI module is loaded and the user is always aware of the version s/he is running. This does not need to hurt the use of shell scripts:

# Which MPI implementation do we use?

#module load mpi/mvapich2-i386
#module load mpi/openmpi-i386
module load mpi/mpich-i386

# Präprozessor  ausführen
foo -preprocess < foo.in
# Berechnung ausführen
mpirun -np 4 foo${MPI_SUFFIX}
# Nachbearbeitung ausführen
mpirun -np 4 bar${MPI_SUFFIX} -process
# Ergebnisse zusammenfassen
bar -collect

The MPI enabled bits MUST be placed in a subpackage with the suffix denoting the MPI compiler used (for instance: foo-openmpi for Open MPI [the traditional MPI compiler in Fedora] or foo-mpich for MPICH). For directory ownership and to guarantee the pickup of the correct MPI runtime, the MPI subpackages MUST require the correct MPI compiler’s runtime package.

Each MPI build of shared libraries SHOULD have a separate -libs subpackage for the libraries (e.g. foo-mpich-libs). As in the case of MPI compilers, library configuration (in /etc/ld.so.conf.d) MUST NOT be made.

In case the headers are the same regardless of the compilation method and architecture (e.g. 32-bit serial, 64-bit Open MPI, MPICH), they MUST be split into a separate -headers subpackage (e.g. 'foo-headers'). Fortran modules are architecture specific and as such are placed in the (MPI implementation specific) -devel package (foo-devel for the serial version and foo-openmpi-devel for the Open MPI version).

Each MPI build MUST have a separate -devel subpackage (e.g. foo-mpich-devel) that includes the development libraries and Requires: %{name}-headers if such a package exists. The goal is to be able to install and develop using e.g. 'foo-mpich-devel' without needing to install e.g. openmpi or the serial version of the package.

Files must be shared between packages as much as possible. Compiler independent parts, such as data files in %{_datadir}/%{name} and man files MUST be put into a -common subpackage that is required by all of the binary packages (the serial package and all of the MPI packages).

Spec-Beispieldatei

# Define a macro for calling ../configure instead of ./configure
%global dconfigure %(printf %%s '%configure' | sed 's!\./configure!../configure!g')

Name: foo
Requires: %{name}-common = %{version}-%{release}

%package common

%package openmpi
BuildRequires: openmpi-devel
# Require explicitly for dir ownership and to guarantee the pickup of the right runtime
Requires: openmpi
Requires: %{name}-common = %{version}-%{release}

%package mpich
BuildRequires: mpich-devel
# Require explicitly for dir ownership and to guarantee the pickup of the right runtime
Requires: mpich
Requires: %{name}-common = %{version}-%{release}

%build
# Have to do off-root builds to be able to build many versions at once

# To avoid replicated code define a build macro
%define dobuild() \
mkdir $MPI_COMPILER; \
cd $MPI_COMPILER; \
%dconfigure --program-suffix=$MPI_SUFFIX ;\
make %{?_smp_mflags} ; \
cd ..

# Build serial version, dummy arguments
MPI_COMPILER=serial MPI_SUFFIX= %dobuild

# Build parallel versions: set compiler variables to MPI wrappers
export CC=mpicc
export CXX=mpicxx
export FC=mpif90
export F77=mpif77

# Build OpenMPI version
%{_openmpi_load}
%dobuild
%{_openmpi_unload}

# Build mpich version
%{_mpich_load}
%dobuild
%{_mpich_unload}

%install
# Install serial version
make -C serial install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"

# Install OpenMPI version
%{_openmpi_load}
make -C $MPI_COMPILER install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"
%{_openmpi_unload}

# Install MPICH version
%{_mpich_load}
make -C $MPI_COMPILER install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"
%{_mpich_unload}


%files # All the serial (normal) binaries

%files common # All files shared between the serial and different MPI versions

%files openmpi # All openmpi linked files

%files mpich # All mpich linked files