Interfaz de Transferencia de Mensajería

Introducción

La Interfaz de Paso de Mensajes (MPI) es una API para la paralelización de programas en múltiples nodos y existe desde 1994 (https://es.wikipedia.org/wiki/Interfaz_de_Paso_de_Mensajes). MPI también se puede usar para la paralelización en máquinas SMP y se considera muy eficiente en este ámbito (con una escalabilidad cercana al 100 % en código paralelizable, en comparación con el ~80 % que se obtiene comúnmente con hilos debido a la asignación de memoria no óptima en máquinas NUMA). Antes de MPI, prácticamente todos los fabricantes de supercomputadoras tenían su propio lenguaje de programación; MPI facilitó la portabilidad del software.

Hay muchas implementaciones de MPI disponibles, como Open MPI (el compilador MPI predeterminado en Fedora y el compilador MPI utilizado en RHEL), MPICH (en Fedora y RHEL) y MVAPICH1 y MVAPICH2 (en RHEL pero todavía no en Fedora).

Dado que algunas bibliotecas MPI funcionan mejor en ciertos hardware que en otros, y que algunos programas funcionan mejor con ciertas bibliotecas MPI, la selección de la biblioteca debe realizarse a nivel de usuario, según la sesión específica. Además, quienes realizan computación de alto rendimiento podrían querer usar compiladores más eficientes que el predeterminado en Fedora (gcc), por lo que es necesario tener varias versiones del compilador MPI, cada una compilada con un compilador diferente instalado simultáneamente. Esto debe tenerse en cuenta al escribir los archivos de especificaciones.

Empaquetados de compiladores MPI

Los archivos de los compiladores MPI DEBEN instalarse en los siguientes directorios:

Tipo archivo Lugar

Binarios

%{_libdir}/%{name}/bin

Bibliotecas

%{_libdir}/%{name}/lib

[[PackagingDrafts/Fortran

Módulos de Fortran]]

%{_fmoddir}/%{name}

[[Packaging/Python

Módulos de Python]]

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

Archivos Config

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

Dado que los archivos de inclusión y las páginas de manual suelen solaparse entre las diferentes implementaciones de MPI, también DEBEN ubicarse fuera de los directorios habituales. Es posible que algunas páginas de manual o archivos de inclusión (ya sea del propio compilador MPI o de algún software MPI instalado en el directorio del compilador) sean específicos de la arquitectura (por ejemplo, una definición en una arquitectura de 32-bit difiere de una en una de 64-bit). Los directorios que DEBEN usarse son los siguientes:

Tipo de archivo Placement

Páginas manual

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

Incluye archivos

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

Partes de la arquitectura independiente (excepto cabeceras las cuales van en -devel) DEBE ser colocado en un subpaquete -common que es BuildArch: noarch.

El tiempo de ejecución de compiladores MPI (mpirun, las bibliotecas, los manuales, etc.) DEBEN ser empaquetado en %{nombre}, y las cabeceras de desarrollo y las bibliotecas en %{nombre}-devel.

Como el compilador se instala fuera de PATH, es necesario cargar las variables relevantes antes de poder usar el compilador o ejecutar programas MPI. Esto se logra utilizando módulos de entorno.

El archivo del módulo DEBE ser instalado bajo %{_sysconfdir}/modulefiles/mpi. Esto concede como usuario con solo una implementación mpi instalada para cargar el módulo con:

module load mpi

El archivo del módulo DEBE tener la línea:

conflicto mpi

para prevenir carga concurrente de múltiples módulos mpi.

El archivo del módulo DEBE anteponer $MPI_BIN al PATH del usuario y $MPI_LIB al LD_LIBRARY_PATH. El archivo del módulo también DEBE configurar algunas variables auxiliares (principalmente para su uso en archivos de especificaciones):

Variable Valor Explicación

MPI_BIN

%{_libdir}/%{name}/bin

binarios compilados contra alguna de las pilas MPI

MPI_SYSCONFIG

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

Pila MPI especificada en los archivos de configuración

MPI_FORTRAN_MOD_DIR

%{_fmoddir}/%{name}

Pila MPI especificada del directorio del módulo Fortran

MPI_INCLUDE

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

Pila MPI con cabeceras específicas

MPI_LIB

%{_libdir}/%{name}/lib

Bibliotecas compiladas frente a la pila MPI

MPI_MAN

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

Pila MPI específica de las páginas man

MPI_PYTHON2_SITEARCH

%{python2_sitearch}/%{name}

Pila MPI específica para módulos de Python 2

MPI_PYTHON3_SITEARCH

%{python3_sitearch}/%{name}

Pila MPI espacífica para módulos de Python 3

MPI_COMPILER

%{name}-%{_arch}

Nombre del paquete del compilador, para utilizar en p.e. archivos spec

MPI_SUFFIX

_%{name}

El sufijo utilizado para programas compilados frente a la pila MPI

Como estos directorios pueden ser utilizados por software que utiliza la pila MPI, el paquete en tiempo de ejecución MPI DEBE ser propietario de todos.

OBLIGATORIO: Por defecto, NO se coloca ningún archivo en /etc/ld.so.conf.d. Si el empaquetador desea proporcionar compatibilidad con alternativas, DEBE colocarse en un subpaquete junto con el archivo ld.so.conf.d tal que no sea necesario instalarla si no se desea.

OBLIGATORIO: Si el mantenedor desea que el módulo de entorno a cargar automáticamente mediante el uso de un scriptlet en /etc/profile.d o mediante algún otro mecanismo, esto DEBE hacerse en un subpaquete.

OBLIGATORIO: El paquete del compilador MPI DEBE proporcionar una macro RPM que facilite la carga y descarga del soporte en los archivos de especificaciones, por ejemplo, colocando lo siguiente en /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};

cargar y descargar el compilador en archivos de especificaciones es tan fácil como %{_openmpi_load} y %{_openmpi_unload}.

La configuración automática de la ruta de carga de módulos en los intérpretes de Python se realiza mediante un archivo .pth ubicado en uno de los directorios donde habitualmente se buscan módulos (%{python2_sitearch}, %{python3_sitearch}). Estos archivos .pth deben adjuntar el directorio especificado con la variable de entorno $MPI_PYTHON2_SITEARCH o $MPI_PYTHON3_SITEARCH, según la versión del intérprete, a sys.path, y no hacen nada si dichas variables no están configuradas. Los archivos de módulo NO DEBEN configurar directamente PYTHONPATH, ya que no se puede configurar para ambas versiones de Python simultáneamente.

Si el módulo de entorno establece indicadores del compilador como CFLAGS (anulando así los exportados en %configure, la macro RPM DEBE hacer que utilicen los indicadores de optimización %{optflags} de Fedora una vez más (como en el ejemplo anterior en el cual el módulo openmpi-%{_arch} establece CFLAGS).

Empaquetado de software MPI

Software que mantiene MPI DEBEN ser empaquetados además en modo serial [p.e. no MPI], si está admitido por desarrollo. (para instancia: foo).

Si es posible, el empaquetador DEBE empaquetar las versiones por cada compilador MPI en Fedora (p.e. si algo solo puede ser compilado con mpich y mcapich2, entonces los paquetes mvapich1 y openmpi no necesitan ser realizados).

La implementación MPI específica de los archivos DEBEN ser instalados dentro del directorio utilizado por el compilador MPI del usuario ($MPI_BIN, $MPI_LIB y el resto).

Los binarios DEBEN tener el sufijo $MPI_SUFFIX (p. ej., _openmpi para Open MPI, _mpich para MPICH y _mvapich2 para MVAPICH2). Esto se debe a dos razones: la versión serial del programa puede aún ser ejecutada al cargar un módulo MPI y el usuario siempre sabe qué versión está ejecutando. Esto no tiene por qué perjudicar el uso de scripts de shell:

# ¿Cual implementación MPI utilizamos?

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

# Ejecutar preprocesador
foo -preprocess < foo.in
# Ejecutar cálculo
mpirun -np 4 foo${MPI_SUFFIX}
# Ejecutar algún procesamiento
mpirun -np 4 bar${MPI_SUFFIX} -process
# Recopilar resultados
bar -collect

Los bits habilitados para MPI DEBEN incluirse dentro de un subpaquete con el sufijo que indica el compilador MPI utilizado (por ejemplo: foo-openmpi para Open MPI [el compilador MPI tradicional de Fedora] o foo-mpich para MPICH). Para la propiedad del directorio y para garantizar la instalación del entorno de ejecución MPI correcto, los subpaquetes MPI DEBEN requerir el paquete de entorno de ejecución del compilador MPI correcto.

Cada compilación MPI de bibliotecas compartidas TENDRÍA un subpaquete -libs independiente para las bibliotecas (p. ej., foo-mpich-libs). Al igual que en el caso de los compiladores MPI, NO DEBE configurarse la biblioteca (en /etc/ld.so.conf.d).

Si los encabezados son los mismos independientemente del método de compilación y la arquitectura (p. ej., serial de 32-bit, Open MPI de 64-bit, MPICH), DEBEN dividirse en un subpaquete -headers independiente (p. ej., foo-headers). Los módulos Fortran son específicos de cada arquitectura y, por lo tanto, se incluyen en el paquete -devel (específico de la implementación de MPI) (foo-devel para la versión serial y foo-openmpi-devel para la versión Open MPI).

Cada compilación MPI DEBE tener un subpaquete -devel independiente (p. ej., foo-mpich-devel) que incluya las bibliotecas de desarrollo y Requires: %{name}-headers si dicho paquete existe. El logro es poder instalar y desarrollar usando, p.e., "foo-mpich-devel" sin necesidad de instalar, p.ej., OpenMPI o la versión serial del paquete.

Los archivos deben compartirse entre paquetes tanto como sea posible. Las partes independientes del compilador, como los archivos de datos en %{_datadir}/%{name} y los archivos man, DEBEN incluirse en un subpaquete -common requerido por todos los paquetes binarios (el paquete serial y todos los paquetes MPI).

Un archivo de especificaciones de muestra

# Define una macro para invocar a ../configure en lugar de ./configure
%global dconfigure %(printf %%s '%configure' | sed 's!\./configure!../configure!g')

Nombre: algo
Requiere: %{name}-common = %{version}-%{release}

%package común

%package openmpi
BuildRequires: openmpi-devel
# Requerir explícitamente la propiedad del directorio y garantizar la selección del tiempo de ejecución correcto
Requires: openmpi
Requires: %{name}-common = %{version}-%{release}

%package mpich
BuildRequires: mpich-devel
# Requerir explícitamente la propiedad del directorio y garantizar la selección del tiempo de ejecución correcto
Requires: mpich
Requires: %{name}-common = %{version}-%{release}

%build
# Es necesario realizar compilaciones fuera de la raíz para poder compilar muchas versiones a la vez

# Para evitar el código replicado, defina una macro de compilación
%define dobuild() \
mkdir $MPI_COMPILER; \
cd $MPI_COMPILER; \
%dconfigure --program-suffix=$MPI_SUFFIX ;\
make %{?_smp_mflags} ; \
cd ..

# Compila versión serial, argumentos simulados
MPI_COMPILER=serial MPI_SUFFIX= %dobuild

# Compila las versiones paralelas: establece variables del compilador para coberturas MPI
export CC=mpicc
export CXX=mpicxx
export FC=mpif90
export F77=mpif77

# Compila la versión OpenMPI
%{_openmpi_load}
%dobuild
%{_openmpi_unload}

# Compila la versión mpich
%{_mpich_load}
%dobuild
%{_mpich_unload}

%install
# Instala la versión serial
make -C serial install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"

# Instala la versión de OpenMPI
%{_openmpi_load}
make -C $MPI_COMPILER install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"
%{_openmpi_unload}

# Instala la versión MPICH
%{_mpich_load}
make -C $MPI_COMPILER install DESTDIR=%{buildroot} INSTALL="install -p" CPPROG="cp -p"
%{_mpich_unload}


%files # Todos los binarios seriales (normal)

%files common # Todos los archivos compartidos ente las series y las versiones MPI diferentes

%files openmpi # Todos los archivos enlazados de openmpi

%files mpich # Todos los archivos mpich enlazados