• Nenhum resultado encontrado

Para os modelos de estudos considerados, foram utilizados algoritmos que trabalham com um conjunto de valores padrões, que por meio deles serão inicializados elementos de carga das variáveis para o ambiente de processamento. Esse procedimento se faz necessário devido a uma forma de calibração e medição comparativa dos valores encontrados na execução dos algoritmos.

Normalmente é uma base numérica já desenvolvida por equipes, financiadas por governos ou instituições privadas, que tem a necessidade de precisão nos elementos que serão possíveis produtos no mercado ou técnicas estatísticas de referência.

Como padrão para a execução do cluster, ou seja, colocá-lo em funcionamento, uma calibração das funcionalidades do mesmo se faz necessária. A etapa de teste é referenciada e adotada como um modelo baseado em estrutura de dados, ou seja, um algoritmo personalizado e pré-definido em muitos ambientes existentes.

É comum que muitos projetistas e programadores utilizem cálculos como o do valor de PI, pontos flutuantes e aproximações infinitesimais, como amostra para um uso mais intenso do cluster propriamente desenvolvido.

A simulação da execução desse algoritmo específico é proposta pelas etapas:

a) O algoritmo em linguagem C/MPI – Executado em apenas um PC comum (nó do cluster);

b) O algoritmo em linguagem C/MPI – Executado em todos os nós do cluster; c) O mesmo algoritmo – no servidor apenas;

d) O comparativo das simulações do algoritmo.

A partir dos itens citados acima, consegue-se visualizar a distribuição das funcionalidades do cluster. Diante dos procedimentos de simulação, o primeiro a ser tomado é a execução de um modelo algorítmico fundamental denominado cálculo de PI (BELEZZO, 2014) distribuído por meio do Método de Monte Carlo.

Usando basicamente o algoritmo de ordenação BubbleSort (ANEXO A), adaptado e como modelo, foi realizada a execução de um código em C, usando o compilador GCC e com um padrão de 1.000.000 (um milhão de elementos de um vetor), sendo executado em todos nós do cluster. A ideia inicial é a de gerar uma sobrecarga dos nós do cluster, de forma que o algoritmo gerasse uma espécie de saturação de todos os cores de cada nó, e a partir de então, também distribuísse o processamento pelos demais nós.

O algoritmo foi simulado com base em 04 máquinas com 02 núcleos de processador e em um servidor com 08 (oito) núcleos.

A figura 25 exibe valores comparativos de carga da CPU quando o sistema operacional está estabilizado (sem carga de CPU e memória) em apenas um dos nós.

Figura 25 - Monitoramento gráfico do sistema operacional

Fonte: Dos autores, 2015.

Obter o funcionamento e a organização dos computadores no formato de cluster, como foi realizado no presente trabalho, possibilita a avaliação e estudos relevantes que considerem o hardware utilizado. Validar o funcionamento, de acordo com o comportamento das máquinas, e se nenhum fator de desempenho ou sobrecarga interfira no sistema operacional individual ou coletivo, é essencial nesse momento, para que as rotinas de teste sejam executadas sem que processos do ambiente interfiram no paralelismo da biblioteca MPI no próprio equipamento. É o que se percebe nas simulações seguintes.

A simulação de execução dos arquivos baseia-se em algoritmos simples, que possam atestar o funcionamento do mesmo. Usando basicamente uma adaptação do algoritmo BubbleSort (ANEXO B) como modelo, foi realizada a execução de código em linguagem C, já adaptado para o formato paralelo, tendo em vista uma possível sobrecarga de dados no cluster, para que fosse realmente comprovado a distribuição de processamento entre as estações.

a) Utilizou-se o algoritmo da figura 4 para se comprovar a comunicação de processos em rede das máquinas configuradas;

b) Em seguida o algoritmo de ordenação citado foi executado, sendo carregado para a CPU e memória, e a partir dele, foram coletados os dados observados de tempo, consumo de memória para que, posteriormente, fosse efetuada uma classificação do seu funcionamento. Para tanto, considerou-se para tal o fator de SpeedUP e outros elementos estatísticos para viabilizar o projeto.

É importante salientar que as métricas de avaliação de cluster como SpeedUP, FLOPS, tempo de execução, dentre outras, são fundamentais para verificar a estabilidade do cluster quando submetido com os algoritmos de simulação. Para consideração utilizou-se essencialmente o fator de SpeedUP.

A determinação do tempo de execução de um algoritmo é importante na avaliação de quanto o seu desempenho interfere efetivamente no consumo de máquinas. O fato de um algoritmo resolver um dado problema não significa que seja aceitável na prática. O tempo de execução não depende somente do algoritmo, mas do conjunto de instruções do computador, da qualidade do compilador de linguagem e a habilidade do programador (PATTERSON, 2014).

Para o estudo considerado obtém-se uma medida independente do tratamento dado ao problema ou dos procedimentos executados para sua solução, que dependerá exclusivamente do seu SpeedUP.

Sabe-se que é possível avaliar o desempenho de programas paralelos considerando as variáveis: tempo de execução, eficiência, escalabilidade, requisitos de memória, custos, desenvolvimento e implementação, consumo da rede, portabilidade e outros (PATTERSON, 2014).

Basicamente, a avaliação dos dados coletados adiante permite testar o desempenho de uma aplicação paralela com base nos tempos de comparação entre a execução com processadores múltiplos e a execução com apenas um processador.

Tem-se a seguir (figura 26), o comparativo na determinação do tempo de execução do algoritmo com 20 (vinte) processos sendo executados com 10 (dez) repetições. A seguir, foram avaliados os algoritmos Hello, BubbleSort (figura 27) e PI distribuído (ANEXO A). São realizadas chamadas de processos para que o sistema operacional possa gerar, por meio das SystemCalls, a duração total do tempo da execução.

Figura 26 - Gráfico comparativo da Comunicação entre Processos

Fonte: Dos autores, 2015.

Figura 27 - Tempo de execução do Algoritmo Adaptado - BubbleMerge

Fonte: Dos autores, 2015.

De forma breve, foi testado uma variante do algoritmo BubbleSort para realizar um teste de desempenho no cluster. Pode-se observar na figura acima (figura 27) a variação do tempo de execução e considerar a diferença no tempo de cálculo realizado.

Para tal, podem ser utilizadas ferramentas de software que determinam o perfil da execução ou usando um simulador da arquitetura. Ao comparar dois ou mais computadores é necessário verificar como se combinam para formar o tempo de execução (PATTERSON, 2014). Além disso, é necessário que o algoritmo seja adequado para o hardware paralelo. O programador precisa dividir uma aplicação de modo que cada processador tenha aproximadamente a mesma quantidade de coisas a fazer ao mesmo tempo, e que a sobrecarga do escalonamento e coordenação entre processos não afaste o benefício de desempenho do

paralelismo. Por isso, em muitas situações é necessário observar a Lei de Amdhal para demonstrar limites práticos do número de processadores paralelos (PATTERSON, 2014).

Observa-se também a determinação do tempo de execução do algoritmo com 04 (quatro) processos sendo executados com 09 (nove) repetições. Foram realizados comparativos com tempos coletados em apenas um dos nós (estação única) e no cluster (figura 28). Percebe-se a evolução em relação à queda do tempo diretamente pelas três medidas entre o melhor tempo, tempo médio e o pior caso.

Figura 28 – Avaliação de Métricas entre o nó estação e o cluster

Fonte: Dos autores, 2015.

Uma vez com os elementos coletados pela forma de um nó, e em seguida pelo cluster, a proposta seguinte foi a de combinar, por meio de uma relação de fatores, o SpeedUP e realizar a divisão entre os dois agrupamentos numéricos que foram obtidos na prática.

A representação visual do SpeedUP no momento que ele é recalculado no padrão de todos os nós (vide figura 28), confirma, com base nos valores encontrados, o desempenho do cluster e o seu ganho de velocidade, quando os algoritmos estão em execução. Observa-se que a relação entre o crescimento do número de pontos, e a própria convergência do SpeedUP, direciona para um valor médio de SpeedUP = 27,69 ≈ 28 vezes maior.

A submissão do algoritmo para comparação direta dos valores obtidos está vinculada pelos números de pontos (figura 28), e seus respectivos tempos de uso pelo processador (processos CPU-bound). Na mesma figura, de forma complementar, também foi acrescido um

teste com um bilhão de pontos, simplesmente como verificação da saturação dos núcleos de processadores que foram executados. Percebe-se claramente a diferença exponencial do crescimento em relação ao tempo de consumo dos processos (figura 29) e, somente após a execução de número 6 (seis), observa-se que a concorrência entre as chamadas são intensificadas.

Figura 29 - Gráfico comparativo entre o nó estação e o cluster

Fonte: Dos autores, 2015.

Após a tabulação dos dados levantados e coletados, e por meio da visualização de gráficos, foi possível comprovar usando a métrica de cálculo do SpeedUP (ganho de velocidade), que realmente o cluster montado e configurado fisicamente está efetivamente tratando os dados com uniformidade de comunicação entre os processos que são executados por meio dos algoritmos. Nota-se que o SpeedUP foi superlinear (Sp ≥ 1) em todos os pontos, e em execuções de pontos equivalentes. Condição de que o paralelismo está ocorrendo e convergindo para o processamento de menor tempo. Não somente com o Sp, mas ao longo de todas as simulações e testes do cluster, foram observados elementos estatísticos que poderiam dar margem a outros desdobramentos, como o cálculo de integrais e de aproximações numéricas.

A margem de acerto e ajustes entre os diferentes testes e simulações realmente demonstram o quanto o paralelismo do cluster o torna eficaz e uma ferramenta prática para estudo das mais diversas áreas em sistemas distribuídos.

5 CONCLUSÃO

A ideia de se construir o cluster é a possibilidade de constatar alguns pontos que comprovam a teoria estudada, dentre eles: a funcionalidade do cluster de balanceamento de carga, cluster de alta disponibilidade e alto desempenho de computação e a validação de que a tecnologia de cluster computacional pode ser vista como uma otimização dos recursos das redes de computadores. O estudo dos algoritmos implementados e simulados confirma o ganho de desempenho pelo SpeedUP em relação as comparações realizadas. Logo, obteve-se o cluster construído e funcionando.

A viabilidade foi confirmada e efetuada por meio da métrica de ganho de velocidade (SpeedUP). Foram simulados os algoritmos PI distribuído e BubbleMerge (variante do BubbleSort) e analisados tempos de processamento e comunicação entre as máquinas. Assim, demonstrou-se o funcionamento estável do cluster físico e lógico, além de suas diferentes interfaces de manipulação e utilização.

A transferência de informações entre os nós (servidor e estações) foi observada e demonstrada pelas telas específicas das aplicações que eram simuladas.

Todos esses itens foram sintetizados e compilados de forma prática, culminando na elaboração de um Manual Prático de Configuração de Cluster, sem que perdesse a essência teórica e ficasse relegada a mera sequência de etapas. Além do que, o próprio cluster está disponível para utilização do meio acadêmico em suas características de desempenho e execução de testes.

Estudos futuros podem ser concentrados em análise de desempenho do cluster, na execução de algoritmos em modelos de processamento gráfico CUDA (GPU) e CPU, comportamento de algoritmos de precisão numérica, dentre outros, inclusive com estudos de caracterizações no desdobramento de processos CPU-bound e IO-bound permitindo uma análise mais específica de que tipo de cluster pode ser projetado.

REFERÊNCIAS

ALECRIM, E. Diferenças entre hub, switch e roteador. [S.l.]: InfoWester, 2004.

Disponível em: <http://www.infowester.com/hubswitchrouter.php>. Acesso em: 18 jun. 2015. ASSOCIAÇÃO BRASILEIRA DOS USUÁRIOS DE ACESSO RÁPIDO. Hub e switch -

Quais as diferenças? [S.l.], [200-]. Disponível em:

http://www.abusar.org/hub_e_switch.html. Acesso em: 18 jun. 2015.

ALECRIM, E. Cluster: principais conceitos. [S.l.]: InfoWester, 2004. Disponível em: <http://www.infowester.com/printversion/cluster.php>. Acesso em: 23 fev. 2014.

BELEZZO, M. Desenvolvimento de um software de Monte Carlo para transporte de

fótons em estruturas de Voxels usando unidades de processamento gráfico. 2014. 84 f.

Dissertação (Mestrado em Ciências) -- Instituto de Pesquisas Energéticas e Nucleares, São Paulo, 2014. Disponível em:

<http://www.iaea.org/inis/collection/NCLCollectionStore/_Public/45/089/45089718.pdf>. Acesso em: 18 jun. 2015.

CANGIANO, A. S. B.; SANTOS, L. G. L. dos. Grid computing - elucidando os conceitos.

Tema, Brasília, v. 9, n. 79, 2005. Disponível em:

<http://www4.serpro.gov.br/imprensa/publicacoes/tema-1/tematec/2005/ttec79>. Acesso em: 23 jul. 2015.

COMER, D. Internetworking with TCP/IP: principles, protocols, and architecture. New Jersey: Prentice Hall, 2000. v. 1.

COULOURIS, G. at al. Sistemas distribuídos: conceitos e projeto. 5. ed. Porto Alegre: Bookman, 2013.

DANTAS, M. A. R. Tecnologias de redes de comunicação e computadores 5. ed. Rio de Janeiro: Axcel Books, 2002.

DEBIAN. Contrato social Debian. [S.l.], 2004. Acesso em: 29 jul. 2015.Disponível em: <http://www.debian.org/social_contract>. Acesso em: 18 jun. 2015.

FERREIRA, R. E. Linux: guia do administrador do sistema. São Paulo: Novatec, 2003. FUGI, Danilo Mezanotti. Algoritmo BubbleMarge.c:padrão distribuído. Programa de computador.

FREEBSD DOCUMENTATION. Uso avançado de redes. In: ______.

FreeBSDHandbook. [S.l.], 2003. cap. 19. Disponível em: <

http://www.openit.com.br/freebsd-hb/network-nfs.html>. Acesso em: 11 ago. 2014.

GNU. O Sistema operacional GNU. Tradução: Leandro Guimarães Faria Corcete Dutra . [S.l.]: Free Software Foundation, 2014. Disponível em: <

LAM/MPI parallel computing. Disponível em: <http://www.lam-mpi.org/US>. Acesso em: 12 ago. 2014.

LINUX On-Line. Disponível em: <http://www.linux.org/info/index.html>. Acesso em: 12 ago. 2014.

LINUX Virtual Server Project. Disponível em: <http://www.linuxvirtualserver.org>. Acesso em: 12 ago. 2014.

MESSAGE PASSING INTERFACE FORUM, 2015, Tennessee. MPI: a message-passing interface standard: version 3.1. Tennessee: University of Tennessee, 2015. Disponível em: <http://www.mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf>. Acesso em: 13 jan. 2014. MPICH. Message passing interface chamaleon. [S.l.], Disponível em: 2015

<http://www.mpich.org>. Acesso em: 23 jul. 2015.

PATTERSON, D.A; HENESSY, J.L. Organização e Projeto de Computadores: A interface hardware/software. 4. ed. Rio de Janeiro: Campus 2014.

PITANGA, M. Construindo supercomputadores com Linux. 3. ed. Rio de Janeiro: Brasport, 2008.

POSIX, Threads. Disponível em:

<http://www.yolinux.com/TUTORIALS/LinuxTutorial/PosixThreads.html>. Acesso em: 22 jul. 2015.

RIBEIRO, U. E. Sistemas distribuídos: desenvolvendo aplicações de alta performance no linux. Rio de Janeiro: Axcel, 2004.

STALLINGS, W. Arquitetura e organização de computadores. São Paulo: Prentice Hall, 2002.

TANENBAUM, A. Sistemas distribuídos: princípios e paradigmas. 2. ed. Rio de Janeiro: Pearson, 2013.

APÊNDICE A – Hardware padrão CUDA – Fabricação: NVídia

A figura trinta (30) representa uma placa com recurso CUDA.

Figura 30 – Placa QUADRO com recurso CUDA

Fonte: NVIDIA, 2015.

“Com o aparecimento das bibliotecas de programação gráfica OPENGL e DIRECTX em meados da década de 90, os fabricante de GPUs tiveram a oportunidade de adicionar às suas capacidades programáveis, ou seja, estruturas de hardware onde cada pixel poderia ser processado em um pequeno programa e poderia incluir texturas como sua entrada.

O crescimento da comunidade de programação paralela baseada em GPUs cresceu muito nos últimos anos. Existe imensa produção científica e o ganho em performance, em alguns casos, supera em mais de duas ordens de grandeza o desempenho de uma CPU tradicional.

A estrutura de desenvolvimento do CUDA distribuída pela NVIDIA consiste basicamente de um driver em uma camada de baixo nível para acesso aos dispositivos de hardware, uma biblioteca de runtime e duas outras bibliotecas de alto nível que fornecem funções em álgebra linear e FFT (Fast Fourier Transform).

A programação de uma GPU utilizando o CUDA é orientada à threads, ou linhas de execução, que é uma forma de um processo dividir a si mesmo em duas ou até mesmo centenas de tarefas, que podem ser executadas simultaneamente. Devido ao seu custo de aquisição, o desenvolvimento dentro desse paradigma ficou fora do escopo desse trabalho.” (PATTERSON, 2014)

APÊNDICE B – Placa mãe do Servidor

A figura 31 traz um exemplo da placa mãe do computador mestre. Figura 31 – Placa mãe do computador mestre

APÊNDICE C – Placa mãe dos Clientes

A figura 32 fornece o modelo de placa mãe dos computadores estações do cluster.

Figura 32 – Placa mãe dos computadores estações

ANEXO A – Algoritmos Utilizados

- Algoritmo BubbleMergei.c – Padrão Distribuído

Algoritmo cedido pelo aluno DANILO MENZANOTI FUGI do IFSMG para simulação do Cluster.

#include <stdio.h> #include <mpi.h> #include <time.h> #define N 1000000

void mostraVetor(int *v, int n);

int * merge(int *v1, int n1, int *v2, int n2); void troca(int *v, int i, int j);

void sort(int *v, int n); int partition( int *a, int l, int r); void quickSort( int *a, int l, int r); double startT,stopT;

double startTime;

void mostraVetor(int *v, int n) { int i; printf("Vetor \n"); for(i=0; i<n;i++) printf("%d \n",v[i]); printf("fim vetor\n"); }

void mostraVetorOrdem(int *v, int n) { int i; int cot=0; printf("\n\nVetor Ordenado\n"); for(i=0; i<n;i++){ printf("%d \n",v[i]); cot++; }

printf("fim vetor\n numero: %d",cot); }

int * merge(int *v1, int n1, int *v2, int n2) {

int i,j,k; int * result;

result = (int *)malloc((n1+n2)*sizeof(int));

i=0; j=0; k=0; while(i<n1 && j<n2) if(v1[i]<v2[j]) { result[k] = v1[i]; i++; k++; } else { result[k] = v2[j]; j++; k++; } if(i==n1) while(j<n2) { result[k] = v2[j]; j++; k++; } else while(i<n1) { result[k] = v1[i]; i++; k++; } return result; }

void troca(int *v, int i, int j) { int t; t = v[i]; v[i] = v[j]; v[j] = t; }

void sort(int *v, int n) { int i,j; for(i=n-2;i>=0;i--) for(j=0;j<=i;j++) if(v[j]>v[j+1]) troca(v,j,j+1); }

void quickSort( int *a, int l, int r) { int j; if( l < r ) { j = partition( a, l, r); quickSort( a, l, j-1); quickSort( a, j+1, r); } }

int partition( int *a, int l, int r) { int pivot, i, j, t;

pivot = a[l]; i = l; j = r+1;

while( 1) {

t = a[i]; a[i] = a[j]; a[j] = t; }

t = a[l]; a[l] = a[j]; a[j] = t;

return j; }

main(int argc, char **argv) { int * dados; int * pedaco; int * outros; int m,n=N; int id,p; int s; int i; int step; MPI_Status status; //Inicializa os processos. MPI_Init(&argc,&argv);

//determina o rank de um processo

MPI_Comm_rank(MPI_COMM_WORLD,&id); //determina o numero de processos executando MPI_Comm_size(MPI_COMM_WORLD,&p); //mostra dados //printf("id: %d ",id); //printf("p: %d \n",p); if(id==0) { int r; srandom(clock()); s = n/p; r = n%p;

// printf("Tamanho das partes do Vetor %d",s); // printf("Divisão com resto igual a : %d \n",r);

dados = (int *)malloc((n+p-r)*sizeof(int)); for(i=0;i<n;i++) dados[i] = random(); if(r!=0) { for(i=n;i<n+p-r;i++) dados[i]=0; s=s+1; } //MOSTRA VETOR //mostraVetor(dados,n); startT = clock(); MPI_Bcast(&s,1,MPI_INT,0,MPI_COMM_WORLD );

pedaco = (int *)malloc(s*sizeof(int));

MPI_Scatter(dados,s,MPI_INT,pedaco,s,MPI_INT, 0,MPI_COMM_WORLD); sort(pedaco,s); //quickSort( pedaco, 0, s) } MPI_Bcast(&s,1,MPI_INT,0,MPI_COMM_WORLD );

pedaco = (int *)malloc(s*sizeof(int));

MPI_Scatter(dados,s,MPI_INT,pedaco,s,MPI_INT, 0,MPI_COMM_WORLD); sort(pedaco,s); //quickSort( pedaco, 0, s) } step = 1; while(step<p) { if(id%(2*step)==0) { if(id+step<p) { MPI_Recv(&m,1,MPI_INT,id+step,0,MPI_COMM_ WORLD,&status); outros = (int *)malloc(m*sizeof(int)); MPI_Recv(outros,m,MPI_INT,id+step,0,MPI_COM M_WORLD,&status); pedaco = merge(pedaco,s,outros,m); s = s+m; } } else {

int near = id-step;

MPI_Send(&s,1,MPI_INT,near,0,MPI_COMM_WO RLD); MPI_Send(pedaco,s,MPI_INT,near,0,MPI_COMM _WORLD); break; } step = step*2; } if(id==0) { // parar relógio stopT = clock(); // mostraVetor(dados,n); // mostraVetorOrdem(pedaco,s); printf("\n\nRESULTADOS\n\n"); printf("Numeros a ordenar: %d; %d processadores \nPronto em %f segundos\n",N,p,(stopT- startT)/CLOCKS_PER_SEC);

}

MPI_Finalize();

}

- Algoritmo Cálculo de PI – Padrão distribuído

#include <stdlib.h>

#include "mpi.h"

#define SERVER (n_procs - 1) #define ROOT 0

#define REQ_POINTS 1000 #define REQUEST 0 #define REPLY 1 main(int argc, char **argv) {

MPI_Group world_group, worker_group; MPI_Comm workers_comm;

MPI_Status status; int my_rank, n_procs; double start, finish, x, y;

int in, out, total_in, total_out, total_points, i, rands[REQ_POINTS], req_points, ranks[1]; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &n_procs); if (n_procs == 1) { MPI_Finalize(); if (my_rank == 0)

printf("Qde. Mínima de processos 2: !\n"); exit(0);

}

// Define um novo comunicador para os clientes MPI_Comm_group(MPI_COMM_WORLD, &world_group); ranks[0] = SERVER; MPI_Group_excl(world_group, 1, ranks, &worker_group); MPI_Comm_create(MPI_COMM_WORLD, worker_group, &workers_comm); MPI_Group_free(&worker_group); MPI_Group_free(&world_group);

// Obtém o número de pontos e propaga a todos if (my_rank == ROOT) {

printf("Indique o total de pontos: "); scanf("%d", &total_points);

}

MPI_Bcast(&total_points, 1, MPI_INT, ROOT, MPI_COMM_WORLD);

// inicia contagem do tempo

MPI_Barrier(MPI_COMM_WORLD); start = MPI_Wtime();

// Calcula o valor aproximado de PI

if (my_rank == SERVER) { // MESTRE do {

MPI_Recv(&req_points, 1, MPI_INT, MPI_ANY_SOURCE, REQUEST, MPI_COMM_WORLD, &status); if (req_points) {

for (i = 0; i < req_points; i++) rands[i] = random();

MPI_Send(rands, req_points, MPI_INT, status.MPI_SOURCE, REPLY, MPI_COMM_WORLD); } } while (req_points); } else { // ESCRAVOS in = out = 0; do { req_points = REQ_POINTS; MPI_Send(&req_points, 1, MPI_INT, SERVER, REQUEST, MPI_COMM_WORLD); MPI_Recv(rands, req_points, MPI_INT, SERVER, REPLY, MPI_COMM_WORLD, &status);

for (i = 0; i < req_points; i += 2) {

x = (((double) rands[i]) / RAND_MAX) * 2 - 1;

y = (((double) rands[i+1]) / RAND_MAX) * 2 - 1;

(x * x + y * y < 1.0) ? in++ : out++; }

MPI_Allreduce(&in, &total_in, 1, MPI_INT, MPI_SUM, workers_comm);

MPI_Allreduce(&out, &total_out, 1, MPI_INT, MPI_SUM, workers_comm);

req_points = (total_in + total_out < total_points);

if (req_points == 0 && my_rank == ROOT) MPI_Send(&req_points, 1, MPI_INT, SERVER, REQUEST, MPI_COMM_WORLD); } while (req_points);

MPI_Comm_free(&workers_comm); }

// Fecha contagem do tempo e mostra resultado MPI_Barrier(MPI_COMM_WORLD);

finish = MPI_Wtime(); if (my_rank == ROOT) {

printf("PI = %.20f\n", (4.0 * total_in) / (total_in + total_out));

printf("Tempo de Execução = %f segundos\n", finish - start);

}

MPI_Finalize(); }

- Algoritmo Tempo de Execução – Modelo distribuído

#include "mpi.h"

main(int argc, char **argv) { int my_rank, n_procs; double start, finish; MPI_Init(&argc, &argv);

MPI_Barrier(MPI_COMM_WORLD); start = MPI_Wtime();

// parte da execução a medir

MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &n_procs); MPI_Barrier(MPI_COMM_WORLD);

finish = MPI_Wtime(); if (my_rank == 0)

printf("Tempo de Execução: %f segundos\n", finish - start); MPI_Finalize();

}

- Coleta de dados da execução do algoritmo PI distribuído-apenas um nó

- Coleta de dados da execução do algoritmo PI distribuído -Todos os nós

ANEXO B – Especificações do Comutador (Switch-Gigabit)

Documentos relacionados