| | | |

Computação Paralela com C++

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

3.4 Reduções

Reduções são rotinas que reduzem um conjunto de dados em um conjunto menor. 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 múltiplos processos. Consulte a Figura 3.5.

Refer to caption
Figura 3.5: Redução de dados.

Sua sintaxe é a seguinte:

1int MPI_Reduce(
2 const void *sendbuf,
3 void *recvbuf,
4 int count,
5 MPI_Datatype datatype,
6 MPI_Op op,
7 int root,
8 MPI_Comm comm)

O argumento sendbuf aponta para o endereço de memória do dado a ser enviado por cada processo, enquanto 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:

1 MPI_MAX maximum
2 MPI_MIN minimum
3 MPI_SUM sum
4 MPI_PROD product
5 MPI_LAND logical and
6 MPI_BAND bit-wise and
7 MPI_LOR logical or
8 MPI_BOR bit-wise or
9 MPI_LXOR logical xor
10 MPI_BXOR bit-wise xor
11 MPI_MAXLOC max value and location
12 MPI_MINLOC min value and location
Exemplo 3.4.1.(Produto interno)

O seguinte Código 14 computa o produto interno entre dois vetores de números randômicos. Cada processo aloca um pedaço de cada vetor, computam o produto interno entre os pedaços e, então, o processo 0 recebe o resultado da soma dos produtos internos computados em cada processo.

Código 14: reduce.cpp
1#include <iostream>
2#include <eigen3/Eigen/Dense>
3...
4// alloc
5int n = 10;
6int chunk_size = n / world_size;
7if (world_rank == world_size - 1)
8 chunk_size += n % world_size;
9
10srand(world_rank);
11Eigen::VectorXd local_u = Eigen::VectorXd::Random(chunk_size);
12Eigen::VectorXd local_v = Eigen::VectorXd::Random(chunk_size);
13
14// local dot product
15double local_dot = local_u.dot(local_v);
16
17// global dot product
18double global_dot = 0.0;
19MPI_Reduce(&local_dot, &global_dot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
20if (world_rank == 0)
21{
22 std::cout << "Dot product: " << global_dot << std::endl;
23}

No caso de arrays de dados, a operação de redução é feita para cada componente. Consulte a Figura 3.6.

Refer to caption
Figura 3.6: Redução de dados em arrays.
Observação 3.4.1.(MPI_Allreduce)

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.(Reduções assíncronas)

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

E. 3.4.1.

Faça um código C++/Open 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 C++/Open 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 C++/Open 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 C++/Open 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 C++/Open 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 C++/Open MPI para computar

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

usando a regra composta do trapézio.


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.

Computação Paralela com C++

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

3.4 Reduções

Reduções são rotinas que reduzem um conjunto de dados em um conjunto menor. 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 múltiplos processos. Consulte a Figura 3.5.

Refer to caption
Figura 3.5: Redução de dados.

Sua sintaxe é a seguinte:

1int MPI_Reduce(
2 const void *sendbuf,
3 void *recvbuf,
4 int count,
5 MPI_Datatype datatype,
6 MPI_Op op,
7 int root,
8 MPI_Comm comm)

O argumento sendbuf aponta para o endereço de memória do dado a ser enviado por cada processo, enquanto 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:

1 MPI_MAX maximum
2 MPI_MIN minimum
3 MPI_SUM sum
4 MPI_PROD product
5 MPI_LAND logical and
6 MPI_BAND bit-wise and
7 MPI_LOR logical or
8 MPI_BOR bit-wise or
9 MPI_LXOR logical xor
10 MPI_BXOR bit-wise xor
11 MPI_MAXLOC max value and location
12 MPI_MINLOC min value and location
Exemplo 3.4.1.(Produto interno)

O seguinte Código 14 computa o produto interno entre dois vetores de números randômicos. Cada processo aloca um pedaço de cada vetor, computam o produto interno entre os pedaços e, então, o processo 0 recebe o resultado da soma dos produtos internos computados em cada processo.

Código 14: reduce.cpp
1#include <iostream>
2#include <eigen3/Eigen/Dense>
3...
4// alloc
5int n = 10;
6int chunk_size = n / world_size;
7if (world_rank == world_size - 1)
8 chunk_size += n % world_size;
9
10srand(world_rank);
11Eigen::VectorXd local_u = Eigen::VectorXd::Random(chunk_size);
12Eigen::VectorXd local_v = Eigen::VectorXd::Random(chunk_size);
13
14// local dot product
15double local_dot = local_u.dot(local_v);
16
17// global dot product
18double global_dot = 0.0;
19MPI_Reduce(&local_dot, &global_dot, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
20if (world_rank == 0)
21{
22 std::cout << "Dot product: " << global_dot << std::endl;
23}

No caso de arrays de dados, a operação de redução é feita para cada componente. Consulte a Figura 3.6.

Refer to caption
Figura 3.6: Redução de dados em arrays.
Observação 3.4.1.(MPI_Allreduce)

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.(Reduções assíncronas)

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

E. 3.4.1.

Faça um código C++/Open 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 C++/Open 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 C++/Open 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 C++/Open 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 C++/Open 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 C++/Open MPI para computar

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

usando a regra composta do trapézio.


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
| | | |