===== Tutorial: Submissão de processos nas filas =====
A GINA usa o gerenciador de filas [[software#torque|TORQUE]], mantendo duas filas:
*short - Para processos executados em até 1 hora. Não há minimo de tempo de execução (walltime).
*long - Para processos executados em até 10 horas. O tempo mínimo de execução (walltime) a alocar é 3601 segundos.
Processos devem ser submetidos à fila route, que os encaminha à mais apropriada das duas acima.
==== Consultas ao servidor TORQUE ====
A situação das filas pode ser consultada com ''qstat''; ''qstat -q'' mostra a situação de todas as filas:
penteado@gina:~> qstat -q
server: gina-n2-ib
Queue Memory CPU Time Walltime Node Run Que Lm State
---------------- ------ -------- -------- ---- --- --- -- -----
batch -- -- -- -- 0 0 -- D S
route -- -- -- -- 0 0 -- E R
short -- -- 01:00:00 -- 0 0 20 E R
long -- -- 48:00:00 -- 0 0 10 E R
----- -----
0 0
Os processos do usuário podem ser consultados com apenas ''qstat'':
penteado@gina:~/subtest> qstat
Job id Name User Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
15.gina ExampleJob penteado 0 R short
16.gina ExampleJob penteado 0 R short
Ou, para muito mais detalhes, ''qstat -f''.
==== Scripts para submissão de trabalhos ====
A submissão de processos é feita com ''qsub''. Ela pode ser feita especificando todas as opções diretamente com argumentos para ''qsub'', ou (o mais comum), criando-se um script que especifica os argumentos como comentários. Por exemplo, criando o script ''example_job.sh'':
#!/bin/sh
#
#This is an example script example_job.sh
#To be used with TORQUE's qsub ("qsub example_job.sh"), not directly
#
#These commands set up the Grid Environment for your job:
#PBS -N example_job
#PBS -d /home/some_user/some_place/
#PBS -l procs=3,walltime=00:01:00
#PBS -q route
#PBS -M some_user
#PBS -m abe
#print the time and date
echo "Starting TORQUE script $PBS_JOBNAME at"
date
#print the name of the node executing these lines (it is only one node)
uname -a
#print some more data from TORQUE
echo "PBS_NODEFILE: $PBS_NODEFILE"
cat $PBS_NODEFILE
echo "PBS_GPUFILE: $PBS_GPUFILE"
if [ -e $PBS_GPUFILE ]
then
cat $PBS_GPUFILE
fi
#go to the proper directory
cd $PBS_O_WORKDIR
#this is where something useful would usually be done
#print the time and date again
echo "Ending TORQUE job $PBS_JOBID at "
date
As linhas comentadas com ''#PBS'' especificam argumentos para o ''qsub''. Veja o seu manual (''man qsub''), ou a sua [[http://www.clusterresources.com/products/torque/docs/commands/qsub.shtml|documentação online]] para mais detalhes. No caso, estão sendo especificados:
*Nome do processo (''-N example_job'').
*Diretório de onde ele será executado (''-d /home/some_user/some_place/'').
*Recursos (número de nós, quantidade de "cores", número de GPUs, tempo de execução) solicitados (''-l procs=3,walltime=00:01:00'').
*Nome da fila (''-q route'').
*Email para envio dos avisos sobre o trabalho (''-M some_user'').
*Opções para o programa de envio de email (''-m abe'').
Se for usar o arquivo acima, edite pelo menos o endereço de email usado, que é para onde será mandado um email informado quando o trabalho for concluído, e o diretório usado para execução.
=== Especificação de recursos ===
Trabalhos que usem mais de um núcleo devem o solicitar em uma de três formas:
*Pelo recurso ''procs''. Ex: ''#PBS -l procs=4,walltime=00:01:00''
*Pelo recurso ''nodes'', para quaisquer nós. Ex: ''#PBS -l nodes=2:ppn=4,walltime=00:01:00'' (2 nós, 4 processos por nó).
*Pelo recurso ''nodes'', para um nó específico. Ex: ''#PBS -l nodes=gina-n1-ib:ppn=4,walltime=00:01:00'' (só o nó gina-n1, 4 processos por nó).
A escolha de um ou outro nó é mais relevante com relação ao local onde estarão os arquivos a serem acessados pelo programa. O diretório /home reside no nó gina-n2, sendo exportado por nfs para o nó gina-n1. Portanto, o acesso a arquivos no /home é mais lento do nó gina-n1, pois se dá pela rede (ethernet). Os nomes dos nós para solicitação nas filas são ''gina-n1-ib'' e ''gina-n2-ib''.
Caso seja necessário o programa lidar com arquivos localmente (por eficiência de acesso, ou para exceder a quota de usuário (10 GB)), pode ser usado o ''/tmp''. Neste caso, todos os arquivos do usuário devem residir dentro de um diretório com o nome do usuário, no ''/tmp'' (ex: ''/tmp/some_user/'').
Para transferência entre nós, e para tornar links mais convenientes, ambos os nós vêem os diretórios ''/tmp_gina-n1'' e ''/tmp_gina-n2'', correspondendo ao ''/tmp'' de cada nó.
== GPUs ==
Trabalhos que usem GPUs devem o solicitar. Apenas as duas GPUs do nó gina-n1 estão disponíveis para as filas (as duas do nó gina-n2 estão reservadas para uso interativo, sem a fila). Exemplo:
#PBS -l nodes=1:ppn=1:gpus=1,walltime=01:00:00
=== Script para MPI ===
Programas com uso de MPI devem ser chamados com o mpirun, com os argumentos determinados pelo TORQUE. Ex:
#!/bin/sh
#
#This is an example script example_MPI.sh
#To be used with TORQUE's qsub ("example_MPI.sh"), not directly
#
#These commands set up the Grid Environment for your job:
#PBS -N example_MPI
#PBS -d /home/some_user/some_place/
#PBS -l nodes=1:ppn=3,walltime=00:01:00
#PBS -q route
#PBS -M some_user
#PBS -m abe
#print the time and date
echo "Starting TORQUE script $PBS_JOBNAME at"
date
#print the name of the node executing these lines (it is only one node)
uname -a
#print some more data from TORQUE
echo "PBS_NODEFILE: $PBS_NODEFILE"
cat $PBS_NODEFILE
echo "PBS_GPUFILE: $PBS_GPUFILE"
if [ -e $PBS_GPUFILE ]
then
cat $PBS_GPUFILE
fi
#determine the number and name of processors that TORQUE has allocated
np=`wc -l $PBS_NODEFILE`
np=${np%"$PBS_NODEFILE"}
echo "Running $np processes"
map=`tr '\n' ':' <$PBS_NODEFILE`
#call an example MPI program, with the proper mpirun arguments
mpirun -machinefile $PBS_NODEFILE -map $map -np $np $PBS_O_WORKDIR/mpitest.out
#print the time and date again
echo "Ending TORQUE job $PBS_JOBID at "
date
Um programa de teste para verificar a execução por MPI pode ser
program main
use mpi
implicit none
integer :: numtasks,i
integer :: name_len,name_len_max
!Variables for MPI
integer :: isendbuf,isendcount,ierr,rank,root,rc
character(len=MPI_MAX_PROCESSOR_NAME) :: proc_name
integer,allocatable :: irecvbuf(:)
character(1),allocatable :: crecvbuf(:)
!Variables for the arrays to use to waste some time
integer,parameter :: length=100000
real(selected_real_kind(15,307)) :: atmp(length),btmp(length)
!MPI initialization
call mpi_init(ierr)
if (ierr .ne. MPI_SUCCESS) then
print *,'Error starting MPI program. Terminating.'
call mpi_abort(MPI_COMM_WORLD,rc,ierr)
end if
!Initialize "global" variables
root=0 !The process that will do the receiving and output
isendcount=1 !How many integerss will be gathered
!Get the MPI "locals"
call mpi_comm_rank(MPI_COMM_WORLD,rank,ierr) !The process rank
call mpi_get_processor_name(proc_name,name_len,ierr) !The processor name
!Do the initialization, only by the root process
if (rank .eq. root) then
call mpi_comm_size(MPI_COMM_WORLD,numtasks,ierr)
allocate(irecvbuf(numtasks*isendcount)) !Make room for gathering the process ranks
endif
!Do the work (by all processes)
isendbuf=rank
!Find out the maximum length of the processor name, accross all processes
call mpi_allreduce(name_len,name_len_max,isendcount,MPI_INTEGER,MPI_MAX,MPI_COMM_WORLD,ierr)
!Make room to get the processor names (has to be here, after knowing the maximum processor name length)
if (rank .eq. root) then
allocate(crecvbuf(name_len_max*numtasks))
endif
!Waste some time, so that the processes take some noticeable time to run
forall(i=1:length) atmp(i)=(i-1)/((length-1)*1d0)
do i=0,100
btmp=acos(cos(atmp*acos(-1d0)))
enddo
!Get the results from everybody (ranks and names)
call mpi_gather(isendbuf,isendcount,MPI_INTEGER,irecvbuf,isendcount,MPI_INTEGER,root,MPI_COMM_WORLD,ierr)
call mpi_gather(proc_name(1:name_len_max),name_len_max,MPI_CHARACTER,crecvbuf,name_len_max,MPI_CHARACTER,root,MPI_COMM_WORLD,ierr)
!Show the results
if (rank .eq. root) then
print *,'I am process number ',rank
print *,'Running on processor ',proc_name(1:name_len)
print *,'Number of tasks is ',numtasks
do i=0,numtasks-1
print *,'Process rank ',irecvbuf(i+1),' ran on processor ',crecvbuf(i*name_len_max+1:(i+1)*name_len_max)
enddo
endif
call mpi_finalize(ierr)
end program main
Que pode ser compilado com o compilador PGI com
''mpif90 mpitest.f90 -o mpitest.out''
Este programa, se executado por um script como o desta seção, resulta em algo como
Starting TORQUE script mpitest at
Mon Apr 11 01:49:14 BRT 2011
Linux gina-n2 2.6.32.13-0.4-default #1 SMP 2010-06-15 12:47:25 +0200 x86_64 x86_64 x86_64 GNU/Linux
PBS_NODEFILE: /var/spool/torque/aux//181.gina-n2-ib
gina-n2-ib
gina-n2-ib
gina-n2-ib
gina-n2-ib
PBS_GPUFILE: /var/spool/torque/aux//181.gina-n2-ibgpu
Running 4 processes
I am process number 0
Running on processor gina-n2
Number of tasks is 4
Process rank 0 ran on processor gina-n2
Process rank 1 ran on processor gina-n2
Process rank 2 ran on processor gina-n2
Process rank 3 ran on processor gina-n2
Ending TORQUE job 181.gina-n2-ib at
Mon Apr 11 01:49:21 BRT 2011
=== Script para OpenMP ===
OpenMP exige memória compartilhada. Como não há memória compartilhada entre os dois nós, programas com OpenMP precisam ser executados em um único nó. Como exemplo, o script acima poderia ser:
#!/bin/sh
#
#This is an example script example_OMP.sh
#To be used with TORQUE's qsub ("example_OMP.sh"), not directly
#
#These commands set up the Grid Environment for your job:
#PBS -N example_OMP
#PBS -d /home/some_user/some_place/
#PBS -l nodes=1:ppn=3,walltime=00:01:00
#PBS -q route
#PBS -M some_user
#PBS -m abe
#print the time and date
echo "Starting TORQUE script $PBS_JOBNAME at"
date
#print the name of the node executing these lines (it is only one node)
uname -a
#print some more data from TORQUE
echo "PBS_NODEFILE: $PBS_NODEFILE"
cat $PBS_NODEFILE
echo "PBS_GPUFILE: $PBS_GPUFILE"
if [ -e $PBS_GPUFILE ]
then
cat $PBS_GPUFILE
fi
#determine the number and name of cores that TORQUE has allocated
np=`wc -l $PBS_NODEFILE`
np=${np%"$PBS_NODEFILE"}
echo "Running on $np cores"
export NCPUS=$np
#go to the proper directory
cd $PBS_O_WORKDIR
#this is where the OpenMP program would be called
#print the time and date again
echo "Ending TORQUE job $PBS_JOBID at "
date
==== Submissão e controle de trabalhos ====
O script é executado então simplesmente passando-o como argumento ao ''qsub'': ''qsub /home/user/example.sh''. As saídas que o processo envia ao ''STDOUT'' e ''STDERR'' (normalmente conectador ao terminal) são redirecionadas para arquivos com nomes baseados no nome do trabalho e ''Job id'', como ''ExampleJob.o15'' (''STDOUT'' para o trabalho 15) e ''ExampleJob.e15'' (''STDERR'' para o trabalho 15). No caso do script acima, ele não gera erro (o arquivo do ''STDERR'' fica vazio), e a saída do ''STDOUT'' é algo do tipo:
Starting TORQUE script example_job at
Mon Apr 11 01:49:14 BRT 2011
Linux gina-n2 2.6.32.13-0.4-default #1 SMP 2010-06-15 12:47:25 +0200 x86_64 x86_64 x86_64 GNU/Linux
PBS_NODEFILE: /var/spool/torque/aux//181.gina-n2-ib
gina-n2-ib
gina-n2-ib
gina-n2-ib
gina-n2-ib
PBS_GPUFILE: /var/spool/torque/aux//181.gina-n2-ibgpu
Ending TORQUE job 181.gina-n2-ib at
Mon Apr 11 01:49:21 BRT 2011
Trabalhos podem ser removidos da fila com ''qdel'', através do seu ''Job id'':
penteado@gina:~/subtest> qstat
penteado@gina:~/subtest> qsub ./qtest.sh
18.gina.iag.usp.br
penteado@gina:~/subtest> qstat
Job id Name User Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
18.gina ExampleJob penteado 0 R short
penteado@gina:~/subtest> qdel 18.gina
penteado@gina:~/subtest> qstat
Job id Name User Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
18.gina ExampleJob penteado 00:00:00 C short
Trabalhos completos (status ''C'') só continuam sendo mostrados na saída do ''qstat'' por 5 dias após seu encerramento.