Primeros pasos con mpi

¡Hola Mundo!

Tres cosas suelen ser importantes cuando se empieza a aprender a utilizar MPI. Primero, debe inicializar la biblioteca cuando esté listo para usarla (también debe finalizarla cuando haya terminado). En segundo lugar, querrá saber el tamaño de su comunicador (lo que usa para enviar mensajes a otros procesos). En tercer lugar, querrá saber su rango dentro de ese comunicador (qué número de proceso tiene dentro de ese comunicador).

#include <mpi.h>
#include <stdio.h>

int main(int argc, char **argv) {
    int size, rank;
    int res;

    res = MPI_Init(&argc, &argv);
    if (res != MPI_SUCCESS)
    {
        fprintf (stderr, "MPI_Init failed\n");
        exit (0);
    }

    res = MPI_Comm_size(MPI_COMM_WORLD, &size);
    if (res != MPI_SUCCESS)
    {
        fprintf (stderr, "MPI_Comm_size failed\n");
        exit (0);
    }
    res = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (res != MPI_SUCCESS)
    {
        fprintf (stderr, "MPI_Comm_rank failed\n");
        exit (0);
    }

    fprintf(stdout, "Hello World from rank %d of %d~\n", rank, size);

    res = MPI_Finalize();
    if (res != MPI_SUCCESS)
    {
        fprintf (stderr, "MPI_Finalize failed\n");
        exit (0);
    }
}

Si ejecuta este programa así:

mpiexec -n 2 ./hello

Usted esperaría obtener una salida como esta:

Hello World from rank 0 of 2!
Hello World from rank 1 of 2!

También puede obtener esa salida al revés (consulte http://stackoverflow.com/a/17571699/491687) para obtener más información sobre esto:

Hello World from rank 1 of 2!
Hello World from rank 0 of 2!

Rango y tamaño

Para obtener el tamaño de un comunicador (por ejemplo, MPI_COMM_WORLD) y el rango del proceso local dentro de él:

int rank, size;
int res;
MPI_Comm communicator = MPI_COMM_WORLD;

res = MPI_Comm_rank (communicator, &rank);
if (res != MPI_SUCCESS)
{
  fprintf (stderr, "MPI_Comm_rank failed\n");
  exit (0);
}
res = MPI_Comm_size (communicator, &size);
if (res != MPI_SUCCESS)
{
  fprintf (stderr, "MPI_Comm_size failed\n");
  exit (0);
}

Iniciar/Finalizar

Antes de que se pueda ejecutar cualquier comando MPI, el entorno debe inicializarse y finalizarse al final:

int main(int argc, char** argv)
{
    int res;
    res = MPI_Init(&argc,&argv);
    if (res != MPI_SUCCESS)
    {
      fprintf (stderr, "MPI_Init failed\n");
      exit (0);
    }
    ...
    res = MPI_Finalize();
    if (res != MPI_SUCCESS)
    {
      fprintf (stderr, "MPI_Finalize failed\n");
      exit (0);
    }
}

Valores devueltos de llamadas MPI

Casi cualquier llamada MPI devuelve un código de error entero, lo que indica el éxito de la operación. Si no ocurre ningún error, el código de retorno es MPI_SUCCESS:

if (MPI_Some_op(...) != MPI_SUCCESS)
{
   // Process error
}

Si ocurre un error, MPI llama a un controlador de errores asociado con el comunicador, la ventana o el objeto de archivo antes de regresar al código de usuario. Hay dos controladores de errores predefinidos (el usuario puede definir controladores de errores adicionales):

  • MPI_ERRORS_ARE_FATAL - los errores resultan en la terminación del programa MPI
  • MPI_ERRORS_RETURN: los errores hacen que el código de error se devuelva al usuario

El controlador de errores predeterminado para comunicadores y ventanas es MPI_ERRORS_ARE_FATAL; para objetos de archivo es MPI_ERRORS_RETURN. El controlador de errores para MPI_COMM_WORLD también se aplica a todas las operaciones que no están específicamente relacionadas con un objeto (por ejemplo, MPI_Get_count). Por lo tanto, comprobar el valor de retorno de las operaciones que no son de E/S sin configurar el controlador de errores en MPI_ERRORS_RETURN es redundante, ya que las llamadas MPI erróneas no se devolverán.

// The execution will not reach past the following line in case of error
int res = MPI_Comm_size(MPI_COMM_WORLD, &size);
if (res != MPI_SUCCESS)
{
    // The following code will never get executed
    fprintf(stderr, "MPI_Comm_size failed: %d\n", res);
    exit(EXIT_FAILURE);
}

Para habilitar el procesamiento de errores del usuario, primero se debe cambiar el controlador de errores de MPI_COMM_WORLD:

MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN);

int res = MPI_Comm_size(MPI_COMM_WORLD, &size);
if (res != MPI_SUCCESS)
{
    fprintf(stderr, "MPI_Comm_size failed: %d\n", res);
    exit(EXIT_FAILURE);
}

El estándar MPI no requiere que las implementaciones de MPI puedan recuperarse de errores y continuar con la ejecución del programa.