Capítulo 1 O CLUSTER Acessando o Cluster O cluster pode ser acessado através de SSH. A partir do *UNIX A maioria dps sistemas unix já oferece um cliente ssh (openssh) na instalação padrão. Caso use uma distribuição GNU/Linux que não tenha o ssh instalado, você poderá instalá-lo com um dos seguintes comandos: apt-get install openssh-client (Debian) yum install openssh-clents (Fedora) slapt-get install openssh (Slackware) Pode ainda baixar o código fonte (http://www.openssh.com) e compilá-lo. Com o cliente ssh instalado basta executar o comando % ssh seu_login@146.164.8.4 A senha de acesso para o usuário é abc123. Pode alterar posteriormente com o comando 'passwd'. A partir do WINDOWS O Windows não dispõe de um cliente ssh por padrão, então recomenda-se o uso do putty 1 para acessar o cluster. Ao abrir o putty basta inserir o IP do cluster: 146.164.8.4 1http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html 1
Figura 1.1: Tela inicial do putty Se for a primeira vez que acessa o cluster, o putty irá pedir conrmação para adicionar a chave remota ao seu arquivo de hosts permitidos. Apenas clique SIM/YES. Figura 1.2: Conrmação da chave 2
Em seguida abrirá a tela de login. Os dados para entrar são: seu_login/abc123 Figura 1.3: Login Com isso o acesso ao cluster estará garantido. Testando PVM (Parallel Virtual Machine) PVM (Parallel Virtual Machine) é um pacote de software que permite uma coleção heterogênea de computadores UNIX e/ou Windows ligados juntos em uma rede sejam usados como um único grande computador paralelo. Além disso, grandes problemas computacionais podem ser resolvidos mais ecientemente usando poder agregado e memória de vários computadores. O software é bastante portável. Acessando Para acessar o ambiente PVM, basta executar o comando % pvm 3
no prompt Figura 1.4: Acesso ao PVM Uma vez dentro do ambiente, pode-se adicionar máquinas (ou nós) que farão parte da máquina virtual: Figura 1.5: Adicionando nós A máquina virtual também pode ser criada passando como parâmetro ao comando pvm um arquivo com os nomes ou IP's das máquinas que irão compor a máquina virtual. 4
Figura 1.6: Criando a máquina virtual na linha de comando Exemplos Existem alguns exemplos no diretório $PVM_ROOT/examples Siga as instruções do arquivo Readme do mesmo diretório para compilar os exemplos. Depois de compilados, os exemplos podem ser executados a partir da linha de comando: Figura 1.7: Executando o exemplo HELLO na linha de comando ou de dentro do ambiente PVM: 5
Figura 1.8: Executando o exemplo HELLO no ambiente paralelo MPICH2 (Message Passing Interface CHamaleon v2) MPICH2 é uma implementação da Message-Passing Interface (MPI). O objetivo do MPICH2 é prover uma implementação MPI para plataformas importantes, incluindo clusters, SMPs 2 e processadores paralelos massivos. Ele também serve como um veículo para pesquisas de implementações MPI e para desenvolvimento de novos e melhores ambientes de programação. O MPICH é controlado por um deamon (mpd) que gerencia toda comunicação entra as máquinas que fazem parte do ambiente virtual. Este deamon precisa de que um arquivo chave seja gerado antes de ser executado. Siga os seguintes passos: 2Simetric Multiprocessor 6
Figura 1.9: Criando o arquivo.mpd.conf Com o arquivo criado, pode-se inicializar o deamon com o comando %mpd & Isso irá inicializar o deamon mpd na máquina local apenas. Para inicializa-lo em uma série de máquinas use: onde: Figura 1.10: Inicializando o mpd em várias máquinas -n especica o número de máquinas a incluir no ambiente virtual. -f especica o arquivo com os nomes das máquinas que podem fazer parte do ambiente virtual. Obs.: o número de máquinas do ambiente virtual tem que ser menor ou igual ao número de máquinas listadas no arquivo ( -f ). Exemplos Existe um programa de exemplo no diretório $MPICH2_ROOT/examples 7
que pode ser executado para testar o ambiente virtual: Onde: Figura 1.11: Executando o exemplo cpi -n expecica o número de processos a serem gerados (menor ou igual ao número de máquinas disponíveis no ambiente virtual). Sun MPI Implementação MPI da Sun. Faz parte do pacote Sun HPC ClusterTools 6, um conjunto de ferramentas que permite aos usuários criarem e customizarem aplicações MPI para serem executadas em cluster e SMPs mpinfo Uma vez dentro do cluster, alguns testes do ambiente paralelo podem ser excutados: Primeiro execute o comando % mpinfo -N 8
Figura 1.12: mpinfo -N A saída desse comando mostra o status atual do cluster. O número de nós, os estados dos nós (ativos ou não), o nome da partição a que eles pertencem, o sistema operacional, o número de CPUs (em cada nó), memória principal disponível, memória swap disponível e a carga. hostname Execute o comando hostname: % mprun -np 0 hostname Figura 1.13: hostname Mais testes No seu diretório home existe um diretório exemplos_mpi. Entre no diretório e execute um dos (ou todos) os programas de exemplo do MPI. 9
Figura 1.14: exemplos MPI Para executar um dos programas basta usar o seguinte comando: % mprun -np 0 nome-do-programa connectivity testa a conectividade entre todos os processos. 10
Algorithm 1 connectivity.c #pragma ident "@(#)connectivity.c 1.3 06/03/06 SMI" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <unistd.h> #include <mpi.h> int main(int argc, char **argv) { MPI_Status status; #include <mpi.h> int main(int argc, char **argv) { MPI_Status status; int verbose = 0; int rank; int np; /* number of processes in job */ int peer; int i; int j; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &np); if (argc>1 && strcmp(argv[1], "-v")==0) verbose = 1; for (i=0; i<np; i++) { if (rank==i) { /* rank i sends to and receives from each higher rank */ for(j=i+1; j<np; j++) { if (verbose) printf("checking connection %4d <-> %-4d\n", i, j); MPI_Send(&rank, 1, MPI_INT, j, rank, MPI_COMM_WORLD); MPI_Recv(&peer, 1, MPI_INT, j, j, MPI_COMM_WORLD, &status); else if (rank>i) { /* receive from and reply to rank i */ MPI_Recv(&peer, 1, MPI_INT, i, i, MPI_COMM_WORLD, &status); MPI_Send(&rank, 1, MPI_INT, i, rank, MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD); if (rank==0) printf("connectivity 11 test on %d processes PASSED.\n", np); MPI_Finalize(); return 0;
monte faz uma estimativa de pi usando o método de monte carlo. Cada processo soma quantos pontos randômicos samplesize gerados no quadrado ( 1, 1), ( 1, 1), (1, 1), (1, 1) caem no círculo de raio 1 e centro (0, 0), depois estima pi usando a fórmula pi = samplesize. 4 sum A estimativa nal de pi é calculada no rank 0 como a média de todas as estimativas. Algorithm 2 monte.f program monte include 'mpif.h' double precision drand external drand double precision x, y, pi, pisum integer*4 ierr, rank, np integer*4 incircle, samplesize parameter(samplesize=2000000) call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, np, ierr)! seed random number generator x = drand(2 + 11*rank) incircle = 0 do i = 1, samplesize x = drand(0)*2.0d0-1.0d0! generate a random point y = drand(0)*2.0d0-1.0d0 if ((x*x + y*y).lt. 1.0d0) then incircle = incircle+1! point is in the circle endif end do pi = 4.0d0 * DBLE(incircle) / DBLE(samplesize)! sum estimates at rank 0 call MPI_REDUCE(pi, pisum, 1, MPI_DOUBLE_PRECISION, MPI_SUM, & 0, MPI_COMM_WORLD, ierr) if (rank.eq. 0) then! final estimate is the average pi = pisum / DBLE(np) print '(A,I4,A,F8.6,A)','Monte-Carlo estimate of pi by ',np, & ' processes is ',pi,'.' endif call MPI_FINALIZE(ierr) end prime retorna se um dado número é primo ou não. 12
Algorithm 3 prime.cc #pragma ident "@(#)prime.cc 1.2 06/03/06 SMI" #include <stdio.h> #include <mpi++.h> #define BUFF_SIZE 10 #define ROOT 0 /* * prototypes */ int primeset(int); /* * main * * Description: Each non-root rank sends a list of numbers to root to * be tested if any lie in the set of prime numbers. Report * the results. */ main(int argc, char **argv) { int rank, size; int list[buff_size]; int i, j; MPI::Status status; MPI::Init(argc, argv); rank = MPI::COMM_WORLD.Get_rank(); size = MPI::COMM_WORLD.Get_size(); if (rank!= ROOT) { /* create list to be tested */ for(i=0; i< BUFF_SIZE; i++) list[i] = rank*10 + i; /* send list to ROOT and report those numbers that are in the prime set */ MPI::COMM_WORLD.Send(list, BUFF_SIZE, MPI::INT, ROOT, 22); MPI::COMM_WORLD.Recv(list, BUFF_SIZE, MPI::INT, ROOT, 22, status); printf("rank %d - prime set:: ", rank); for (i=0; i< BUFF_SIZE; i++) { if (list[i] > 0) printf("%d ",list[i]); printf("\n"); else { /* recieve from non-root ranks, test list, and return modified list */ for(j=0; j< (size-1); j++) { MPI::COMM_WORLD.Recv(list, BUFF_SIZE, MPI::INT, MPI::ANY_SOURCE, MPI::ANY_TAG, status); for(i=0; i< BUFF_SIZE; i++) list[i] = primeset(list[i]); MPI::COMM_WORLD.Send(list, BUFF_SIZE, MPI::INT, status.get_source(), MPI::Finalize(); /* * primeset * status.get_tag()); 13
Execução de exemplo: Figura 1.15: Exemplo de um teste em execução 14