Esta atividade deve ser colocada no repositório, nas pasta atividades/atividade06 sob os nomes de arquivos indicados na questão.
Valor: 2,5 Pontos.
Data de Entrega: 07/09/2020.
Considere a seguinte aplicação MPI. Nela, os processos definem vetores aleatórios, calculam a média global e o desvio padrão. Salve o código em questao01.c
// Cálculo das Médias
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>
#define NELEM 1024
int main(int argc, char *argv[]) {
int i, rank, size;
float *random_numbers;
float avg, dif_quad_local = 0, sum_local = 0;
float sum_global, dif_quad_global, std_dev;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Cria um vetor de números aleatórios em cada processo.
srand(MPI_Wtime() * rank);
random_numbers = (float *) malloc(sizeof(float) * NELEM);
for(i = 0; i < NELEM; i++)
random_numbers[i] = (rand()/(float)RAND_MAX);
for(i = 0; i < NELEM; i++)
sum_local += random_numbers[i];
printf("Process %d: local sum %f, local average %f .\n", rank, sum_local, sum_local/NELEM);
// Média Global
MPI_Allreduce(&sum_local, &sum_global, 1, MPI_FLOAT, MPI_SUM, MPI_COMM_WORLD);
avg = sum_global / (NELEM * size);
// Soma local do Quadrado das diferenças
for(i = 0; i < NELEM; i++)
dif_quad_local += (random_numbers[i]- avg) * (random_numbers[i] - avg);
// Soma Global do Quadrado das diferenças
MPI_Reduce(&dif_quad_local, &dif_quad_global, 1, MPI_FLOAT, MPI_SUM, 0, MPI_COMM_WORLD);
if (rank == 0) {
std_dev = sqrt(dif_quad_global/(NELEM * size));
printf("Average %f, Standard Deviation %f\n", avg, std_dev);
}
free(random_numbers);
MPI_Finalize();
return 0;
}
Reescreva o código sem o uso da função MPI_Allreduce e salve em questao01_no_all.c. Execute o código original e modificado com N = 1024 * 1024 e com 2, 4, 6 e 8 processos, na sua própria máquina. Prepare um arquivo questao01.txt com os resultados.
# Core i5 4440
# N = 1024 * 1024
# Processos Tempo MPI_Allreduce Tempo sem MPI_Allreduce
1 ... ...
2 ... ...
4 ... ... .
6 ... ...
8 ... ...
Considere o exemplo abaixo como demonstração do uso da coletiva MPI_Alltoall:
// Cálculo das Médias
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
int i, rank, size;
int *input_array, *output_array;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
input_array = (int *) malloc(size * sizeof(int));
output_array = (int *) malloc(size * sizeof(int));
for (i = 0; i < size; i++)
input_array[i] = rank * size + i;
printf("Input for process %d\n", rank);
for (i = 0; i < size; i++)
printf("%d ", input_array[i]);
printf("\n");
MPI_Alltoall(input_array, 1, MPI_INT, output_array, 1, MPI_INT, MPI_COMM_WORLD);
printf("Output for process %d\n", rank);
for (i = 0; i < size; i++)
printf("%d ", output_array[i]);
printf("\n");
free(input_array);
free(output_array);
MPI_Finalize();
return 0;
}
Altere o programa para que cada programa envie e recebe 2 elementos dos demais processos, salvando o programa resultante em questao02.c.
Escreva uma programa questao03.c para calcular o produto escalar entre dois vetores de tipo ponto flutuante, utilizando rotinas de comunicação coletiva do MPI para envio dos vetores iniciais e recepção dos resultados parciais pelo processo raiz. Considere que os dois vetores iniciais são inicializados na raiz, ambos com todos os elementos iguais a valores fornecidos como parâmetro. O tamanho dos vetores também é um parâmetro. Por exemplo:
$ mpirun -np 4 ./prodEscalarVetor 1.0 2.0 100
Executa o produto escalar de dois vetores, o primeiro com 100 elementos iguais a 1.0, o segundo com 100 elementos iguais a 2.0. Para facilitar, assuma que a divisão de N (tamanho do vetor) por P (quantidade de processos) não tem resto. Assuma que o valor de N não é conhecido e deve ser enviado pelo processo raiz para os demais processos com o uso de uma rotina de comunicação coletiva.
Execute o programa anterior com N = 1.000.000 e com 1, 2, 4, 6 e 8 processos utilizando uma máquina com 8 núcleos na nuvem AWS. Instrumente o código com o uso da rotina MPI_Wtime(). Trace os gráficos, com o número de processadores no eixo x, para as seguintes grandezas: tempo de execução e speedup. Nomeie o gráfico de questao04_01node_08cores.png. Refaça os experimentos para um cluster de duas máquinas com 4 núcleos cada nomeie o arquivo como questao04_02nodes_04cores.png.
Você pode usar qualquer ferramenta que quiser para criar os gráficos (gnuplot, Excel, LibreOffice, etc);