Exemplo de uma implementação MPI em C: Comunicação em Anel

3 minutos de leitura

Atualizado em:

[caption id="attachment_886" align="alignright" width="260"]Comunicação em Anel usando MPI Comunicação em Anel usando MPI[/caption]

Exemplo de uma implementação em MPI (Message Passing Interface) na linguagem C, que envia um valor pelos processadores no formato de um anel, por exemplo: o primeiro processador envia para o segundo que envia para o terceiro, assim por diante até o último enviar para o primeiro.

Para instalar e rodar o OpenMPI no Linux, veja esta post que escrevi: Olá Mundo com MIP em C

Na execução do programa há a opção de definir o número de voltas, e é contabilizado o tempo em segundos de cada volta e o tempo total no final.

Código fonte

comunicacao-anel.c

#include 
#include 
#include 

int size, rank, msg, tag, voltas;
 
int main(int argc, char *argv[]){
   MPI_Status stat;
   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD,&size);
   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
	
	//Passar o número de voltas no parâmentro, caso contrário o numero de voltas será 1
	if (argc>1){
		voltas = atoi(argv[1]);
	}else{
		voltas = 1;
	}

	int controleVoltas = 1;	
	int proximo = rank + 1;
	int anterior = rank - 1;
	double startTime, voltaAnterior;

	//Controla que é o proximo e o anterior
	if (rank==size-1){
		proximo = 0;
	}
	if (rank==0){
		anterior = size-1;
	}

	//Se for o 0 inicia o envio
	if(rank==0){
	   	msg = 42; tag = 0;
	
		voltaAnterior = startTime = MPI_Wtime();

		MPI_Send(&msg, 1, MPI_INT, proximo, tag, MPI_COMM_WORLD);
		printf("Processo %d enviou %d para %d.\n", rank, msg, proximo);		
	}
	
	//Roda o valor enquanto o número de voltas não for ultrapassado
	while (controleVoltas<=voltas){
		controleVoltas++;

		//Aguarda o recebimento do proc. anterior
		MPI_Recv(&msg, 1, MPI_INT, anterior, tag, MPI_COMM_WORLD, &stat);
		printf("Processo %d recebeu %d de %d.\n", rank, msg, anterior);
		
		//Se voltar para o 0 marca o tempo da volta
		if (rank==0){
			double tempoVolta = MPI_Wtime();
			printf("Tempo da volta %d: %f segundos\n",controleVoltas-1,tempoVolta-voltaAnterior);
			voltaAnterior = tempoVolta;
		}

		//Se voltar para o 0 e não tiver mais voltas, encerra o loop
		if (rank==0 && controleVoltas>voltas)
			continue;

		//Envia o valor para o próximo proc.
		MPI_Send(&msg, 1, MPI_INT, proximo, tag, MPI_COMM_WORLD);
		printf("Processo %d enviou %d para %d.\n", rank, msg, proximo);	
	}	
	
	//No fim o 0 marca o tempo total
	if (rank==0){
		double tempo = MPI_Wtime();
		printf("Tempo total: %f segundos\n",tempo-startTime);
	}
	
   MPI_Finalize();
}

Execução

Para executar: mpirun -np {num_proc} comunicacao-anel {num_voltas}

Saída da execução com 4 processadores e 1 volta:

$mpirun -np 4 comunicacao-anel 1
Processo 0 enviou 42 para 1.
Processo 1 recebeu 42 de 0.
Processo 1 enviou 42 para 2.
Processo 2 recebeu 42 de 1.
Processo 2 enviou 42 para 3.
Processo 0 recebeu 42 de 3.
Tempo da volta 1: 0.000147 segundos
Tempo total: 0.000160 segundos
Processo 3 recebeu 42 de 2.
Processo 3 enviou 42 para 0.

Saída da execução com 4 processadores e 2 voltas:

$mpirun -np 4 comunicacao-anel 2
Processo 0 enviou 42 para 1.
Processo 0 recebeu 42 de 3.
Tempo da volta 1: 0.000206 segundos
Processo 0 enviou 42 para 1.
Processo 0 recebeu 42 de 3.
Tempo da volta 2: 0.000026 segundos
Tempo total: 0.000235 segundos
Processo 1 recebeu 42 de 0.
Processo 1 enviou 42 para 2.
Processo 1 recebeu 42 de 0.
Processo 1 enviou 42 para 2.
Processo 2 recebeu 42 de 1.
Processo 2 enviou 42 para 3.
Processo 2 recebeu 42 de 1.
Processo 2 enviou 42 para 3.
Processo 3 recebeu 42 de 2.
Processo 3 enviou 42 para 0.
Processo 3 recebeu 42 de 2.
Processo 3 enviou 42 para 0.

Conclusão

Este foi um exemplo simples de uso do MPI, que é uma ferraenta muit poderosa para processamento paralelo.

[]'s

Deixe um comentário