Buscar

descricao-do-padrao-mpi

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 13 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

1 
Message Passing Interface (MPI) 
Gustavo Mitsuyuki Waku1 
1Instituto de Computação (IC) – Universidade Estadual de Campinas (UNICAMP) 
Campinas, SP – Brazil 
gustavo.waku@gmail.com 
 
Abstract. The programming model based on message passing is very versatile, 
having portability as it’s major feature. This paper describes the specification 
of the MPI and does an investigation about it. 
Resumo. O modelo de programação baseado em passagem de mensagem é 
bastante versátil tendo como principal vantagem a portabilidade. Neste 
contexto este trabalho realiza a investigação e a descrição do padrão MPI. 
 
1. Introdução 
 Message Passing Interface (MPI) é um padrão que especifica um modelo (um 
conjunto de interfaces) e não sua implementação (como). O modelo de programação de 
passagem de mensagem é bastante poderoso por ser fácil de usar e possui alta 
portabilidade. A facilidade de uso se justifica pelo uso de interfaces simples claramente 
especificadas quanto ao seu comportamento, uso e parâmetros para operação. A 
portabilidade pelo fato de que com o uso passagem de mensagem, é possível escrever 
programas que irão funcionar em máquinas de tipos variados como por exemplo 
multiprocessadores com memória distribuída, redes de estações de trabalhos ou 
ambientes híbridos dos mais variados tipos. A idéia geral é permitir escrever aplicações 
que usem passagem de mensagem como modelo de programação de forma padronizada 
possibilitando interoperabilidade entre os programas e consequente aumento de 
escalabilidade. Atualmente, o padrão é utilizado principalmente em máquinas paralelas 
e clusters (conjuntos) de estações de trabalho. 
 O modelo de programação usando passagem de mensagem era uma relativa 
novidade no início da década de 90 e vários fabricantes tinham sua própria 
implementação de passagem de mensagem, faltava uma especificação que 
“padronizasse” o segmento, sobretudo para permitir um uso mais uniforme e permitir 
uma interoperabilidade maior entre os diversos sistemas. Após várias reuniões com 
desenvolvedores, fabricantes, em 1994 a primeira versão do padrão MPI-1 foi proposta. 
A especificação é mantida por um fórum ( o MPI fórum http://www.mpi-forum.org/ ) e 
atualmente a versão mais recente é a MPI-3.0. 
 O MPI-1 tratava basicamente de comunicação ponto a ponto, o MPI-2.0 
apresentou novas áreas como Entrada/Saída Paralela, operações remotas de memória e 
gerenciamento dinâmico de processos, além de corrigir e adicionar novas funções ao 
MPI-1. O MPI-3.0 extendeu as operações sobre conjuntos para adicionar operações não 
bloqueantes e pequenas correções ao padrão proposto anteriormente. 
 
 
 
 
 
2 
 
Fig 1. Linha do tempo de evolução de versões 
 Este trabalho apresenta as os conceitos básicos do padrão MPI mostrando 
exemplos de utilização, e está dividido nos seguintes tópicos: Conceitos 
Básicos, Comunicação ponto a ponto, Deadlocks, Starvation, Modos de comunicação e 
operações não bloqueantes, Comunicação coletiva, Topologia de Processos, Entrada e 
Saída Paralela. 
 
2. Conceitos Básicos 
 Para entender melhor a comunicação básica ponto a ponto, alguns conceitos 
iniciais são necessários como processo, grupo, contexto e comunicador. 
 Processo é um módulo executável identificado por um rank (similar o pid do 
Linux e varia de 0 a N-1). O grupo é uma coleção ordenada de processos. O contexto é 
uma entidade que serve para separar o espaço, por exemplo mensagens de diferentes 
contexto não podem interferir uma na outra. O comunicador é um conceito que 
encapsula o conceito de grupo e contexto, definem como será a interação entre os 
processos. Os comunicadores mais comuns são MPI_COMM_WORLD (pode colaborar 
com outros processos), MPI_COMM_SELF (modo privado que inviabiliza 
colaboração). Existem basicamente dois tipos de comunicadores: intra e inter. Os Intra-
comunicadores definem a comunicação dentro do grupos de processos, e inter-
comunicadores, entre grupos de processos. 
 
3. Comunicação ponto a ponto 
 A comunicação básica ponto a ponto no padrão ocorre por operações básicas de 
send e receive. Estas operações podem ser síncronas (ou seja, esperam a operação 
completar antes de prosseguir com a execução) ou assíncronas (também chamadas de 
não-bloqueantes, i.e., não esperam o término da operação para prosseguir). O exemplo 
abaixo ilustra um exemplo de comunicação síncrona em C. 
 
#include "mpi.h" 
int main( int argc, char *argv[]) 
{ 
 char message[20]; 
 int myrank; 
 MPI_Status status; 
V
1
.
1
 
J
u
n
 
9
5 
 
 
 
3 
 MPI_Init( &argc, &argv ); 
 MPI_Comm_rank( MPI_COMM_WORLD, &myrank ); 
 if (myrank == 0) /* code for process zero */ 
 { 
 strcpy(message,"Hello, there"); 
 MPI_Send(message, strlen(message)+1, MPI_CHAR, 1, 99, MPI_COMM_WORLD); 
 } 
 else if (myrank == 1) /* code for process one */ 
 { 
 MPI_Recv(message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status); 
 printf("received :%s:\n", message); 
 } 
 MPI_Finalize(); 
return 0; } 
 O exemplo acima foi projetado para ser executado com 2 processos. O processo 
0 envia uma mensagem “Hello, there” e o outro processo 1 a recebe. Cada processo é 
identificado pelo rank (variável myrank). Para enviar o processo 0 utiliza a api 
MPI_SEND sendo necessário indicar aonde está armazenada a mensagem (send buffer), 
o seu tamanho (em número de elementos), o tipo de informação que será enviado, o 
número do processo que irá receber, o tag, e o comunicator (espécie de grupo). Para 
receber uma mensagem o processo 1 utiliza o MPI_RECV, sendo necessário indicar o 
recipiente aonde será armazenada a mensagem (receive buffer), o tamanho máximo, o 
tipo de dado, quem está enviando (é o rank ou pid), o tag, comunicator, e status da 
operação. 
 A api MPI_SEND é especificada da seguinte forma: 
 
MPI_SEND(buf, count, datatype, dest, tag, comm) 
Parameter type (IN, 
OUT or INOUT) 
Parameter name desc 
IN buf Initial address of send buffer 
IN count Number of elements in send buffer(non-negative integer) 
IN datatype Datatype of each send buffer elemento (handle) 
IN dest Rank of destination (integer) 
IN tag Message tag (integer) 
IN comm Communicator (handle) 
 A tag é um identificador para rotular uma determinada mensagem, isso permite 
sua distinção de possíveis outras mensagens enviadas/recebidas para um mesmo 
processo. 
 Communicator especifica um conjunto de processos que compartilham o mesmo 
contexto. Dentro deste grupo cada processo é identificado pelo seu rank. O mais comum 
é que seja utilizado o parâmetro pré-definido MPI_COMM_WORLD que permite 
comunicação entre todos os processos entre si. 
 O conjunto source, dest, tag e comm é também chamado de envelope, o source é 
um valor implícito, dest é o valor do rank de destino, tag é um valor que varia de 0 a 
MPI_TAG_UB (constante menor que 32767). 
 A operação bloqueante de receive é definida como: 
 
MPI_RECV (buf, count, datatype, source, tag, comm, status) 
Parameter type (IN, Parameter name desc 
 
 
 
4 
OUT or INOUT) 
OUT buf Initial address of receive buffer 
IN count Number of elements of receive buffer(non-negative integer) 
IN datatype Datatype of each send buffer elemento (handle) 
IN source Rank of source (integer) or MPI_ANY_SOURCE 
IN tag Message tag (integer) or MPI_ANY_TAG 
IN comm Communicator (handle) 
OUT status Status object 
 O buffer de receive é um conjunto de count elementos consecutivos que 
começam em buf e são do tipo datatype. Se o conteúdo não couber em buf, um erro de 
overflow será gerado. Somente os count elementos são modificados em buf, os demais 
não são alterados, ou seja, é preciso que a manipulação seja feita de forma cuidadosa 
caso contrário o usuário poderá acabar lendo lixo de buf que não faz parte da mensagem 
original. Quando uma mensagem é recebida, o seu tag, source e comm devem “casar” 
com a mensagem enviada. Alternativamente, pode ser utilizados parâmetros como 
MPI_ANY_SOURCE e MPI_ANY_TAG, para especificar receptores genéricosindicando que qualquer valor de source ou de tag são aceitos. Podemos notar que a 
operação de send deve especificar necessariamente quem vai receber, enquanto a 
operação de receive pode aceitar dados de qualquer emissor, por isso essas operações 
são ditas assimétricas. O parâmetro status pode ser utilizada para consultar sobre 
possíveis erros, em C essa estrutura possui 3 campos básicos: MPI_SOURCE, 
MPI_TAG, MPI_ERROR. 
 É importante especificar o tipo de dados que está sendo enviado e recebido para 
evitar erros de conversão de tipos dentro de um mesmo programa. Entre sistemas 
heterogêneos, muito embora exista a necessidade de conversão de tipos devido a 
representação para comunicação, o padrão não especifica uma regra de conversão de 
representação, apenas se espera que uma conversão de ponto flutuante seja feita ao 
valor mais representativo no sistema destino, visando preservar ao máximo seu valor 
inteiro, lógico e de caractere. 
 A seguir segue um outro exemplo de comunicação ponto a ponto usando 4 
processos. A implementação foi feita em java usando a biblioteca MPJ express que 
implementa a especificação do padrão MPI. 
 
/** 
 * Universidade Estadual de Campinas 
 * Programa desenvolvido para a disciplina MO601 como parte do trabalho sobre MPI 
 * @author Gustavo Waku 
 * */ 
 
package p1; 
import mpi.*; 
 
public class HelloWorldMPI { 
 public static final int TAG = 99; 
 
 public static void main(String[] args) throws Exception { 
 MPI.Init(args) ; 
 int myrank = MPI.COMM_WORLD.Rank(); 
 int numprocs = MPI.COMM_WORLD.Size(); 
 
 System.out.println("I am process <"+myrank+"> of total <"+ numprocs +"> processes."); 
 
 char [] message1 = "Hello There, I`m process <0> speaking".toCharArray(); 
 char [] buf1 = new char[message1.length]; 
 char [] message2 = ("Hi, I`m process <" + myrank + "> speaking").toCharArray(); 
 char [] buf2 = new char[message2.length]; 
 
 if (myrank == 0) { 
 /* process zero broadcasts to all of the rest it`s message, 
 * and waits to receive their ack */ 
 for ( int i=1; i<numprocs; i++ ) { 
 
 
 
5 
 System.out.println(" process <0> sends message to: <" + i + ">"); 
 MPI.COMM_WORLD.Send(message1, 0, message1.length, MPI.CHAR, i, TAG); 
 /* void Send(java.lang.Object buf, int offset, int count, 
 * Datatype datatype, int dest, int tag) 
 * Blocking send operation. */ 
 } 
 for ( int i=1; i<numprocs; i++ ) { 
 System.out.println(" process <0> waits to receive messages from <" + i + ">"); 
 MPI.COMM_WORLD.Recv(buf2, 0, buf2.length, MPI.CHAR, i, TAG); 
 
 System.out.println("process <0> received: " + new String(buf2)); 
 /* Status Recv(java.lang.Object buf, int offset, int count, 
 * Datatype datatype, int source, int tag) 
 * Blocking receive operation. */ 
 } 
 } else { 
 /* receive from rank 0: */ 
 System.out.println(" process <"+ myrank +"> waits to receive from <0>"); 
 MPI.COMM_WORLD.Recv(buf1, 0, buf1.length, MPI.CHAR, 0, TAG); 
 System.out.println("process <"+ myrank +"> received: " + new String(buf1) + "!"); 
 
 /* send to rank 0 */ 
 System.out.println(" process <"+ myrank +"> sends message back to <0>"); 
 MPI.COMM_WORLD.Send(message2, 0, message2.length, MPI.CHAR, 0, TAG); 
 } 
 MPI.Finalize(); 
 } 
} 
 O programa acima foi projetado para funcionar com N processos. O processo 0 
envia mensagens aos demais N-1 processos e depois aguarda que os mesmos retornem 
uma resposta. Os outros N-1 processos recebem as mensagens do processo 0 e em 
seguida enviam uma outra mensagem para o mesmo. Todas as chamadas de envio e 
recebimento são síncronas. 
 A seguinte saída é obtida quando executada com N=4. 
MPJ Express (0.38) is started in the multicore configuration 
I am process <3> of total <4> processes. 
 process <3> waits to receive from <0> 
I am process <0> of total <4> processes. 
 process <0> sends message to: <1> 
I am process <2> of total <4> processes. 
 process <2> waits to receive from <0> 
I am process <1> of total <4> processes. 
 process <1> waits to receive from <0> 
 process <0> sends message to: <2> 
 process <0> sends message to: <3> 
 process <0> waits to receive messages from <1> 
process <1> received: Hello There, I`m process <0> speaking! 
 process <1> sends message back to <0> 
process <3> received: Hello There, I`m process <0> speaking! 
 process <3> sends message back to <0> 
process <2> received: Hello There, I`m process <0> speaking! 
 process <2> sends message back to <0> 
process <0> received: Hi, I`m process <1> speaking 
 process <0> waits to receive messages from <2> 
process <0> received: Hi, I`m process <2> speaking 
 process <0> waits to receive messages from <3> 
process <0> received: Hi, I`m process <3> speaking 
 
4. Deadlocks 
Em uma comunicação síncrona, podem ocorrer deadlocks caso o programa tenha 
sido projetado de forma equivocada. Um exemplo é a situação em que um processo 0 
envia uma mensagem ao processo 1 e fica esperando, o processo 1 envia para o 
processo 0 e também fica esperando. Uma maneira de evitar isso é fazer com que um 
 
 
 
6 
deles comece recebendo a mensagem, e o outro enviando. Outras situações de deadlock 
podem ocorrer e devem ser observadas caso a caso. O padrão não especifica formas de 
identificar, apenas enumera alguns possíveis casos de deadlock. 
5. Starvation e Fairness (Justiça) 
O protocolo não garante justiça na comunicação. Suponha que um processo envie 
uma mensagem, o processo destino pode não receber a mensagem devido a mensagem 
ter sido sobreposta por outra mensagem enviada por outro processo. De maneira 
análoga, suponha vários processos receptores de mensagens produzidas por outro 
processo, é possível que algum deles nunca receba a mensagem produzida. É 
responsabilidade do programador garantir que não ocorra starvation. 
 
6. Modos de comunicação e operações não bloqueantes 
Os exemplos de operações de send mostrados são bloqueantes, ou seja, o 
programa não executa a próxima linha se a mensagem não foi armazenada 
completamente em um buffer, esse buffer pode ser o receive buffer ou um buffer 
temporário. Ou seja, o programa poderia continuar a execução assim que a mensagem 
foi armazenada em um buffer de saída. O padrão MPI estabelece 4 tipos de 
comunicação para cada send/receive bloqueante, são eles: standard, buffered, 
synchronous e ready. 
Na comunicação standard fica à critério da disponibilidade de memória do 
sistema se a mensagem vai ser armazenada em buffer ou não. Se ela for armazenada em 
buffer, o programa pode continuar assim que a mensagem for transferida ao buffer. Se 
não houver memória (ou por questões de desempenho) e a mensagem não for 
armazenada em buffer, o programa não retoma sua execução até que o comando receive 
correspondente seja invocado. O fato de essa operação poder depender de um comando 
receive correspondente torna a operação send standard não local. 
A comunicação buffered é aquela em que a mensagem é copiada para um buffer 
temporário e não espera o comando receive correspondente para continuar a execução, 
por isso a operação é dita local. 
Uma operação send synchronous é aquela que só termina quando o comando 
receive correspondente é alcançado e a mensagem começou a ser recebida (i.e., a 
operação de receive começou a receber a mensagem). Essa operação é útil para indicar 
que o receptor alcançou um determinado ponto de execução (que já começou a receber 
a mensagem). Por depender do receptor alcançar um determinado estado a operação é 
dita não local. 
Um send ready é aquele que espera o comando receive correspondente ser 
alcançado para poder iniciar. O send ready possui semântica igual a operação de send 
standard e send synchronous. 
As operações para buffered, synchronous e ready são indicadas por um prefixo 
B, S ou R na frente da assinatura da função, exemplo: MPI_BSEND, MPI_SSEND, 
MPI_RSEND. 
Alternativamente à execução bloqueante, existea não bloqueante que começa a 
operação (por exemplo, pode começar a copiar para o buffer), mas não termina e 
 
 
 
7 
prossegue com sua execução. O propósito de permitir operações não bloqueantes é 
otimizar a execução de programas. No entanto se faz necessário a percepção de 
chamada iniciada (send_start) e chamada completada (send_complete). 
Está claro que as chamadas não bloqueantes operações de send podem iniciar 
sem dependência alguma, mas para serem completadas podem depender do estado do 
receptor e portanto podem ser não locais. A única chamada local não bloqueante é o 
send buffered, que não depende de outro sinal para completar, ou seja, a chamada inicia 
e completa localmente. 
A tabela abaixo resume as características de cada tipo de operação. 
 
Tipo de operação Variante Local ou não local Comando MPI 
Bloqueante Standard Não local MPI_(SEND | RECV) 
Bloqueante Buffered Local MPI_BSEND 
Bloqueante Synchronous Não local MPI_SSEND 
Bloqueante Ready Não local MPI_RSEND 
Não bloqueante Standard Local ou Não local 
*(depende do buffer) 
MPI_I(SEND | RECV) 
Não bloqueante Buffered Local MPI_IBSEND 
Não bloqueante Synchronous (send start) Local 
(send complete) Não local 
MPI_ISSEND 
Não bloqueante Ready (send start) Local 
(send complete) Não local 
MPI_IRSEND 
O padrão MPI estabelece o prefixo I (imediato) juntamente com as variantes B 
(buffered), S (synchronous) ou R (ready) como assinatura das funções, exemplo: 
MPI_ISEND(standard), MPI_IBSEND, MPI_ISSEND, MPI_IRSEND. 
 
7. Comunicação Coletiva 
 É possível definir grupos e fazer com que esses grupos troquem informação entre 
si, ou estabelecer como a comunicação será feita dentro do grupo. A figura abaixo 
ilustra os tipos de comunicação coletiva, cada linha representa um processo, e cada 
coluna representam os dados. 
 
 
 
 
8 
 
 
 Na broadcast, um dado é replicado para os demais processos do grupo. No 
scatter, ocorre a distribuição dos dados, a centralização ocorre no gather. O allgather 
centraliza a informação em cada um dos processos, e o complete exchange realiza uma 
espécie de transposição de dados. 
 
8. Topologia Virtual de Processos 
O MPI faz uma distinção clara entre topologia física e virtual. O padrão não 
especifica como os processos são mapeados fisicamente, no entanto em diversas 
situações é conveniente atrelar uma topologia específica para facilitar sua referência. 
(como por exemplo a cartesiana, para um programa que faz operações recorrentes com 
processos vizinhos). Topologias são atributos opcionais dos intra-comunicadores. Os 
tipos suportados de topologia são: Cartesiana, grafal e grafal distribuída. 
 
9. Entrada e Saída (E/S) paralela 
A versão 1.1 o MPI não suportava escrita paralela, e a maneira mais comum de 
escrever um programa que fizesse entrada e saída de dados era deixar um processo 
único tomando conta do arquivo e os demais fazendo computação e fornecendo 
informação ao processo que manuseia o arquivo. 
 
 
 
9 
A seguir vamos demonstrar como é possível utilizar o MPI e paralelizar essa 
entrada e saída de dados. 
 
Figura 2. Diagrama de uma escrita sendo manuseada por 1 processo. 
 
#include "mpi.h" 
#include <stdio.h> 
#define BUFSIZE 100 
int main(int argc, char *argv[]) 
{ 
 int i, myrank, numprocs, buf[BUFSIZE]; 
 MPI_Status status; 
 FILE *myfile; 
 MPI_Init(&argc, &argv); 
 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
 MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
 for (i=0; i<BUFSIZE; i++) 
 buf[i] = myrank * BUFSIZE + i; 
 if (myrank != 0) 
 MPI_Send(buf, BUFSIZE, MPI_INT, 0, 99, MPI_COMM_WORLD); 
 else { 
 myfile = fopen("testfile", "w"); 
 fwrite(buf, sizeof(int), BUFSIZE, myfile); 
 for (i=1; i<numprocs; i++) { 
 MPI_Recv(buf, BUFSIZE, MPI_INT, i, 99, MPI_COMM_WORLD, 
 &status); 
 } 
 fwrite(buf, sizeof(int), BUFSIZE, myfile); 
 } 
 fclose(myfile); 
 MPI_Finalize(); 
return 0; } 
No exemplo acima o processo 0 é o responsável por manusear o arquivo, os 
demais somente fazem computação e devolvem ao processo 0. 
É possível fazer um incremento neste esquema, fazendo com que os arquivos 
sejam escritos de forma independente por cada um dos processos. Ou seja, cada 
processo abre, escreve e fecha o arquivo. As principais desvantagens dessa abordagem 
são: a) os arquivos precisam ser juntados para utilização futura por um outro processo, 
b) se uma aplicação for escrita de forma paralela, ela vai necessariamente paralelizar até 
no máximo o número de arquivos produzidos, c) é difícil manusear e trafegar na rede 
vários arquivos, assim como manter lógica deles. 
 
 
 
10 
 
Figura 3. Escrevendo em múltiplos arquivos. 
 
#include "mpi.h" 
#include <stdio.h> 
#define BUFSIZE 100 
int main(int argc, char *argv[]) 
{ 
 int i, myrank, buf[BUFSIZE]; 
 char filename[128]; 
 MPI_File myfile; 
 MPI_Init(&argc, &argv); 
 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
 for (i=0; i<BUFSIZE; i++) 
 buf[i] = myrank * BUFSIZE + i; 
 sprintf(filename, "testfile.%d", myrank); 
 MPI_File_open(MPI_COMM_SELF, filename, 
 MPI_MODE_WRONLY | MPI_MODE_CREATE, 
 MPI_INFO_NULL, &myfile); 
 MPI_File_write(myfile, buf, BUFSIZE, MPI_INT, 
 MPI_STATUS_IGNORE); 
 MPI_File_close(&myfile); 
 MPI_Finalize(); 
return 0; } 
Similar a manipulação de arquivos do Unix, o MPI também precisa abrir, 
escrever e fechar um arquivo. Como cada processo utiliza seu próprio arquivo a api 
MPI_File_open é utilizada. O primeiro argumento MPI_COMM_SELF estabelece o 
comunicador entre os processos. O segundo argumento é o nome do arquivo. O terceiro 
parâmetro da chamada é o MPI_MODE_WRONLY | MPI_MODE_CREATE, isso 
força a sobrescrita caso já exista um arquivo, ou cria um novo se não existe. O quarto 
argumento define um objeto nulo para o MPI_Info object (um objeto utilizado para 
entrada em outras chamadas MPI). O quinto argumento é o endereço da variável 
MPI_File. MPI_File_open retorna um código que pode ser comparado com 
MPI_SUCCESS. A tabela a seguir mostra a assinatura do método e seus parâmetros. 
 
 
MPI_FILE_OPEN (comm, filename, amode, info, fh) 
Parameter type (IN, 
OUT or INOUT) 
Parameter name desc 
IN comm Communicator (handle) 
IN filename Name of the file (String) 
IN amode Way to access the file (integer) 
IN info Info object 
OUT fh New file handle 
 
 
 
11 
Para escrever o arquivo, o programa utiliza a api MPI_FILE_WRITE, com 
parâmetros similares ao MPI_RECV. 
 
MPI_FILE_WRITE (fh, buf, count, datatype, status) 
Parameter type (IN, 
OUT or INOUT) 
Parameter 
name 
desc 
INOUT fh File handle 
IN buf Initial address of receive buffer 
IN count Number of elements of receive buffer(non-negative integer) 
IN datatype Datatype of each send buffer elemento (handle) 
OUT status Status object 
Finalmente, depois que o arquivo foi modificado, MPI_FILE_CLOSE é 
necessário para fechar o arquivo de forma segura. 
 
MPI_FILE_CLOSE (fh) 
Parameter type (IN, OUT or INOUT) Parameter name desc 
INOUT fh File handle 
É possível escrever em um único arquivo de modo que os processos possam 
colaborar na construção do arquivo, a figura abaixo ilustra a estratégia utilizada. 
 
Figura 4. Processos escrevendo em um único arquivo. 
 
#include "mpi.h" 
#include <stdio.h> 
#define BUFSIZE 100 
int main(int argc, char *argv[]) 
{ 
 int i, myrank, buf[BUFSIZE]; 
 MPI_File thefile; 
 MPI_Init(&argc, &argv); 
 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
 for (i=0; i<BUFSIZE; i++) 
 buf[i] = myrank * BUFSIZE + i; 
 MPI_File_open(MPI_COMM_WORLD, "testfile", 
 MPI_MODE_CREATE | MPI_MODE_WRONLY, 
 MPI_INFO_NULL, &thefile); 
 MPI_File_set_view(thefile, myrank * BUFSIZE * sizeof(int), 
 MPI_INT, MPI_INT, "native", MPI_INFO_NULL); 
 MPI_File_write(thefile, buf, BUFSIZE, MPI_INT,MPI_STATUS_IGNORE); 
 MPI_File_close(&thefile); 
 MPI_Finalize(); 
return 0; } 
 
 
 
12 
O programa acima é bem parecido com o anterior, mas a chamada de 
MPI_FILE_OPEN define MPI_COMM_WORLD, isto permite a colaboração entre os 
processos. 
Para permitir que os processos vejam segmentos diferentes dentro do arquivo 
utilizados a api MPI_FILE_SET_VIEW. 
 
MPI_FILE_SET_VIEW(fh, offset, etype, filetype, datarep, info) 
Parameter type (IN, OUT or INOUT) Parameter name desc 
INOUT fh File handle (MPI_File) 
IN offset Displacement/OffSet (integer) 
IN etype Elementary datatype (handle) 
IN filetype Filetype (handle) 
IN datarep Data representation (string) 
IN Info Info object (MPI_INFO object) 
O primeiro argumento fh é o MPI_File definido anteriormente, o segundo 
argumento é o offset aonde se iniciará a escrita [myrank * BUFSIZE * sizeof(int)], o 
terceiro argumento é o etype que define o tipo dos elementos manipulados, o quarto 
argumento é o filetype que pode ser um etype ou conjuntos derivados de etypes, o 
quinto argumento é o data representation que especifica o tipo de representação do 
arquivo, e finalmente o último argumento é um MPI_INFO object. 
Não é difícil imaginar um outro possível cenário agora ao invés de escrita, 
ocorre a leitura paralela, os exemplos são análogos, apenas substituindo a api 
MPI_FILE_WRITE por MPI_FILE_READ, a assinatura dos dois métodos são 
análogos, e também é necessário indicar aonde o processo deve iniciar sua escrita com 
MPI_FILE_SET_VIEW. 
A seguir um outro programa que escrito em C++ que faz a leitura de um arquivo 
com múltiplos processos. 
#include "mpi.h" 
#include <stdio.h> 
int main(int argc, char *argv[]) 
{ 
 int myrank, numprocs, bufsize, *buf, count; 
 MPI_File thefile; 
 MPI_Status status; 
 MPI_Offset filesize; 
 MPI_Init(&argc, &argv); 
 MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
 MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
 MPI_File_open(MPI_COMM_WORLD, "testfile", MPI_MODE_RDONLY, 
 MPI_INFO_NULL, &thefile); 
 MPI_File_get_size(thefile, &filesize); /* in bytes */ 
 filesize = filesize / sizeof(int); /* in number of ints */ 
 bufsize = filesize / numprocs + 1; /* local number to read */ 
 buf = (int *) malloc (bufsize * sizeof(int)); 
 MPI_File_set_view(thefile, myrank * bufsize * sizeof(int), 
 MPI_INT, MPI_INT, "native", MPI_INFO_NULL); 
 MPI_File_read(thefile, buf, bufsize, MPI_INT, &status); 
 MPI_Get_count(&status, MPI_INT, &count); 
 printf("process %d read %d ints\n", myrank, count); 
 MPI_File_close(&thefile); 
 MPI_Finalize(); 
 return 0; } 
 
 
 
13 
 
10. Considerações e Conclusões 
O padrão MPI define um conjunto de operações padrão para operar com 
passagem de mensagem. Ao definir comportamento esperado, ele permite que diversas 
implementações em diversas linguagens sejam disponíveis (Fortran, C, C++, Java), 
assim como padronização de diversos produtos comerciais como (Scali MPI Connect, 
WMPI II,SGI Message Passing Toolkit, Intel MPI, Sun MPI, HP-MPI, MPI/Pro). 
 
11. Referências Bibliográficas 
 
[1] MPI: A Message-Passing Interface Standard Version 3.0. Setembro 2012. 
Disponível em: http://www.mpi-forum.org/docs/mpi-3.0/mpi30-report.pdf. Acessado 
em outubro de 2012. 
 
[2] Message Passing Interface. Disponível em: http://en.wikipedia.org/wiki/Message_ 
Passing_Interface. Acessado em: outubro de 2012. 
 
[3] MPJ Express. Disponível em: http://mpj-express.org/. Acessado em: outubro de 
2012. 
 
[4] MPJ Express: An Implementation of MPI in Java Linux/UNIX/Mac User Guide. 
Disponível em: http://mpj-express.org/docs/guides/linuxguide.pdf. Acessado em: 
outubro de 2012. 
 
[5] Culler D. E.; Singh J. P. Kaufmman M. Parallel Computer Architecture. Morgan 
Kaufmann Publishers, 1999. 
 
[6] Gropp W.; Lusk E.; Thakur R. Using MPI-2 Advanced Features of the Message 
Passing Interface, MIT press, 1994. 
 
[7] Open MPI. Disponível em: http://www.open-mpi.org/. Acessado em: outubro de 
2012. 
 
[8] Sun MPI 6.0 Software Programming and Reference Manual. Disponível em: 
http://docs.oracle.com/cd/E19061-01/hpc.cluster5/817-0085-10/. Acessado em: outubro 
de 2012.

Continue navegando