PPC Prova 2

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 6

Avaliação 2 [09/12/2020]

COMP0397 - PROGRAMAÇÃO PARALELA E CONCORRENTE


Prof. Hendrik Macedo (hendrik@academico.ufs.br)

INSTRUÇÕES (leia com bastante atenção)

i. A prova possui 9 questões. As 8 primeiras valem 1pt cada. A questão 9 vale 2pts.
ii. Respostas devem estar em um arquivo de texto simples Aval1_SeuNome.txt conforme modelo
ao final.
iii. Todas as respostas devem vir acompanhadas de justificativas, obrigatoriamente. Respostas
sem justificativa serão desconsideradas, ou seja, 0pt (zero ponto) será atribuído à questão.
iv. Você só terá direito a efetuar um único upload do arquivo-resposta pelo SIGAA. O sistema não
permitirá novos envios substitutivos/corretivos.
v. O horário de prova será das 12h30 às 15h.

CÓDIGO DE CONDUTA E ÉTICA. Ao se submeter a esta avaliação, você está automaticamente


concordando que adotorá postura ética, se comprometendo a não se comunicar em hipótese
alguma com colegas desta ou de qualquer outra turma, seja por meio digital ou presencial.
Você também estará garantindo que é o autor exclusivo do arquivo-resposta de que fará
upload. Por fim, você estará ciente de que o professor poderá utilizar todos os recursos
tecnológicos disponíveis para verificar a ocorrência de plágio entre as justificativa
apresentadas pela turma.

Questões
1. Qual o maior risco de mal funcionamento de um programa MPI que pode levar a resultados
errados (ou resultado algum)?

A. As race conditions que fazem com que processos concorrentes possam consumir variáveis que
estão simultaneamente sendo alteradas.
B. A possibilidade de deadlock quando dois ou mais processos ficam mutualmente bloqueados em
virtude de operações de comunicação point-to-point.
C. A possibilidade de deadlock quando dois ou mais processos ficam bloqueados em virtude de
operações de comunicação coletiva.
D. O mau design de solução paralela que exige que vários processos troquem uma quantidade
exagerada de dados, gerando overhead de comunicação em excesso.
E. O mal design de solução paralela que provoca um desbalanceamento exagerado de carga entre
os processos.

2. Sobre os tipos de comunicações coletivas existentes em MPI, assinale a afirmação correta.


A. MPI_Scatter permite distribuir n elementos de um array entre os p processos existentes de forma
ordenada: os primeiros n/p dados são enviados ao processo 0, os n/p seguintes ao processo 1 e
assim sucessivamente.
B. MPI_Gather é a operação "inversa" do MPI_Scatter. Se cada processo armazena um subarray de
m elementos, esses serão coletados de forma ordenada (processo 1, 2, 3, etc..) e enviados ao
processo 0, necessariamente.
C. MPI_Allgather possui o mesmo efeito prático que realizar um MPI_Bcast seguido de um
MPI_Gather, com a vantagem de gerar menos overhead de comunicação.
D. MPI_Scatter permite distribuir n elementos de um array entre os p processos existentes,
excluindo-se o processo 0, que fica responsável apenas pelo retorno dos dados com MPI_Gather.
E. MPI_Scatter permite que selecionemos exatamente para quais processos de uma mesma família
(mesmo comunicador) desejamos repartir os dados do array original.

3. Assinale a alternativa que pode representar uma possível saída impressa pela execução
 mpiexec -n 3 ...  do programa abaixo.

#include <stdio.h>
#include <mpi.h>
int main(void) {
int comm_sz, my_rank, status, x, y, z;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
switch(my_rank) {
case 0:
x=0; y=1; z=2;
MPI_Bcast(&x, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Send(&y, 1, MPI_INT, 2, 43, MPI_COMM_WORLD);
MPI_Bcast(&z, 1, MPI_INT, 1, MPI_COMM_WORLD);
break;
case 1:
x=3; y=8; z=5;
MPI_Bcast(&x, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&y, 1, MPI_INT, 1, MPI_COMM_WORLD);
break;
case 2:
x=6; y=7; z=8;
MPI_Bcast(&z, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Recv(&x, 1, MPI_INT, 0, 43, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
MPI_Bcast(&y, 1, MPI_INT, 1, MPI_COMM_WORLD);
break;
}
printf("| %d %d %d ", x, y, z);
MPI_Finalize();
return 0;
}

A. | 0 1 8 | 0 8 5 | 1 8 0
B. | 0 1 8
C. | 0 1 2 | 3 8 5 | 6 7 8
D. | 3 7 8 | 3 7 8 | 3 7 8
E. | 3 7 8

Observe o código a seguir escrito em MPI C (as chamadas  sleep(..)  servem para simular o
tempo de execução de cada operação) e responda às questões 4, 5 e 6.

#include <stdio.h>
#include <mpi.h>
#include <unistd.h>
void op0(void) {sleep(1);}
void op1(void) {sleep(2);}
void op2(void) {sleep(4);}
int main(void) {
int m, local_m, n, local_n;
int my_rank, comm_sz;
MPI_Comm comm;
MPI_Init(NULL, NULL);
comm = MPI_COMM_WORLD;
MPI_Comm_size(comm, &comm_sz);
MPI_Comm_rank(comm, &my_rank);
double local_start, local_finish, local_elapsed;
double elapsed = 0.0;
MPI_Barrier(comm);
local_start = MPI_Wtime();
if (my_rank == 0)
op0();
if (my_rank == 1)
op1();
if (my_rank == 2)
op2();
local_finish = MPI_Wtime();
local_elapsed = local_finish - local_start;
MPI_Reduce(&local_elapsed, &elapsed, 1, MPI_DOUBLE, MPI_MAX, 0, comm);
if (my_rank == 0)
printf("%.1f\n", elapsed);
MPI_Finalize();
return 0;
}

4. Qual alternativa representaria o valor a ser impresso pela execução do programa em


questão?

A. 1.0
B. 2.0
C. 4.0
D. 7.0
E. Não determinístico. Poderia ser qualquer um dos 4 tempos acima sugeridos.

5. Se comentássemos todas as quatro linhas contendo  if  (ou seja, as operações op0(), op1(),
op2() e printf(...) seriam executadas incondicionalmente), qual alternativa melhor representa o
que seria impresso ao fim da execução?
A. 1.0 2.0 4.0
B. 7.0 7.0 7.0
C. 0.0 7.0 0.0
D. 0.0 0.0 4.0
E. 4.0 4.0 4.0

6. A respeito da performance global do programa ilustrado, assinale a afirmação que


representa a justificativa mais apurada.

A. Se eliminarmos o elemento de sincronização existente no código, a performance global do


programa irá subir consideravelmente.
B. Se magicamente conseguíssemos balancear bem a carga entre processos, o elemento de
sincronização ainda assim afetaria bastante a performance global.
C. O maior problema do código em questão é o grande overhead de comunicação entre processos.
D. O maior problema do código em questão é o desbalanceamento de carga entre processos.
E. Nenhuma afirmação possui alta acuidade com a realidade.

Observe o trecho de código sequencial a seguir escrito em C e responda à questões 7, 8 e 9.

scanf("%d %d", &x, &c);


x++;
a = x+2;
b = a+3;
c++;
printf("| x = %d | a = %d | b = %d | c = %d ", x, a, b, c);

7. O código abaixo representa uma tentativa de paralelização do código acima em 4 cores.


Assinale a alternativa correta acerca dessa tentativa, considerando que o usuário forneceu
como entrada os valores 4 e 5.

#include <stdio.h>
#include <mpi.h>
int main(void) {
int my_rank, comm_sz, x, a, b, c;
MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
if (my_rank == 0) scanf("%d %d", &x, &c);
MPI_Bcast(&x, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&c, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (my_rank == 0) {x++; printf("| x = %d ", x);}
if (my_rank == 1) {a = x+2; printf("| a = %d ", a);}
if (my_rank == 2) {b = a+3; printf("| b = %d ", b);}
if (my_rank == 3) {c++; printf("| c = %d ", c);}
MPI_Finalize();
return 0;
}
A. Independente dos valores finais das variáveis, qualquer execução geraria a mesma sequência de
impressão: | x = ... | a = ... | b = ... | c = ...
B. Os valores finais de x e c estariam corretos mas os de a e b não necessariamente.
C. Nenhum dos valores estaria necessariamente correto.
D. Todos os valores estariam corretos, mas a ordem de impressão poderia variar.
E. Execuções diferentes podem levar a valores finais diferentes para uma ou mais variáveis.

8. O código abaixo representa outra tentativa de paralelização em 4 cores. Assinale a


alternativa correta acerca dessa tentativa, considerando a mesma entrada anterior.

#include <stdio.h>
#include <mpi.h>
int main(void) {
int my_rank, comm_sz, x, a, b, c;
MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
if (my_rank == 0) {
scanf("%d %d", &x, &c);
x++;
MPI_Send(&x, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
MPI_Send(&c, 1, MPI_INT, 3, 0, MPI_COMM_WORLD);
printf("| x = %d ", x);
} else if (my_rank == 1) {
MPI_Recv(&x, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
a = x+2;
MPI_Send(&a, 1, MPI_INT, 2, 0, MPI_COMM_WORLD);
printf("| a = %d ", a);
} else if (my_rank == 2) {
MPI_Recv(&a, 1, MPI_INT, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
b = a+3;
printf("| b = %d ", b);
} else if (my_rank == 3) {
MPI_Recv(&c, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
c++;
printf("| c = %d ", c);
}
MPI_Finalize();
return 0;
}

A. Qualquer execução geraria | x = 5 | a = 7 | b = 10 | c = 6, nessa ordem.


B. Os valores finais de x, a, b e c podem variar em execuções diferentes.
C. Esta codificação representa o melhor design de paralelização possível para o problema.
D. A impressão do valor final de b antes do de a é impossível.
E. A codificação funciona porque MPI_Recv bloqueia à espera do MPI_Send correspondente.

9. Crie uma versão alternativa de paralelização para o código anterior que permita que todos
os 4 processos envolvidos possam executar suas operações com o máximo de
independência uns dos outros e, ainda assim, preservar os valores finais das variáveis
geradas pela versão sequencial. [OBS: Você pode reutilizar o código anterior para escrever o
seu, eventualmente riscando ou modificando trechos indesejados ou adicionando novos
trechos e apontando claramente a inclusão feita entre linhas existentes. Você deve manter o
uso de comunicação point-to-point ao invés da coletiva.].

Modelo de arquivo-resposta (Aval1_SeuNome.txt)


Nome completo: Fulano(a) da Silva
Matrícula: 010101010101

1. A. Justificativa: blá blá, blá, blá, blá....


... blá, blá, blá.
2. C. Justificativa: blé, blé, blé, blé, blé, blé...
... blé.
3. ...
4. ...
5. ...
6. ...
7. ...
8. D. Justificativa: blú, blú, blú... blú, blú, blú...,
... blú, blú, blú.
9. ...

OBS: obviamente, as letras assinaladas neste modelo são apenas ilustrativas e não necessariamente
correspondem à alternativa correta da respectiva questão.

Você também pode gostar