| | | |

Matemática Numérica Paralela

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

3.4 Reduções

Em revisão

Reduções são rotinas que reduzem um conjunto de dados em um conjunto menor de dados. Um exemplo de redução é a rotina de calcular o traço de uma matriz quadrada. Aqui, vamos apresentar algumas soluções MPI de rotinas de redução.

A rotina MPI_Reduce, permite a redução de dados distribuídos em um processo. Sua sintaxe é a seguinte

int MPI_Reduce(
  const void *sendbuf,
  void *recvbuf,
  int count,
  MPI_Datatype datatype,
  MPI_Op op,
  int root,
  MPI_Comm comm)

O argumento sendbuf aponta para o endereço de memória do dado a ser enviado por cada processo, enquando que o argumento recvbuf aponta para o endereço de memória onde o resultado da redução será alocada no processo root. O argumento count é o número de dados enviados por cada processo e datatype é o tipo de dado a ser enviado (o qual deve ser igual ao tipo do resultado da redução). O argumento comm é o comunicador entre os processos envolvidos na redução. A operação de redução é definida pelo argumento op e pode ser um dos seguintes

    MPI_MAX             maximum
    MPI_MIN             minimum
    MPI_SUM             sum
    MPI_PROD            product
    MPI_LAND            logical and
    MPI_BAND            bit-wise and
    MPI_LOR             logical or
    MPI_BOR             bit-wise or
    MPI_LXOR            logical xor
    MPI_BXOR            bit-wise xor
    MPI_MAXLOC          max value and location
    MPI_MINLOC          min value and location
Exemplo 3.4.1.

No seguinte código reduce.cc, cada processo aloca um número randômico na variável x. Em seguida, o processo 0 recebe o máximo entre os números alocados em todos os processos (inclusive no processo 0).

Código: reduce.cc
1#include <stdio.h>
2#include <stdlib.h>
3
4// API MPI
5#include <mpi.h>
6
7int main(int argc, char** argv) {
8
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 // cronometro
21 time_t init = time (NULL);
22
23 // semente do gerador randomico
24 srand (init + world_rank);
25
26 double x = double (rand ()) / RAND_MAX;
27
28 printf ("%d: %f\n",
29 world_rank, x);
30
31 double y;
32 MPI_Reduce (&x, &y, 1, MPI_DOUBLE,
33 MPI_MAX, 0, MPI_COMM_WORLD);
34
35 if (world_rank == 0)
36 printf ("Max. entre os numeros = %f\n",
37 y);
38 // Finaliza o MPI
39 MPI_Finalize();
40
41 return 0;
42}

Segue um teste de rodagem:

$ mpic++ reduce.cc
$ mpirun -np 3 a.out
0: 0.417425
1: 0.776647
2: 0.633021
Máx. entre os números = 0.776647

Verifique!

No caso de uma array de dados, a operação de redução será feita para cada componente. Veja o próximo exemplo.

Exemplo 3.4.2.

No reduce2.cc, cada processo aloca um vetor com dois números randômicos. Em seguida, o processo 0 recebe o vetor resultante da soma dos vetores alocados em cada processo (inclusive no processo 0).

Código: reduce2.cc
1#include <stdio.h>
2#include <stdlib.h>
3
4// API MPI
5#include <mpi.h>
6
7int main(int argc, char** argv) {
8
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 // cronometro
21 time_t init = time (NULL);
22
23 // semente do gerador randomico
24 srand (init + world_rank);
25
26 double x[2] = {double (rand ()) / RAND_MAX,
27 double (rand ()) / RAND_MAX};
28
29 printf ("%d: %f %f\n",
30 world_rank, x[0], x[1]);
31
32 double y[2];
33 MPI_Reduce (&x, &y, 2, MPI_DOUBLE,
34 MPI_SUM, 0, MPI_COMM_WORLD);
35
36 if (world_rank == 0)
37 printf ("Vetor soma = %f %f\n",
38 y[0], y[1]);
39
40 // Finaliza o MPI
41 MPI_Finalize();
42
43 return 0;
44}

Segue um teste de rodagem:

$ mpic++ reduce2.cc
$ mpirun -np 3 a.out
0: 0.193702 0.035334
Vetor soma = 0.656458 0.843728
1: 0.051281 0.447279
2: 0.411475 0.361114

Verifique!

Observação 3.4.1.

A rotina MPI_Allreduce executa uma redução de dados e o resultado é alocada em todos os processos. Sua sintaxe é similar a rotina MPI_Reduce, com exceção do argumento root, o qual não é necessário nessa rotina. Verifique!

Observação 3.4.2.

As rotinas MPI_Ireduce e MPI_Iallreduce são versões assíncronas das rotinas MPI_Reduce e MPI_Allreduce, respectivamente.

3.4.1 Exercícios

Em revisão

E. 3.4.1.

Faça um código MPI em cada processo aloca um número randômico na variável x. Então, o processo 0 recebe o mínimo entre os números alocados em cada processo, inclusive nele mesmo.

E. 3.4.2.

Faça um código MPI em cada processo aloca um número randômico na variável x. Então, o processo 0 recebe o produtório entre os números alocados em cada processo, inclusive nele mesmo.

E. 3.4.3.

Faça um código MPI para computar a soma dos termos de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Reduce e certifique-se de que cada processo aloque somente os dados necessários, otimizando o uso de memória computacional.

E. 3.4.4.

Faça um código MPI para computar a norma do máximo de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Reduce e certifique-se de que cada processo aloque somente os dados necessários, otimizando o uso de memória computacional.

E. 3.4.5.

Faça um código MPI para computar a norma L2 de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Allreduce de forma que cada processo contenha a norma computada ao final do código.

E. 3.4.6.

Faça um código MPI para computar

erf(x)=2π0xet2𝑑t (3.14)

usando a regra composta do ponto médio. Use a rotina MPI_Reduce.


Envie seu comentário

Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!

Opcional. Preencha seu nome para que eu possa lhe contatar.
Opcional. Preencha seu e-mail para que eu possa lhe contatar.
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.

Licença Creative Commons
Este texto é disponibilizado nos termos da Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional. Ícones e elementos gráficos podem estar sujeitos a condições adicionais.

Matemática Numérica Paralela

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

3.4 Reduções

Em revisão

Reduções são rotinas que reduzem um conjunto de dados em um conjunto menor de dados. Um exemplo de redução é a rotina de calcular o traço de uma matriz quadrada. Aqui, vamos apresentar algumas soluções MPI de rotinas de redução.

A rotina MPI_Reduce, permite a redução de dados distribuídos em um processo. Sua sintaxe é a seguinte

int MPI_Reduce(
  const void *sendbuf,
  void *recvbuf,
  int count,
  MPI_Datatype datatype,
  MPI_Op op,
  int root,
  MPI_Comm comm)

O argumento sendbuf aponta para o endereço de memória do dado a ser enviado por cada processo, enquando que o argumento recvbuf aponta para o endereço de memória onde o resultado da redução será alocada no processo root. O argumento count é o número de dados enviados por cada processo e datatype é o tipo de dado a ser enviado (o qual deve ser igual ao tipo do resultado da redução). O argumento comm é o comunicador entre os processos envolvidos na redução. A operação de redução é definida pelo argumento op e pode ser um dos seguintes

    MPI_MAX             maximum
    MPI_MIN             minimum
    MPI_SUM             sum
    MPI_PROD            product
    MPI_LAND            logical and
    MPI_BAND            bit-wise and
    MPI_LOR             logical or
    MPI_BOR             bit-wise or
    MPI_LXOR            logical xor
    MPI_BXOR            bit-wise xor
    MPI_MAXLOC          max value and location
    MPI_MINLOC          min value and location
Exemplo 3.4.1.

No seguinte código reduce.cc, cada processo aloca um número randômico na variável x. Em seguida, o processo 0 recebe o máximo entre os números alocados em todos os processos (inclusive no processo 0).

Código: reduce.cc
1#include <stdio.h>
2#include <stdlib.h>
3
4// API MPI
5#include <mpi.h>
6
7int main(int argc, char** argv) {
8
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 // cronometro
21 time_t init = time (NULL);
22
23 // semente do gerador randomico
24 srand (init + world_rank);
25
26 double x = double (rand ()) / RAND_MAX;
27
28 printf ("%d: %f\n",
29 world_rank, x);
30
31 double y;
32 MPI_Reduce (&x, &y, 1, MPI_DOUBLE,
33 MPI_MAX, 0, MPI_COMM_WORLD);
34
35 if (world_rank == 0)
36 printf ("Max. entre os numeros = %f\n",
37 y);
38 // Finaliza o MPI
39 MPI_Finalize();
40
41 return 0;
42}

Segue um teste de rodagem:

$ mpic++ reduce.cc
$ mpirun -np 3 a.out
0: 0.417425
1: 0.776647
2: 0.633021
Máx. entre os números = 0.776647

Verifique!

No caso de uma array de dados, a operação de redução será feita para cada componente. Veja o próximo exemplo.

Exemplo 3.4.2.

No reduce2.cc, cada processo aloca um vetor com dois números randômicos. Em seguida, o processo 0 recebe o vetor resultante da soma dos vetores alocados em cada processo (inclusive no processo 0).

Código: reduce2.cc
1#include <stdio.h>
2#include <stdlib.h>
3
4// API MPI
5#include <mpi.h>
6
7int main(int argc, char** argv) {
8
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 // cronometro
21 time_t init = time (NULL);
22
23 // semente do gerador randomico
24 srand (init + world_rank);
25
26 double x[2] = {double (rand ()) / RAND_MAX,
27 double (rand ()) / RAND_MAX};
28
29 printf ("%d: %f %f\n",
30 world_rank, x[0], x[1]);
31
32 double y[2];
33 MPI_Reduce (&x, &y, 2, MPI_DOUBLE,
34 MPI_SUM, 0, MPI_COMM_WORLD);
35
36 if (world_rank == 0)
37 printf ("Vetor soma = %f %f\n",
38 y[0], y[1]);
39
40 // Finaliza o MPI
41 MPI_Finalize();
42
43 return 0;
44}

Segue um teste de rodagem:

$ mpic++ reduce2.cc
$ mpirun -np 3 a.out
0: 0.193702 0.035334
Vetor soma = 0.656458 0.843728
1: 0.051281 0.447279
2: 0.411475 0.361114

Verifique!

Observação 3.4.1.

A rotina MPI_Allreduce executa uma redução de dados e o resultado é alocada em todos os processos. Sua sintaxe é similar a rotina MPI_Reduce, com exceção do argumento root, o qual não é necessário nessa rotina. Verifique!

Observação 3.4.2.

As rotinas MPI_Ireduce e MPI_Iallreduce são versões assíncronas das rotinas MPI_Reduce e MPI_Allreduce, respectivamente.

3.4.1 Exercícios

Em revisão

E. 3.4.1.

Faça um código MPI em cada processo aloca um número randômico na variável x. Então, o processo 0 recebe o mínimo entre os números alocados em cada processo, inclusive nele mesmo.

E. 3.4.2.

Faça um código MPI em cada processo aloca um número randômico na variável x. Então, o processo 0 recebe o produtório entre os números alocados em cada processo, inclusive nele mesmo.

E. 3.4.3.

Faça um código MPI para computar a soma dos termos de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Reduce e certifique-se de que cada processo aloque somente os dados necessários, otimizando o uso de memória computacional.

E. 3.4.4.

Faça um código MPI para computar a norma do máximo de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Reduce e certifique-se de que cada processo aloque somente os dados necessários, otimizando o uso de memória computacional.

E. 3.4.5.

Faça um código MPI para computar a norma L2 de um vetor de n números randômicos, com nnp, sendo np o número de processos. Use a rotina MPI_Allreduce de forma que cada processo contenha a norma computada ao final do código.

E. 3.4.6.

Faça um código MPI para computar

erf(x)=2π0xet2𝑑t (3.14)

usando a regra composta do ponto médio. Use a rotina MPI_Reduce.


Envie seu comentário

Aproveito para agradecer a todas/os que de forma assídua ou esporádica contribuem enviando correções, sugestões e críticas!

Opcional. Preencha seu nome para que eu possa lhe contatar.
Opcional. Preencha seu e-mail para que eu possa lhe contatar.
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.

Licença Creative Commons
Este texto é disponibilizado nos termos da Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional. Ícones e elementos gráficos podem estar sujeitos a condições adicionais.

Pedro H A Konzen
| | | |