TORQUE Resource manager es un software que permite «agendar» tareas computacionales,i.e.
«tareas batch». Provee control sobre estas tareas y los recursos computacinoales de sistemas distribuidos. Posee los siguientes componentes:
Servidor: En este caso se llama
pbs_server. Permite operaciones básicas como crear, modificar, borrar y ejecutar un trabajo.
Ejecutor: Es un demonio, llamado en nuestro caso
pbs_mom, que pone el comando en ejecución cuando recibe una copia del trabajo de el server.
Agendador: Otro demonio que tiene las políticas para decidir que trabajo se ejecuta, donde y cuando. Usamos el agendador MAUI el cual se puede comunicar con varios MOMs para comunicar al servidor el estado de los recursos y para conocer del servidor el estado de los trabajos a ejecutar.
Hola Torque
Usted puede solicitar a TORQUE el estado de un nodo con el comando
pbsnodes o de todos los nodos con
pbsnodes -a, con los cuales debe obtener una salida como esta para cada nodo en el sistema:
wn1
state = free
np = 32
ntype = cluster
status = rectime=1376977699,varattr=,jobs=,state=free,netload=28936987148,gres=,
loadave=1.04,ncpus=32,physmem=57801956kb,availmem=100795756kb,
totmem=106629856kb,idletime=1149356,nusers=1,nsessions=2,sessions=2996358788,
uname=Linux gfif-wn1 3.2.0-4-amd64 #1 SMP Debian 3.2.41-2 x86_64,opsys=linux
«free» significa que el nodo está en capacidad de correr tareas, «np» es el número de procesadores.
Enviar un trabajo
Para enviar un trabajo o tarea al sistema TORQUE es necesario crear un script de shell (puede ser bash, sh, ksh, etc) con directivas especiales a modo de comentario...
#! /bin/sh
#PBS -N prueba
#PBS -o prueba.out
#PBS -e prueba.err
#PBS -l walltime=00:01:00
date
hostname
sleep 20
date
Archivo que hemos llamado prueba.sh para correrlo así
¿Cómo espera usted que sea la salida de este trabajo?
Si está corriendo en múltiples máquinas ¿Dónde se espera encontrar el stdout?
Monitorear el trabajo
El comando
qstat -a nos muestra el estado de los trabajos de todas las colas, obtenemos uua salida como esta
Job ID Username Queue Jobname SessID NDS TSK Memory Time S Time
-------------------- -------- -------- ---------------- ------ ----- --- ------ ----- - -----
1171.gfif.udea.e gerardo batch prueba 21476 2 2 -- 00:01 R --
El commando
Muesta una sálida del tipo
wn4
state = free
np = 72
ntype = cluster
jobs = 0/8530.gfifmaster, 1/8530.gfifmaster, 2/8530.gfifmaster
status = ...
Que quiere decir que nodo `wn4` tiene procesadores disponible ( status=free ) pues de los 72 se están usando 3 (`jobs = 0/8530.gfifmaster, 1/8530.gfifmaster, 2/8530.gfifmaster`)
Algunos comandos de pbs para monitoreo y control son
qstat -a | Verifica el estado de los trabajos, las colas y el servidor PBS.
|
qstat -f | Obtiene toda la información del trabajo lanzado, como: Recursos pedidos, cola, fuente, destino, propietario, recursos límite, etc.
|
qdel job.ID | Borra un trabajo.
|
qhold job.ID | Pone un trabajo en estado de espera si se encuentra en cola.
|
qrls job.ID | Saca a un trabajo del estado de espera.
|
Algunos comandos útiles de maui
showq | Muestra una lista detallada de los trabajos lanzados.
|
showbf | uestra los recursos libres.
|
checkjob job.ID | muestra una descripción detallada del trabajo.
|
showstart job.ID | Muestra el tiempo estimado de comienzo del trabajo.
|
El script de PBS
Algunas opciones de PBS para el script son
Opción | Descripción
|
#PBS -N myJob | Asigna el nombre a un trabajo
|
#PBS -l nodes=4:ppn=2 | El número de nodos y procesos por nodo
|
#PBS -q queuename | Asigna la cola en al que su trabajo va a estar.
|
#PBS -l walltime=01:00:00 | El tiempo de reloj «de pared» durante el cual su trabajo puede correr.
|
#PBS -o mypath/my.out | La dirección y el nombre del archivo para guardar el stdout.
|
#PBS -e mypath/my.err | La dirección y el nombre del archivo para guardar el stderr.
|
#PBS -j oe | Une el stdout con el stderr.
|
#PBS -M user@mail | email del usuario al cual enviar reportes.
|
#PBS -m b | Envia un email cuando el trabajo comienza.
|
#PBS -m e | Envia un email cuando el trabajo termina.
|
#PBS -m a | Envia un email cuando el trabajo aborta por un error.
|
#PBS -V | Exporta todas las variables de entorno al trabajo.
|
Algunas variables de entorno de PBS son
PBS_O_HOME | La ruta al home de el que se corrió qsub.
|
PBS_O_WORKDIR | El directorio en el que se corrió qsub.
|
PBS_O_LOGNAME | El nombre de usuario que corrió qsub.
|
PBS_O_HOST | El nombre de la máquina en la que se corrió qsub.
|
PBS_O_QUEUE | La cola a la que el trabajo fue enviado.
|
PBS_JOBID | El identificador que asigna PBS al trabajo.
|
PBS_JOBNAME | El nombre del trabajo.
|
PBS_NODEFILE | El archivo que contiene la lista de nodos para tareas en paralelo.
|
El proceso de los procesos.
Multiples trabajos
En este ejemplo vamos a ver como podemos acondicionar nuestros programas o nuestro codigo para que trabaje en simultaneo de acuerdo a los argumentos.
creemos una carpeta para hacer el siguente ejercicio.
Creemos un arhcivos integral.cpp
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
double integral(double (*fun)(double),double min,double max, double delta=0.1)
{
double sum=0;
double i;
for(i=min;i<max;i+=delta) sum+=fun(i)*delta;
return sum;
}
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("Error: requiere 2 argumentos, 1=total procesos 2=proceso actual.\n");
return -1;
}
int total_procs=atoi(argv[1]);
int actual_proc=atoi(argv[2]);
double min=0;
double max=2*M_PI;
double parte=(max-min)/total_procs;
double pmin=min+(actual_proc)*parte;
double pmax=pmin+parte;
printf("int(sin,%lf,%lf)=%lf\n",pmin,pmax,integral(sin,pmin,pmax));
return 0;
}
Compilar con:
g++ -o integral integral.cc
creamos el archivo job.sh que contiene las indicaciones para qsub
#!/bin/bash
#
#
#PBS -N JODID
#PBS -M omazapa@gfif.udea.edu.co
#PBS -t 0-4
#echo jobid=$PBS_ARRAYID
$PBS_O_WORKDIR/integral 5 $PBS_ARRAYID
Corremos el script, el status E(Exit) indica que finaliza inmediatamente.
[omazapa] [gfif] [~/pbs/jobid]$ qsub job.sh
1189.gfif.udea.edu.co
[omazapa] [gfif] [~/pbs/jobid]$ qstat
Job id Name User Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
1189-0.gfif JODID-0 omazapa 00:00:00 E batch
1189-1.gfif JODID-1 omazapa 00:00:00 E batch
1189-2.gfif JODID-2 omazapa 00:00:00 E batch
1189-3.gfif JODID-3 omazapa 00:00:00 E batch
1189-4.gfif JODID-4 omazapa 00:00:00 E batch
El resultado de nuestro problema esta en los acrhivos que genera y tenemos que obtenerlo.
[omazapa] [gfif] [~/pbs/jobid]$ cat JODID.o1189-*
int(sin,0.000000,1.256637)=0.683713
int(sin,1.256637,2.513274)=1.161746
int(sin,2.513274,3.769911)=0.034286
int(sin,3.769911,5.026548)=-1.140556
int(sin,5.026548,6.283185)=-0.739188
para obtenerlo corremos el siguiente comando.
cat JODID.o* | gawk -F"=" '{sum+=$2} END {printf("%f\n" ,sum)}'
[omazapa] [gfif] [~/pbs/jobid]$ cat JODID.o* | gawk -F"=" '{sum+=$2} END {printf("%f\n" ,sum)}'
0.000001
Message Passing Interface (MPI)
En esta parte vamos a ver como correr programar paralelizados con mpi, para nuetro caso compilaremos con openmpi.
#include <stdio.h>
#include <mpi.h>
int main (int argc, char *argv[]){
int rank, size;
char hostname[256];
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
gethostname(hostname,255);
printf( "Hello world from %s process %d of %d\n", hostname,rank, size );
MPI_Finalize();
return 0;
}
Bueno el código lo compilamos con
el script para el job llamemolo mpi.sh
#!/bin/sh
### Job name
#PBS -N hellompi
### Output files
#PBS -e hellompi.err
#PBS -o hellompi.log
### Mail to user
#PBS -M omazapa@gfif.udea.edu.co
### Queue name (small, medium, long, verylong) batch is default queue
#PBS -q batch
### Number of nodes and ppn (proc per node)
#PBS -l nodes=2:ppn=5
# This job's working directory
mpirun -machinefile $PBS_NODEFILE -np 10 $PBS_O_WORKDIR/hello
Mpi python
Para python tenemos lo siguiente hello.py
from mpi4py import MPI
import sys
size = MPI.COMM_WORLD.Get_size()
rank = MPI.COMM_WORLD.Get_rank()
name = MPI.Get_processor_name()
sys.stdout.write("Helloworld! I am process %d of %d on %s.\n" % (rank, size, name))
y el script para el job seria
#!/bin/sh
### Job name
#PBS -N hellompi
### Output files
#PBS -e hellompi.err
#PBS -o hellompi.log
### Mail to user
#PBS -M omazapa@gfif.udea.edu.co
### Queue name (small, medium, long, verylong) batch is default queue
#PBS -q batch
### Number of nodes and ppn (proc per node)
#PBS -l nodes=2:ppn=5
# This job's working directory
mpirun -machinefile $PBS_NODEFILE -np 10 python $PBS_O_WORKDIR/hello.py
Ejercicios
busqueda.tar.gz
En el archivo busqueda.tgz hay 2 programas(uno en C y otro en python) y 3 archivos con números del 0 al 9. La idea detrás de cada programa es contar las ocurrencias de alguno de estos números en los 3 archivos.
Se debe realizar en primera instancia el script de PBS que envie este solo proceso donde hayan recursos disponibles.
Luego se debe modificar el programa y el script de tal manera que haga la búsqueda en 3 procesos diferentes.
Referencias
torque jobs
Ejemplos
Random output
[+]
Si parallel.py es un programa con una salida aleatoria, siempre difrente: zee_spc_full.xlsx
que correo en el directorio w1, el siguiente
se puede enviar al sistema de colas de gfif con
y lo que hace es una copia de w1 al siguiente wn nuevo (n-entero) y correr el programa en wn. Es decir, si ya existe w2, crea w3, etc.
Al final hay que unir todos los outputs.
#! /bin/sh
#PBS -N parallel
#PBS -o parallel.out
#PBS -e parallel.err
#PBS -l walltime=100:00:00
DIR=/scratch/restrepo/prog/toolbox/mybinders/radinu/ZeeHB/tests
n=$(ls -ld $DIR/w* | awk -F "tests/w" '{print $2}' | sort -n | tail -n1)
n=$(echo $n | sed -r 's/([0-9]+).*/\1/')
n=$(( $n + 1 ))
if [ "$n" ];then
cd $DIR
mkdir -p w$n
cp w1/* w$n
rm -f w$n/zee_spc_full.xlsx
cd w$n
echo $(pwd)
./parallel.py
else
echo "USAGE: $0 DIR_NUMBER"
fi
P.D. parallel.py es realmente un link simbólico:
w1/parallel.py -> ../parallel.py
Sistema de colas
- Cola corta por defecto: 24h, sin restricciones (5 nodos)
- Cola larga 720h: tiene 3 nodos con máximo 72 cores.
Para lanzar los trabajos adicionar al scrip:
- PBS -q long
Matar múltiples trabajos
qdel $(qstat | awk '{print $1}' | grep -E '^[0-9]')
Muchas gracias
Diego