lunes, 22 de abril de 2013

Introducción a la programación en paralelo con MPI (Message Passing Interface) en entornos HPC

En la primera publicación de este Blog os explique como construir un cluster de alto rendimiento y en esta  vamos a ver los conceptos básicos sobre la programación paralela con MPI para incrementar el rendimiento de nuestras aplicaciones.

Introducción

En muchas ocasiones nos encontramos con el problema de que la ejecución de determinados algoritmos suponen un coste de tiempo demasiado elevado y las soluciones como utilizar hardware mas potente para reducir este tiempo tienen limitaciones técnicas y son muy caras. Antes estos problemas tenemos como solución la programación paralela empleando clusters HPC.

La programación en paralelo implica el desarrollo de software que se ejecuta simultáneamente en varios procesadores. Existe intercambio de información entre los procesos que forman la aplicación mediante la utilización de librerias MPI. Este intercambio de información se lleva a cabo entre procesadores que se encuentran en la misma maquina y/o en procesadores que se encuentran en la misma red, por lo que es importante que estas comunicaciones se hagan en una red con la menor latencia posible.La situación optima es que haya mucho computo por parte de los procesadores y poco intercambio de información. 

Para diseñar el algoritmo del software paralelizado se precisa intercambiar mediante alguno de estos esquemas:

  • Master-slave, master-worker o client-server: Todo el control lo lleva un procesador, y él se encarga de asignar tareas a los otros procesadores. Solo hay comunicación entre el servidor y el cliente, pero nunca entre clientes.
  • Completamente distribuido: La tarea se hace de forma conjunta y todos los procesos tienen el mismo peso. Las comunicaciones fluyen en cualquier sentido.

MPI (Message Passing Interface)

La primera versión de MPI (“Message Passing Interface”, Interfaz de Paso de Mensajes) fué desarrollada en 1993-1994 por un grupo de investigadores al servicio de la industria, el gobierno y el sector académico.  Es un estándar que define la sintaxis y la semántica de las funciones contenidas en una librería de paso de mensajes, diseñada para ser usada en programas que exploten la existencia de múltiples procesadores.
Aunque la interfaz no cambie, puede implementarse tanto en sistemas que utilicen paso de mensajes, como sistemas de memoria compartida.Existen implementaciones de software libre de MPI tales como OpenMPI, LAM, MPICH,... y estan disponibles para numerosos lenguajes de programación tales como C, C++,Fortran, JAVA, Python, ...

Estructura básica de un programa MPI, compilación y ejecución

  • En toda aplicación paralizada con MPÎ hay 3 fase:
    1. Inicio del sistema paralelo
    2. Computación y comunicación
    3. Finalización del sistema paralelo
  • Las funciones están definidas en mpi.h
  • Hay un compilador específico para crear programas paralelos: mpicc, lamcc, mpic++,...
  • Hay un lanzador de aplicaciones paralelas: mpirun, lamrun,...

1.Inicio del sistema paralelo
  • Con MPI el procesador 0 es el que interactúa con el usuario, así que es el único que conoce los parámetros de entrada
  • MPI_Init(int *argc, char ***argv)
  • A partir de ese momento, la aplicación está sincronizada y todos los procesos conocen los parámetros de entrada

Hello World

#include <mpi.h>
int main(int argc, char *argv[])
{
MPI_Init(&argc,&argv);
......
}


2.Computación y comunicación

  • Hay dos funciones muy interesantes en MPI para que los procesos puedan organizarse
    • MPI_Comm_size número total de procesos
    • MPI_Comm_rank posición del proceso actual
  • Haremos que todos los procesos envíen un mensaje al primero indicando cada uno que proceso es y el primero lo pinte por pantalla
Hello World

#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]){
int size, rank , i;
char mensaje[100];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank==0){
for(i=1; i<size; i++){
MPI_Recv(mensaje, 100, MPI_CHAR, i, 0, MPI_COMM_WORLD, 0);
printf(mensaje);
}
}else{
sprintf(mensaje,"Hola mundo paralelo, soy el proceso %d de %d\n",rank,size);
MPI_Send(mensaje, 100, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
}
}



3 Finalización del sistema paralelo

  • Todos los procesos deben ejecutar MPI_Finalize antes de terminar
  • Esa función cierra las comunicaciones entre los procesos y da por finalizada la aplicación paralela.

Hello World

#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[])
{
int size, rank , i;
char mensaje[100];
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank==0){
for(i=1; i<size; i++){
MPI_Recv(mensaje, 100, MPI_CHAR, i, 0, MPI_COMM_WORLD, 0);
printf(mensaje);
}
}else{
sprintf(mensaje,"Hola mundo paralelo, soy el proceso %d de %d\n",rank,size);
MPI_Send(mensaje, 100, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return EXIT_SUCCESS;
}



Funciones básicas de MPI


Para desarrollar aplicaciones paralelas contamos con numerosas funciones pero en este apartado veremos funciones mas básicas de MPI:

 int MPI_Init (int *argc, char ***argv)
– La primera función MPI que hay que ejecutar

 int MPI_Finalize ( )
– La última función MPI que hay que ejecutar MPI (Message Passing Interface)

 int MPI_Comm_size(MPI_Comm comm, int *size)
– MPI_Comm_size(MPI_COMM_WORLD, &num_procs)

int MPI_Comm_rank(MPI_Comm comm, int *rank)
– MPI_Comm_rank(MPI_COMM_WORLD, &pos)

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
– MPI_Send(&num, 1, MPI_INT, 2, 0, MI_COMM)

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
– MPI_Recv(&num, 1, MPI_INT, 1, 0, MI_COMM, &status)


Compilación de una aplicación paralela 

Para compilar un programa paralelo debemos usar un compilador especial. Dependiendo de si usamos C o C++, y dependiendo de la librería instalada: mpicc, mpic++, lamcc, lamc++, lamc++-64,...

> mpicc -o holamundo holamundo.c

Ejecución de una aplicación paralela

Ahora podemos ejecutar el programa en la máquina paralela. Dependiendo de la instalación que tengamos, usamos mpirun, mpiexec, lamrun,...

> mpirun –np 4 ./holamundo

Hola mundo paralelo, soy el proceso 1 de 4
Hola mundo paralelo, soy el proceso 2 de 4
Hola mundo paralelo, soy el proceso 3 de 4

Las aplicaciones pueden ser enviadas a un gestor de trabajos p.e. SGE (Sun Grid Engine),

#!/bin/bash
#$ -cwd
#$ -pe hpmpi 4
#$ -N mi_identificador_de_tarea
#$ -M correo@correo.com
#$ -m be
#$ -S /bin/bash
#$ -q MPI_Pmas
mpirun -np $NSLOTS ./holamundo
> qsub tarea


Conclusión:

Hemos hecho un acercamiento a la programación en paralelo y espero que os sirva para entender de que se trata y que os permita desarrollar vuestras primeras aplicaciones. Al tratarse de un area extensa espero en futuros artículos volver a hablar de la programación paralela pero ya en aspectos mas avanzados 

.








viernes, 20 de julio de 2012

Construcción automática de un Cluster Beowulf con ABC GNU/Linux

Soy Iker Castaños, Ingeniero de Sistemas GNU/Linux y economista
Mi idea es utilizar este blog para ir publicando post sobre noticias o guias relativas a administración de sistemas y desarrollo.
Este es mi primer post y por ello he creído conveniente el publicar una guía sobre la utilización de mi proyecto que mas repercusión mediática ha tenido, la distribución ABC (Automated Beowulf Cluster) GNU/Linux. 
El desarrollo del proyecto esta siendo discontinuado ya que empleo mi tiempo libre. La ultima versión fue desarrollada basándose en Ubuntu 9.04.
ABC GNU/Linux permite construir clusters Beowulf en modo live o siendo instalado en uno de los pcs del cluster (frontend). Los nodos arrancan de a traves de la red, son nodos diskless ya que no precisan de disco duro. 
Publique un articulo científico sobre ABC para el IEEE en el ICAT2009 (Bosnia & Herzegovina) pero esta guía os permitirá emplear la distribución de una manera rápida y sencilla.

REQUISITOS MINIMOS (orientativos):

Para poder construir un cluster Beowulf con ABC GNU/Linux es preciso cumplir los siguientes requisitos orientativos:

• Utilizar más de un PC y todos los PCs integren 256 MB de memoria RAM y que al menos sean procesadores P3 500Mhz o equivalente. En caso de que se quiera construir un cluster en modo “live” no es preciso utilizar disco duro alguno, en caso de querer instalar la distribución en el front-end(el PC donde se inserta el disco de ABC) será necesario que ese PC tenga disco duro.
• Los PCs deben están interconectados a través de un switch. Nunca debe utilizar un router para interconectar los PCs. La velocidad del switch y  la categoría del cableado empleado han de ser la mayor posible ya que en caso de que el cluster este formado por un gran numero de PCs la latencia perjudicaría el rendimiento del sistema
•  Descargar la ISO de ABC del mirror de la UPV/EHU o del mirror de sourceforge:
     Mirror sourceforge
     Mirror UPV/EHU

ARRANQUE DEL FRONT-END:

        Como ha sido mencionado en el punto anterior, en uno de los PCs insertaremos el disco de ABC GNU/Linux. En este PC escogeremos en su BIOS que el dispositivo preferido para el arranque sea el DVD. Una vez arrancado el disco se mostrara en la pantalla lo siguiente:


 Como puede ser observado en la captura de la pantalla, puede optarse por las siguientes opciones:

1. Modo “live”. Este modo de arranque se hace sin necesidad de instalación  alguna., todo el sistema arranca en RAM. Presionando la tecla “enter” o  escribiendo “live” y presionando “enter”.
2. Modo “installer”. Mediante este modo se instalara la distribución en el disco duro del front-end. La instalación se lleva a cabo mediante el instalador de Ubuntu, el cual es muy sencillo y amigable para el usuario. Es muy  importante que durante la instalación se cree el usuario “master” con clave “master” y que al PC le pongamos como hostname “master”. Una vez instalado su funcionamiento es idéntico al del modo “live”, solo que no se precisara disco alguno, el arranque será mas rápido y los datos del “home” del usuario permanecerán aun apagando o reiniciando el sistema Para optar  por este modo se debe escribir “install” y presionar la tecla “enter”.
3. Modo “checkdisk”. Es utilizado para comprobar la integridad del soporte óptico. Para optar por este modo se debe teclear “check” y presionar la tecla “enter”.
4. Modo “memtest” Es utilizado para comprobar el estado de la memoria RAM. Para optar por este modo se debe teclear “memtest” y presionar la tecla “enter”.
5. En caso de que se opte por arrancar del disco duro tan solo se debe teclear “hd” y presionar la tecla “enter”
Tanto si se arranca en modo “live” o si se arranca una instalación de ABC GNU/Linux que se encuentre en el disco duro, accederemos al escritorio GNOME como se muestra en la siguiente captura de pantalla:

                                             

Una vez arrancado el front-end se debe arrancar los nodos como se comentara en el siguiente punto.

ARRANQUE DE LOS NODOS:
       
Se debe configurar la BIOS especificando que el dispositivo de arranque sea lan NIC mediante PXE. Una vez configurada la BIOS el arranque de cada nodo se llevara a cabo como se muestra en las siguientes capturas de pantalla:






Como puede observarse cada nodo obtendrá una IP y arrancara a través del front-end. Una vez arrancados todos los nodos podremos utilizar el cluster de la manera que se describe en el siguiente punto.

UTILIZACIÓN DE LAM, OPENMPI Y GANGLIA:

        Todos los PCs del cluster han registrado sus IPs en el fichero “clusterhosts” que se encuentra en el “home” del usuario. Es preciso arrancar el daemon lam para poder ejecutar aplicaciones en paralelo sin ser root. El arranque del daemon lam lo llevaremos a cabo en una consola mediante el comando “lamboot –v clusterhosts” como se muestra en la siguiente pantalla o clickeando el acceso “autolamboot”, el cual se encuentra en el escritorio del front-end:


        Una vez arrancado el daemon lam es preciso compilar la aplicación que vayamos a correr en paralelo mediante el comando “mpicc.openmpi codigofuente –o  binario”.
        Para correr la aplicación en paralelo es necesario ejecutar el comando “mpiexec.openmpi –n N binario”, siendo N el numero de nodos que quieran serutilizados. El ejemplo que se ha enunciado anteriormente sirve para a continuación mostrar la compilación y ejecución en 3 nodos del “Hello World!” paralelizado pero OpenMPI permite trabajar con muchísimas variables tales como número de procesos, numero de nodos, número de procesadores, etcétera. Para más información del uso de openMPI ww.open-mpi.org/
                                            
        A continuación se muestra la compilación de un “Hello World!” cuyo código ha sido paralelizado con las librerías MPI y su posterior ejecución en paralelo mediante el uso de 3 nodos del cluster.


La distribución incluye un monitor de recursos llamado ganglia. Es posible acceder a el presionando el acceso directo llamado “Cluster monitor“. A través del navegador Web firefox se visualizara todos los recursos de CPU; memoria, red, etcétera. A continuación se observa una captura de pantalla de ganglia en funcionamiento:

                                            

CAMBIO DE CONFIGURACIÓN DE RED:

        ABC GNU/Linux ha sido diseñada de tal manera que permite que el front-end pueda utilizar una segundo NIC para conectarse a Internet. Por defecto este NIC obtendra su IP mediante DHCP pero en los casos en los cuales el administrador del cluster quiera cambiar su configuración, deberá modificar el fichero “interfaces” el cual se encuentra en “/home/master/clusternet/”.

REFERENCIAS:

Web de la UPV/EHU sobre ABC GNU/Linuhttp://www.ehu.es/AC/ABC.htm