Message Passing Interface - MPI Jorge Barbosa
Introdução ao MPI Até ao fim dos anos 80, os fabricantes de computadores desenvolviam a sua própria biblioteca de funções para desenvolver programas paralelos. Resulta código não portável A falta de um standard dificulta o desenvolvimento das aplicações Em Abril de 92 começou o forum MPI: (www.mpi-forum.org) Participaram fabricantes de hardware e software, universidades e utilizadores finais. Ao fim de uma série de reuniões resultou a especificação standard do MPI O objectivo consistiu em incluir na especificação toda a funcionalidade que se julgava necessária para fazer do modelo passagem de mensagens um caso de sucesso. A versão final do standard MPI 1 foi terminada em Maio de 1994. A versão MPI 2 foi terminada em 1998. Apenas em 2003 foram distribuidas implementações segundo o standard MPI 2.
Introdução ao MPI Especificação de uma biblioteca standard: Define a sintaxe e semântica de um modelo para passagem de mensagens Não é uma linguagem nem um compilador Não é uma implementação específica Não especifica detalhes de implementação, apenas sugere soluções. As implementações realizadas podem fazer as mesmas coisas de forma muito diferente. Os fabricantes deverão desenvolver uma implementação do standard MPI que funcione, e optimize a execução dos programas, no seu sistema.
Introdução ao MPI Principais características do MPI para suportar paralelismo numa arquitectura de memória distribuída: Rotinas para troca de mensagens: Identifica processos emissor/receptor Comunicações ponto-a-ponto Comunicações colectivas Rotinas para sincronização Tipos de dados derivados para facilitar o envio na mesma mensagens de dados não contíguos na memória Facilidade de definir subconjuntos de processos Possibilidade de criar topologias de processos
Principais implementações MPICH Argonne National Lab www.mcs.anl.gov/mpi/mpich (MPI2 em Abril de 2003) LAM Ohio Supercomputer Center www.lam-mpi.org CHIMP Edinburgh Parallel Computing Centre www.epcc.ed.ac.uk/chimp WMPI Critical Software www.criticalsoftware.com/hpc/ Versão Windows do MPI2 lançada em Julho de 2003 Versão Linux do MPI2 lançada em Janeiro de 2004
Introdução ao MPI O MPI contém mais de 125 rotinas Uma grande parte dos programas pode ser escrita apenas com 6 rotinas Depois de iniciar, os processos são identificados pelo rank (de 0 a N-1) dentro do conjunto N de processos criados. Este valor pode ser utilizado para particularizar as acções que cada processo deve fazer. Principais instruções: MPI_INIT: Inicializa o MPI MPI_Finalize: Finaliza o MPI MPI_COMM_SIZE: número de processos criados MPI_COMM_RANK: qual o número de processo (0 a N-1) MPI_SEND: Envio de mensagem MPI_RECV: Recepção de mensagem
MPI_Init, MPI_Finalize int MPI_Init(int *argc, char ***argv) inicializa o ambiente de execução do MPI Deve ser a primeira instrução executada Só pode ser chamada uma vez int MPI_Finalize() Finaliza o ambiente de execução do MPI Os processos têm de invocar esta rotina antes de terminarem.
Estrutura básica de um programa #include mpi.h int main () { MPI_Init () processamento MPI_Finalize () } processamento adicional e local não pode invocar mais rotinas MPI.
Comunicação entre processos O MPI define grupos de processos comunicadores Os processos para comunicarem têm de pertencer a um comunicador (grupo). Por defeito existe o MPI_COMM_WORLD, que representa todos os processos. Dentro do comunicador, cada processo tem um número (rank). P2 P1 P3 Pn MPI_COMM_WORLD O utilizador pode definir vários comunicadores para agrupar os processos em grupos de trabalho. Utilização: Broadcast de uma mensagem para o grupo. Sincronização dos processos do grupo especifico.
Comunicação entre processos MPI_Comm_size(MPI_Comm comm, int *size) A função devolve em size o número de processos que pertencem ao comunicador (grupo) comm MPI_Comm_rank(MPI_Comm comm, int *rank) A função devolve em rank a posição do processo dentro do comunicador comm.
Comunicação entre processos int MPI_Send( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm ) Instrução para enviar um conjunto de dados referênciados por buf para o processo dest (rank) dentro do comunicador comm. Parâmetros de entrada: buf: initial address of send buffer (choice) count: number of elements in send buffer (nonnegative integer) datatype: datatype of each send buffer element (handle) dest: rank of destination (integer) tag: message tag (integer) comm: communicator (handle)
MPI_Datatype: Comunicação entre processos
Comunicação entre processos int MPI_Recv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) Instrução para receber um conjunto de dados para buf enviados por source (rank) dentro do comunicador comm. Parâmetros de entrada: count: maximum number of elements in receive buffer (integer) datatype: datatype of each receive buffer element (handle) source: rank of source (integer) (Pode ser MPI_ANY_SOURCE) tag: message tag (integer) (Pode ser MPI_ANY_TAG) comm: communicator (handle) Parâmetros de saída: buf initial address of receive buffer (choice) status status object (Status) (Pode ser MPI_STATUS_IGNORE)
MPI_Status MPI Status The MPI_Status datatype is a structure. The three elements for use by programmers are: MPI_SOURCE Who sent the message MPI_TAG What tag the message was sent with MPI_ERROR Any error return
Erros que podem resultar da execução das instruções anteriores MPI_SUCCESS No error; MPI routine completed successfully. MPI_ERR_COMM Invalid communicator. A common error is to use a null communicator in a call (not even allowed in MPI_Comm_rank). MPI_ERR_TYPE Invalid datatype argument. May be an uncommitted MPI_Datatype (see MPI_Type_commit). MPI_ERR_COUNT Invalid count argument. Count arguments must be non-negative; a count of zero is often valid. MPI_ERR_TAG Invalid tag argument. Tags must be non-negative; tags in a receive (MPI_Recv, MPI_Irecv, MPI_Sendrecv, etc.) may also be MPI_ANY_TAG. The largest tag value is available through the the attribute MPI_TAG_UB. MPI_ERR_RANK Invalid source or destination rank. Ranks must be between zero and the size of the communicator minus one; ranks in a receive (MPI_Recv, MPI_Irecv, MPI_Sendrecv, etc.) may also be MPI_ANY_SOURCE.
Exemplo 1: Hello World Escrever um programa em que cada processo escreve Hello word from process i of n onde n corresponde ao total de processos. Assumir que todos os processos podem usar printf. #include <stdio.h> #include "mpi.h" int main( argc, argv ) int argc; char **argv; { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); printf( "Hello world from process %d of %d\n", rank, size ); MPI_Finalize(); return 0; } >mpicc -o helloworld helloworld.c >mpirun -np 4 helloworld
Exemplo 2: Comunicação em Anel Escrever um programa em que o processo 0 lê um valor do teclado e comunica-o ao processo seguinte, em anel. Ou seja, o processo i recebe o valor de i-1 e envia-o para o processo i+1 até atingir o último processo. #include <stdio.h> #include "mpi.h" int main( int argc,char **argv ) { int rank, value, size; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); do { if (rank == 0) { scanf( "%d", &value ); MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD ); } else { MPI_Recv( &value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, &status ); if (rank < size - 1) MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD ); } printf( "Process %d got %d\n", rank, value ); } while (value >= 0); } MPI_Finalize( ); return 0;