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)