Computação Paralela - Atividade 06

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.

Questão 01 - 0,5 Ponto.

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

Questão 02 - 0,5 Ponto.

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.

Questão 03 - 0,5 Ponto.

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.

Questão 04 - 1 Ponto.

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