| | | | |

3.1 Olá, Mundo!

Ajude a manter o site livre, gratuito e sem propagandas. Colabore!

Em revisão

A computação paralela com MPI inicia-se simultaneamente com múltiplos processadores (instâncias de processamento), cada um utilizando seu próprio endereço de memória (memória distribuída). Cada processo lê e escreve em seu próprio endereço de memória privada. Observamos que o processamento já inicia-se ramificado e distribuído, sendo possível a comunicação entre os processos por instruções explícitas (instruções MPI, Message Passing Interface). A sincronização entre os processos também requer instruções específicas.

Vamos escrever nosso primeiro código MPI. O Código ola.cc é paralelamente executado por diferentes processadores, cada processo escreve “Olá” e identifica-se.

Código: ola.cc
1#include <stdio.h>
2
3// API MPI
4#include <mpi.h>
5
6#include <gsl/gsl_cblas.h>
7
8int main() {
9  // Inicializa o MPI
10  MPI_Init(NULL, NULL);
11
12  // numero total de processos
13  int world_size;
14  MPI_Comm_size(MPI_COMM_WORLD, &world_size);
15
16  // ID (rank) do processo
17  int world_rank;
18  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
19
20  // Escreve mensagem
21  printf("Ola! Eu sou o processo %d/%d.\n",
22         world_rank, world_size);
23
24  // Finaliza o MPI
25  MPI_Finalize();
26
27  return 0;
28}

Na linha 3, o API MPI é incluído no código. O ambiente MPI é inicializado na linha 8 com a rotina MPI_Init inicializa o ambiente MPI. Na inicialização, o comunicador MPI_COMM_WORLD é construído entre todos os processos inicializados e um identificador (rank) é atribuído a cada processo. O número total de processos é obtido com a rotina MPI_Comm_size. Cada processo é identificado por um número natural sequencial 0, 1, …, world_size-1. O id (rank) de um processo é obtido com a rotina MPI_Comm_rank (veja a linha 16). A rotina MPI_Finalize finaliza o ambiente MPI.

Para compilar este código, digite no terminal

$ mpic++ ola.cc

Esta instrução de compilação é análoga a

g++ ola.cc -I/usr/lib/x86_64-linux-gnu/openmpi/include/openmpi
   -I/usr/lib/x86_64-linux-gnu/openmpi/include
   -pthread -L/usr/lib/x86_64-linux-gnu/openmpi/lib
   -lmpi_cxx -lmpi

ou semelhante dependendo da instalação. Para ver a sua configuração, digite

$ mpic++ ola.cc --showme

Ao compilar, um executável a.out será criado. Para executá-lo, basta digitar no terminal:

$ mpirun -np 2 a.out

Esta instrução inicializa simultaneamente duas cópias (-np 2, dois processos) do código ola.cc (do executável a.out). Cada processo é executado de forma idependente (em paralelo e não sincronizados).

Ao executar, devemos ver a saída do terminal como algo parecido com

Olá! Eu sou o processo 1/2.
Olá! Eu sou o processo 0/2.

A saída irá variar conforme o processo que primeiro enviar a mensagem para o dispositivo de saída. Execute o código várias vezes e analise as saídas!

3.1.1 Exercícios resolvidos

Em revisão

ER 3.1.1.

O número de instâncias de processamento pode ser alterado diretamente na instrução mpirun pela opção -np. Altere o número de instâncias de processamento para 4 e execute o Código ola.cc.

Solução.

Para alterar o número de instâncias de processamento não é necessário recompilar o código22endnote: 2Caso ainda não tenha compilado o código, copile-o.. Basta executá-lo com o comando

$ mpirun -np 4 ./a.out

A saída deve ser algo do tipo

Olá! Eu sou o processo 1/4.
Olá! Eu sou o processo 3/4.
Olá! Eu sou o processo 2/4.
Olá! Eu sou o processo 0/4.

Execute o código várias vezes e analise as saídas!

ER 3.1.2.

Escreva um código MPI para ser executado com 2 instâncias de processamento. Cada processo recebe os números inteiros

int n = 2;
int m = 3;

Então, um dos processos deve escrever a soma n+m e o outro deve escrever o produto.

Solução.

O código abaixo contém uma implementação deste exercício. Veja os comentários abaixo.

Código: sp.cc
1#include <stdio.h>
2#include <assert.h>
3
4// API MPI
5#include <mpi.h>
6
7int main(int argc, char** argv) {
8  // Inicializa o MPI
9  MPI_Init(NULL, NULL);
10
11  // numero total de processos
12  int world_size;
13  MPI_Comm_size(MPI_COMM_WORLD, &world_size);
14
15  // verifica o num. de processos
16  if (world_size != 2) {
17    printf("ERRO! Numero de processos "
18           "deve ser igual 2.\n");
19    int errorcode=-1;
20    MPI_Abort(MPI_COMM_WORLD, errorcode);
21  }
22
23  // ID (rank) do processo
24  int world_rank;
25  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
26
27  int n = 2;
28  int m = 3;
29
30  if (world_rank == 0)
31    printf("n+m = %d\n", n+m);
32  else if (world_rank == 1)
33    printf("n*m = %d\n", n*m);
34
35  // Finaliza o MPI
36  MPI_Finalize();
37
38  return 0;
39}

Neste código, os processos são abortados caso o usuário tente executá-lo com um número de processos diferente de 2. Para abortar todos os processos ativos, utiliza-se a rotina MPI_Abort (veja as linhas 15-21). O argumento de entrada errorcode é arbitrário e serve para informar o usuário de uma categoria de erros conforme a política de programação utilizada.

Observamos que o controle do que cada processo deve fazer, é feito através de sua identificação world_rank (veja as linhas 30-33).

3.1.2 Exercícios

Em revisão

E. 3.1.1.

Rode o Código ola.cc com um número de processadores (core) maior do que o disponível em sua máquina. O que você observa? Modifique a instrução mpirun para aceitar a execução confirme o número de threads disponível na máquina. Por fim, modifique a instrução de forma a aceitar um número arbitrário de instâncias de processamento.

E. 3.1.2.

Faça um código MPI para ser executado com 2 instâncias de processamento. Uma das instâncias de processamento deve alocar

int a = 2;
int b = 3;

e escrever a diferença ab. A outra instância deve alocar

int a = 4;
int b = 5;

e escrever o quociente b/a.


Envie seu comentário

As informações preenchidas são enviadas por e-mail para o desenvolvedor do site e tratadas de forma privada. Consulte a Política de Uso de Dados para mais informações. Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!