Esta atividade deve ser colocada no repositório, nas pasta atividades/atividade05 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, o processo 0 define uma quantidade aleatória de números (entre 0 e MAX-1) e os envia para o processo 1.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>
#define MAX 100
int main(int argc, char *argv[]) {
int rank, total_num, tag = 0;
int source = 0, destination = 1, numbers[MAX];
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == source) {
srand(time(0));
total_num = (rand() / (float) RAND_MAX) * MAX;
MPI_Send(numbers, total_num, MPI_INT, destination, tag, MPI_COMM_WORLD);
printf("Process %d sent %d numberts to 1\n", source, total_num);
} else if (rank == destination) {
MPI_Recv(numbers, MAX, MPI_INT, source, tag, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_INT, &total_num);
printf("Process %d received %d numbers. Source = %d, tag = %d\n", destination, total_num, status.MPI_SOURCE, status.MPI_TAG);
}
MPI_Finalize();
return 0;
}
Este código utiliza a função MPI_Get_count, que recebe uma variável do tipo MPI_Status preenchida por uma chamada MPI_Recv anterior e retorna a quantidade de valores recebidos. Os valores dos números não importam, pois queremos apenas exercitar as funções do MPI.
Você deve modificar o código para que seja executado com um número qualquer de processos, e que todos os processos com rank diferente de 0 enviem uma mensagem com tamanho aleatório para o processo 0. Cada processo deve informar na tela quantos números está enviando ao 0. Quando terminar de receber todas as mensagens, o processo 0 deve também informar quantos números recebeu de cada outro processo. Salve o arquivo no repositório sob o nome questao01.c.
Dica: você pode usar MPI_ANY_SOURCE e MPI_ANY_TAG para facilitar a troca de mensagens.
O programa a seguir implementa Método do Trapézio para fazer o cálculo da integral de uma função (exp) em um intervalo (limitado por a e b).
#include <stdio.h>
#include <math.h>
#include <mpi.h>
double f(double x) {
double return_val;
return_val = exp(x);
return return_val;
}
int main(int argc, char *argv[]) {
int rank, size;
double a = 0.0, b = 1.0;
long int n = 100000000;
double x,h;
double integral = 0.0, total;
int source, destination = 0;
int tag = 3;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
h = (b - a)/n;
if (rank == 0)
integral = (f(a) + f(b)) / 2.0;
for (x = a + h * (rank + 1); x < b; x += size * h) {
integral += f(x);
}
integral = integral * h;
if (rank == 0) {
total = integral;
for (source = 1; source < size; source++) {
MPI_Recv(&integral, 1, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, &status);
total += integral;
}
} else {
MPI_Send(&integral, 1, MPI_DOUBLE, destination, tag, MPI_COMM_WORLD);
}
if (rank == 0) {
printf("With n = %ld.\n", n);
printf("Integral from %lf to %lf = %lf \n", a, b, total);
}
MPI_Finalize();
return 0;
}
Antes de continuar, salve o código no arquivo questao02.c e tenha certeza que você entende como as iterações do laço estão sendo distribuídas entre os processos. O segredo para essa compreensão é entender o primeiro laço for.
Após compreender a distribuição dos processos, execute o programa com 1, 2, 4 e 8 processos. Use sua própria máquina, independente de quantos núcleos ela tem.
Se as execuções ocorrerem com sucesso, instrumente o código com o uso da rotina MPI_Wtime e anote o tempo de execução para cada número de processos. Não se preocupe se os valores estiverem muito próximos ou semelhantes.
Armazene o tempo de execução no arquivo questao02.txt com o formato abaixo:
# Core i5 4440
# Processos Tempo
1 ...
2 ...
4 ...
6 ...
8 ...
Escreva um programa para calcular o produto escalar de dois vetores. Utilize rotinas MPI_Send e MPI_Recv para comunicação entre os processos. Considere cada vetor com N posições, informado como argumento na linha de comando, e divida a operação entre P processos distintos. Considere que a dividação de N por P não tem resto. Atribua os valores iniciais aos vetores localmente e assuma que todos os processos conhecem o tamanho N total do vetor. Salve o resultado no arquivo questao03.c.
Execute o programa do exercício anterior com N = 1.000.000 e com 1, 2, 4 e 8 processos, na sua própria máquina. Instrumente o código com uso da rotina MPI_Wtime(). Faça um novo arquivo questao04.txt no mesmo formato da Questão 02.
Considere uma topologia em anel para N processos. Ou seja processo 0 está "conectado" ao processo 1, processo 1 ao processo 2, assim sucessivamente, até o processo N - 1 se conectar ao processo 0. Esta "ligação" não é fixa, trata-se do fluxo das mensagens.
Escreva um programa chamado questao05.c utilizando as rotinas MPI_Send e MPI_Recv para comunicação entre os processos que faça circular uma mensagem contendo um inteiro positivo ao longo desse canal. O processo com rank 0 é quem inicia a transmissão e cada vez que a mensagem passa por ele novamente o valor contido na mensagem deve ser decrementando até chegar ao valor 0. Quando um processo receber a mensagem com valor 0 ele deverá passá-la adiante e então terminar sua execução. O valor inicial deve ser informado como argumento na linha de comando.
Dica: para identificar os nós vizinhos no anel faça:
destination = (rank + 1) % size;
source = (rank + size - 1) % size;