Um cluster HPC com PVM

O PVM (Paralel Virtual Machine – Máquina Paralela Virtual) é uma biblioteca de passagem de mensagens amplamente usada em soluções de processamento de alto desempenho.

Originalmente criado no final da década de 80 o PVM tem uma filosofia bastante interessante, pois visa principalmente o funcionamento em ambientes heterogêneos, afinal, ela foi criada pelo Heterogeneous Network Project. Com isso, é possível usar essa biblioteca interagindo entre diversos sistemas unix, OS/2, e ambientes menos usuais em clusters como máquinas com Windows NT, 2000 ou XP.

Os procedimentos descritos neste documento funcionam corretamente em ambientes que suportam pacotes RPM, mas pode ser realizado em qualquer “sabor” de GNU/Linux, com exceção no que diz respeito à instalação de pacotes. Caso seu sistema não suporte pacotes RPM não desista! O procedimento para instalação do PVM está muito bem descrito no arquivo README que acompanha o código fonte do PVM. O código fonte pode ser encontrado aqui: http://www.netlib.org/pvm3/

Para utilização proveitosa deste pacote, são necessários pelo menos dois computadores conectados à rede, ambos com protocolo TCP/IP em perfeito funcionamento.

É interessante que a rede possua uma tecnologia moderna, que possa oferecer a maior largura de banda possível, sendo que o PVM também funcionará perfeitamente numa rede lenta. Mas tome cuidado com isso, redes muito lentas podem afetar drasticamente o desempenho do processamento, tornando a obtenção de resultados inferior ao desempenho de máquinas com processamento local.

Instalação

Para instalar o PVM devemos usar os seguintes pacotes:

pvm-3.4.3-28.i386.rpm
pvm-gui-3.4.3-28.i386.rpm

O primeiro pacote consiste na biblioteca de troca de mensagens, o daemon PVM, alguns utilitários, programas de testes e outros. O segundo é a interface gráfica em TCL/TK, que proporciona ao usuário controle total sobre a máquina virtual paralela.

Instale o pacote pvm-3.4.3-28.i386.rpm:

[root@localhost RPMS]# rpm -ivh pvm-3.4.3-28.i386.rpm
Preparing...                ########################################### [100%]
  1:pvm                    ########################################### [100%]

Instale o pacote pvm-gui-3.4.3-28.i386.rpm:

[root@localhost RPMS]# rpm -ivh pvm-gui-3.4.3-28.i386.rpm
Preparing...                ########################################### [100%]
  1: pvm-gui               ########################################### [100%]

Configuração

Será necessário habilitar alguns serviços no sistema, talvez isso implicará em instalar adicionalmente o pacote xinetd.

Raramente uma instalação do GNU/Linux não possui os serviços do xinetd, caso sua instalação não possua este pacote, certamente ele poderá ser encontrado no CDROM de sua distribuição.

Configuração dos pré-requisitos

Os pré-requisitos devem ser configurados corretamente, pois são fundamentais para operação básica da máquina virtual paralela, sem eles não será possível adicionar máquinas ao PVM, e então o cluster só existirá fisicamente.

Os daemons

Configure os serviços rexec, rlogin, rsh para iniciarem automaticamente durante a iniciação do sistema. Para tanto será necessário iniciar também o daemon xinetd. Proceda da seguinte forma:

[root@localhost root]# ntsysv

A seguinte tela será exibida, então basta selecionar os serviços especificados.

Tela do utilitário ntsysv

Com isso, basta reiniciar o daemon xinetd com o comando:

[root@localhost root]# cd /etc/rc.d/init.d
[root@localhost init.d]# ./xinetd restart
Stopping xinetd:                                           [  OK  ]
Starting xinetd:                                           [  OK  ]

Contas de usuários

Todas as máquinas que fazem parte da máquina virtual devem possuir contas de usuários (do cluster) em comum, ou seja, se o usuário frango quiser usar o cluster PVM, ele deverá ter uma conta em cada máquina com o nome frango, e é ainda melhor se o uid do usuário frango for igual em todas as estações.

Em princípio, num cluster grande, isso pode parecer impossível de administrar, mas pode ser facilmente concebido com o auxilio de alguma ferramenta como NIS.

Configurando as variáveis de ambiente

É necessário, que a instalação em todos os hosts seja feita de forma igual, ou seja, os diretórios de instalação do PVM em todas os hosts devem ser iguais.

Com isso é necessário configurar algumas variáveis de ambiente em todos os hosts. Essas variáveis devem estar presentes no arquivo .bash_profile de cada conta de usuário que usará o cluster, ou no arquivo /etc/bashrc.

Adicione no final do arquivo mencionado as seguintes linhas:

# Variaveis de ambiente do PVM
export PVM_ROOT=/usr/share/pvm3
export PVM_TMP=/tmpexport PVM_ARCH=LINUX
export PATH=$PATH:$PVM_ROOT/lib:$PVM_ROOT/lib/$PVM_ARCH
export PATH=$PATH:$PVM_ROOT/bin/$PVM_ARCH
export PVM_DPATH=$PVM_ROOT/lib/pvmd

Para saber mais sobre essas variáveis de ambiente veja a página de manual do PVM, para tanto use o seguinte comando:

[root@localhost root]# man pvm_intro

O PVM possui as seguintes paginas de manual:

pvm             Informações sobre o uso do PVM e seus comandos.
aimk        Wrapper para portar aplicações para serem executadas em diversas estações.
pvmd3        Daemon que provê comunicação e controle de processos entre as estações.
pvm_intro    Documento com funcionalidades e variáveis de ambiente.

Configuração do PVM

Após realizar o procedimento descrito acima em todas as estações que farão parte do cluster PVM, configuraremos a máquina virtual. Essas configurações devem ficar na estação que será usada como Front-End, ou então em todas as máquinas que dispararão processos.

Vamos agora aprender sobre algumas funções, e comandos básicos do PVM.

Para incluir as estações à máquina virtual PVM manualmente, deve-se usar o comando add, da seguinte forma:

[root@localhost root]# pvm
pvm> add machine2
add machine2
1 successful
                   HOST     DTID
               machine2    80000

Dessa forma o host machine2 foi incluído manualmente à máquina virtual PVM.

Ainda é possível fazer a inclusão automática de hosts, para tanto, existem duas maneiras.

A primeira solução consiste em editar um arquivo texto simples, com os nomes das estações que fazem parte do cluster PVM, cada um em uma linha, dessa forma:

machine1
machine2
machine3

Esse arquivo pode ter um nome qualquer… Tendo como exemplo o arquivo hosts.pvm, podemos iniciar o PVM e adicionar os hosts simultaneamente dessa forma:

[root@localhost root]# pvm hosts.pvm

A outra maneira não menos útil, é passar em forma de comandos PVM a adição de hosts.

Criaremos um script, com o seguinte conteúdo:

#!/bin/bash

echo "add machine1 machine2 machine3"|pvm

Então para executá-lo, basta dar permissão de execução e mandar ver!

[root@localhost root]# chmod 777 hosts.pvm.sh
[root@localhost root]# ./hosts.pvm.sh
pvm> add machine1 machine2 machine3
3 successful
                   HOST     DTID
               machine1    80000
               machine2    c0000
               machine3   100000
pvm> quit

Console: exit handler called
pvmd still running.

Esse recurso é útil na criação de scripts para automatizar o processo de inclusão de máquinas.

Recomendo fortemente que seja feito um script para incluir oshosts à máquina virtual paralela, unicamente para não ter muito trabalho…

Testes

O PVM possui alguns arquivos de exemplo que podem ser usados para fins de teste, e podem encontrados no diretório /usr/share/pvm3/examples. Neste mesmo diretório existe um arquivo chamado Readme, este arquivo possui a descrição e como devem ser compilados os programas de exemplo.

Seguindo a descrição do arquivo Readme, para compilar o programa de número 4 devemos usar o seguinte procedimento:

Compilando:

[user@localhostexamples]$ aimk dbwtest ibwtest pbwtest rbwtest
making in LINUX/ for LINUX
make: `dbwtest' is up to date.
cc -g -I../../include -DSYSVSIGNAL -DNOWAIT3
-DRSHCOMMAND=\"/usr/bin/rsh\" -DNEEDENDIAN -DFDSETNOTSTRUCT
-DHASERRORVARS -DCTIMEISTIMET -DSYSERRISCONST -DPACK
-DENCODE=PvmDataInPlace -o ibwtest \ ../../examples/bwtest.c
-L../../lib/LINUX -lgpvm3 -lpvm3 ../../lib/LINUX/libpvm3.a(lpvm.o): In
function `pvm_tc_conreq':
lpvm.o(.text+0x897): the use of `tmpnam' is dangerous, better use
`mkstemp'
mv ibwtest ../../bin/LINUX
cc -g -I../../include -DSYSVSIGNAL -DNOWAIT3
-DRSHCOMMAND=\"/usr/bin/rsh\" -DNEEDENDIAN -DFDSETNOTSTRUCT
-DHASERRORVARS -DCTIMEISTIMET -DSYSERRISCONST -o pbwtest
../../examples/bwtest.c -L../../lib/LINUX -lgpvm3 -lpvm3
../../lib/LINUX/libpvm3.a(lpvm.o): In function `pvm_tc_conreq':
lpvm.o(.text+0x897): the use of `tmpnam' is dangerous, better use
`mkstemp'
mv pbwtest ../../bin/LINUX
cc -g -I../../include -DSYSVSIGNAL -DNOWAIT3
-DRSHCOMMAND=\"/usr/bin/rsh\" -DNEEDENDIAN -DFDSETNOTSTRUCT
-DHASERRORVARS -DCTIMEISTIMET -DSYSERRISCONST -DPACK
-DENCODE=PvmDataRaw -o rbwtest \ ../../examples/bwtest.c
-L../../lib/LINUX -lgpvm3 -lpvm3 ../../lib/LINUX/libpvm3.a(lpvm.o): In
function `pvm_tc_conreq':
lpvm.o(.text+0x897): the use of `tmpnam' is dangerous, better use
`mkstemp'
mv rbwtest ../../bin/LINUX

Executando:

[user@localhost examples]$ cd /usr/share/pvm3/bin/LINUX
[user@localhost LINUX]$ pvm
pvmd already running.
pvm> conf
conf
5 hosts, 1 data format
                   HOST     DTID     ARCH   SPEED       DSIG
             dhoris.lc3    40000    LINUX    1000 0x00408841
             mibzar.lc3    c0000    LINUX    1000 0x00408841
              zaabe.lc3   100000    LINUX    1000 0x00408841
              gosen.lc3   140000    LINUX    1000 0x00408841
              timna.lc3   180000    LINUX    1000 0x00408841
pvm> spawn -6 -> dbwtest
spawn -6 -> dbwtest
[1]
6 successful
t14000a
t14000b
t180006
t4000c
tc0008
t10000a
pvm> [1:t180006]  180006 myinst is 1
[1:t180006] 180006 -- I am the slave
[1:t180006] t180006: 100000 doubles received correctly
[1:t180006]
[1:t180006]
[1:t180006] EOF
[1:t4000c]  4000c myinst is 0
[1:t4000c] --- Simple PVM Bandwidth Test ----
[1:t4000c]  Using pack option: PvmDataDefault
[1:t4000c]  Max data size is: 800000
[1:t4000c]  Number of iterations/sample: 20
[1:t4000c]
[1:t4000c]
[1:t4000c]  Roundtrip time is measured from user-space to user-space.
[1:t4000c]  For packed messages this includes the combined time of:
[1:t4000c]     inst 0: pvm_initsend()
[1:t4000c]     inst 0: pvm_pack()
[1:t4000c]     inst 0: pvm_send()
[1:t4000c]     inst 1: pvm_recv()
[1:t4000c]     inst 1: pvm_unpack()
[1:t4000c]     inst 1: pvm_initsend()
[1:t4000c]     inst 1: pvm_pack()
[1:t4000c]     inst 1: pvm_send()
[1:t4000c]     inst 0: pvm_recv()
[1:t4000c]     inst 0: pvm_unpack()
[1:t4000c]
[1:t4000c]
[1:t4000c] ---------------------------------------
[1:t4000c] 4000c -- I am the master
[1:t4000c] t4000c: 100000 doubles received correctly
[1:t4000c]
[1:t4000c]
[1:t4000c] Roundtrip T = 1796 (us)  (0.0000 MB/s)  Data size: 0
[1:t4000c] Roundtrip T = 1670 (us)  (0.0096 MB/s)  Data size: 8
[1:t4000c] Roundtrip T = 1738 (us)  (0.0921 MB/s)  Data size: 80
[1:t4000c] Roundtrip T = 2348 (us)  (0.6814 MB/s)  Data size: 800
[1:t4000c] Roundtrip T = 9068 (us)  (1.7644 MB/s)  Data size: 8000
[1:t4000c] Roundtrip T = 79137 (us)  (2.0218 MB/s)  Data size: 80000
[1:t4000c] Roundtrip T = 812905 (us)  (1.9682 MB/s)  Data size: 800000
[1:t4000c] EOF
[1:t14000b]  14000b myinst is 5
[1:t14000b] 14000b -- I am the slave
[1:t14000b] t14000b: 100000 doubles received correctly
[1:t14000b]
[1:t14000b]
[1:t14000b] EOF
[1:t14000a]  14000a myinst is 4
[1:t14000a] --- Simple PVM Bandwidth Test ----
[1:t14000a]  Using pack option: PvmDataDefault
[1:t14000a]  Max data size is: 800000
[1:t14000a]  Number of iterations/sample: 20
[1:t14000a]
[1:t14000a]
[1:t14000a]  Roundtrip time is measured from user-space to user-space.
[1:t14000a]  For packed messages this includes the combined time of:
[1:t14000a]     inst 0: pvm_initsend()
[1:t14000a]     inst 0: pvm_pack()
[1:t14000a]     inst 0: pvm_send()
[1:t14000a]     inst 1: pvm_recv()
[1:t14000a]     inst 1: pvm_unpack()
[1:t14000a]     inst 1: pvm_initsend()
[1:t14000a]     inst 1: pvm_pack()
[1:t14000a]     inst 1: pvm_send()
[1:t14000a]     inst 0: pvm_recv()
[1:t14000a]     inst 0: pvm_unpack()
[1:t14000a]
[1:t14000a]
[1:t14000a] ---------------------------------------
[1:t14000a] 14000a -- I am the master
[1:t14000a] t14000a: 100000 doubles received correctly
[1:t14000a]
[1:t14000a]
[1:t14000a] Roundtrip T = 1735 (us)  (0.0000 MB/s)  Data size: 0
[1:t14000a] Roundtrip T = 1389 (us)  (0.0115 MB/s)  Data size: 8
[1:t14000a] Roundtrip T = 1439 (us)  (0.1112 MB/s)  Data size: 80
[1:t14000a] Roundtrip T = 2081 (us)  (0.7689 MB/s)  Data size: 800
[1:t14000a] Roundtrip T = 9523 (us)  (1.6801 MB/s)  Data size: 8000
[1:t14000a] Roundtrip T = 94683 (us)  (1.6898 MB/s)  Data size: 80000
[1:t14000a] Roundtrip T = 967457 (us)  (1.6538 MB/s)  Data size: 800000
[1:t14000a] EOF
[1:tc0008]  c0008 myinst is 3
[1:tc0008] c0008 -- I am the slave
[1:tc0008] tc0008: 100000 doubles received correctly
[1:tc0008]
[1:tc0008]
[1:tc0008] EOF
[1:t10000a]  10000a myinst is 2
[1:t10000a] --- Simple PVM Bandwidth Test ----
[1:t10000a]  Using pack option: PvmDataDefault
[1:t10000a]  Max data size is: 800000
[1:t10000a]  Number of iterations/sample: 20
[1:t10000a]
[1:t10000a]
[1:t10000a]  Roundtrip time is measured from user-space to user-space.
[1:t10000a]  For packed messages this includes the combined time of:
[1:t10000a]     inst 0: pvm_initsend()
[1:t10000a]     inst 0: pvm_pack()
[1:t10000a]     inst 0: pvm_send()
[1:t10000a]     inst 1: pvm_recv()
[1:t10000a]     inst 1: pvm_unpack()
[1:t10000a]     inst 1: pvm_initsend()
[1:t10000a]     inst 1: pvm_pack()
[1:t10000a]     inst 1: pvm_send()
[1:t10000a]     inst 0: pvm_recv()
[1:t10000a]     inst 0: pvm_unpack()
[1:t10000a]
[1:t10000a]
[1:t10000a] ---------------------------------------
[1:t10000a] 10000a -- I am the master
[1:t10000a] t10000a: 100000 doubles received correctly
[1:t10000a]
[1:t10000a]
[1:t10000a] Roundtrip T = 3153 (us)  (0.0000 MB/s)  Data size: 0
[1:t10000a] Roundtrip T = 2655 (us)  (0.0060 MB/s)  Data size: 8
[1:t10000a] Roundtrip T = 2766 (us)  (0.0578 MB/s)  Data size: 80
[1:t10000a] Roundtrip T = 3770 (us)  (0.4244 MB/s)  Data size: 800
[1:t10000a] Roundtrip T = 15175 (us)  (1.0544 MB/s)  Data size: 8000
[1:t10000a] Roundtrip T = 136795 (us)  (1.1696 MB/s)  Data size: 80000
[1:t10000a] Roundtrip T = 1438444 (us)  (1.1123 MB/s)  Data size: 800000
[1:t10000a] EOF
[1] finished

É importante perceber que o resultado como mostrado acima não é exibido instantaneamente, podendo demorar alguns segundos para sua exibição completa.

Os softwares para o PVM podem ser executados a partir da linha de comando também. Consulte a documentação do software especifico para saber como usar esse recurso.

Desempenho

Informações de desempenho podem ser visualizadas melhor em alguns casos com o XPVM. Para executar-lo basta usar a seguinte sintaxe num terminal do modo gráfico:

[user@localhost user]# xpvm

No teste anterior o programa exibiu ao final de sua execução um pequeno relatório com alguns dados sobre os tempos de execução, veremos como esses dados podem ser interpretados através do XPVM. A seguir temos um screenshot da execução do mesmo programa de teste sob a monitoração do XPVM.

Podemos observar que do lado direito, logo abaixo da exibição dos hosts, existe um contador de tempo, onde foi registrado o período total de execução do processo. Perceba também no gráfico timeline que nem todos os hosts processam a mesma quantidade de dados, e nem mesmo estão sincronizados.

Recomendo que o usuário leia com atenção cada um dos menus, para tirar o máximo proveito de todas as funcionalidades do XPVM.

Conclusão

Os procedimentos de execução do programa podem ser realizados através da bonita interface gráfica do XPVM, que provê maior interatividade e facilidade de uso da máquina virtual paralela. O XPVM também oferece recursos de tracing, que pode ajudar muito a debugar programas e ver como sua execução se comporta no ambiente do cluster, é possível visualizar gráficos de tempo, utilização de CPU e muitos outros.

Talvez você tenha se decepcionado com as aplicações de teste do PVM, que realmente não são nada interessantes… E você está coberto de razão, mas mantenha a calma, o que você viu são apenas testes…

Realmente os programas de exemplo são muito abstratos, e não mostram nenhuma vantagem, ou algo atrativo, interessante para usar o PVM. Isso muda de figura completamente quando usamos um software com finalidades conhecidas como uma aplicação para quebrar senhas, um renderizador de imagens, ou até mesmo um utilitário para rippar CDs.

Para maiores informações, acessem o site do projeto LC3.

Referências

GEIST, AL.
BEGUELIN, ADAM.
   PVM - A USERS' GUIDE AND TUTORIAL FOR NETWORK PARALLEL C
   Editora MIT PRESS, 1994

SPECTOR, DAVID L.
   BUILDING LINUX CLUSTERS. EUA
   Editora OREILLY & ASSOC, 2000

Documentação do PVM, como manterial on-line, e páginas de manual que acompanha o programa.

Considerações finais

Esse documento é parte do projeto LC3 (Low Cost Computer Cluster).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: