===== 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.