hit counter

Sistemas y servicios informáticos para Internet. Curso 2009-2010

Capítulo 3. Migración y checkpoints en Condor

Tabla de contenidos

3.1. Universo standard

3.1. Universo standard

Hasta ahora hemos estado enviando trabajos dentro del universo vanilla. Condor soporta otros universos que proporcionan interesante características. En concreto, el universo standard es muy útil para trabajos que se ejecutan durante mucho tiempo ya que condor hace checkpoints de ellos que luego permiten pausarlos y restaurarlos.

El universo stardard ofrece dos grandes ventajas respecto al universo vanilla:

  1. Los trabajos puede ser restaurados desde el instante en el que se hizo un checkpoint, ya que un checkpoint guarda todo el estado del programa en ejecución. Esto permite que si el trabajo se ejecuta en una máquina que falla se puede continuar su ejecución en otra sin tener que empezar desde el principio

  2. El acceso a ficheros es redirigido de forma transparente desde la máquina donde se ejecuta el trabajo a la máquina desde la que se envió el trabajo. Las transferencias de ficheros no son necesarias, los ficheros se crean en la máquina de envío

Para poder utilizar el universo standard es necesario recompilar los programas con las librerías de condor. Debido a que condor no funciona en modo kernel sino en modo usuario, no todos los programas se pueden ejecutar en el universo stardard, hay limitaciones.

Antes de empezar con el nuevo ejercicio, vamos crear un nuevo directorio que lo contenga.

$> mkdir ~/condor/nsort
$> cd ~/condor/nsort

A continuación vamos a crear dos ficheros fuente en lenguaje C++.

$> cat > ngen.cpp
//
// ngen.cpp
// Genera números aleatorios
// Recibe como argumento la cantidad de números a generar

#include <iostream>

int main(int argc, char* argv[])
{
  if (argc != 2)
  {
    std::cout << "Usage: ngen <number>" << std::endl;
    return -1;
  }

  srand(time(0));
  int numgen = atoi(argv[1]);
  for (int i = 0; i < numgen; i++)
    std::cout << rand() << std::endl;

  return 0;
}
$> cat > nsort.cpp
//
// nsort.cpp
// Ordena una lista de números
// Si recibe el parámetro -qsort utiliza el algoritmo std::sort
// En otro caso usa una ordenación tipo burbuja (lenta)

#include <iostream>
#include <vector>

void BubbleSort(std::vector<int>& data)
{
  int i, j, temp;
  double done;

  int length = data.size();
  for(i = length - 1; i > 0; i--)
  {
    for(j = 0; j < i; j++)
    {
      if(data[j] > data[j+1])
      { 
        temp = data[j];   
        data[j] = data[j+1];
        data[j+1] = temp;
      }
    }
		done = ((length - 1) - i)/(double)length;
  	std::cerr << done*100 << "% done" << std::endl;
  }
  std::cerr << "100% done" << std::endl;
}

int main(int argc, char* argv[])
{
  std::vector<int> data;
  bool use_qsort = false;
  
  if (argc == 2)
  {
    if (strcmp(argv[1], "-qsort") == 0)
      use_qsort = true;
  }

  int number;
  while (std::cin >> number)
    data.push_back(number);
      
  if (use_qsort)
    std::sort(data.begin(), data.end());
  else
    BubbleSort(data);

  for (int i =0; i < data.size(); i++)
    std::cout << data[i] << std::endl;

  return 0;
}

El programa nsort.cpp lee de la entrada estándar (stdin) una lista de números, la ordena, e imprime el resultado por la salida estándar (stdout). Mientras ordena la lista imprime por la salida de error (stderr) el porcentaje que lleva ordenado. Por defecto, el programa utiliza el método de la burbuja, aunque también se puede forzar a que utilice el algoritmo de ordenación quicksort pasándole como parámetro -qsort. El programa ngen.cpp se va a utilizar para generar las listas de números. Este programa recibe un parámetro que indica cuantos números se van a generar.

Para compilarlos utilizaremos el compilador g++

$> g++ -o ngen ngen.cpp
$> g++ -o nsort nsort.cpp

A continuación vamos a comprobar que funcionan correctamente.

$> ./ngen 5 > nsort.in
$> cat nsort.in
679869553
9540590
542490780
1315065666
882304959
$> ./nsort < nsort.in
0% done
20% done
40% done
60% done
100% done
488936095
492384844
695267639
707128557
1477109292

Para poder ejecutar el trabajo sobre el universo standard hay que enlazar el programa con las librerías de condor.

$> condor_compile g++ -o nsort nsort.cpp
LINKING FOR CONDOR : /usr/bin/ld -L/opt/condor/lib -Bstatic --eh-frame-hdr -m 

...

Los warnigs que aparecen tras la compilación se pueden ignorar.

Es conveniente eliminar la información de depuración del ejecutable

$> ls -l nsort
-rwxr-xr-x  1 ruf users 5101246 Jan 29 17:10 nsort
$> strip nsort
$> ls -l nsort
-rwxr-xr-x  1 ruf users 1547292 Jan 29 17:13 nsort

A pesar de eliminar la información de depuración, el ejecutable sigue ocupando bastante debido o a que contiene las librerías de condor.

Si se vuelve a ejecutar el programa ahora, avisa de la creación de un fichero de checkpoint.

$> ./nsort < nsort.in
Condor: Notice: Will checkpoint to ./nsort.ckpt
Condor: Notice: Remote system calls disabled.
0% done
20% done
40% done
60% done
100% done
488936095
492384844
695267639
707128557
1477109292

Creamos un fichero de descripción para el trabajo, indicando que queremos utilizar el universo standard.

$> cat > nsort.sub
Universe   = standard
Executable = nsort
Input      = nsort.in
Output     = nsort.out
Error      = nsort.error
Log        = nsort.log
Queue

Envíamos el trabajo y observamos los resultados.

$> condor_submit nsort.sub
Submitting job(s).
Logging submit event(s).
1 job(s) submitted to cluster 118.
$> condor_q


-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.infn.it
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD

0 jobs; 0 idle, 0 running, 0 held

$> cat nsort.log
a]]
000 (118.000.000) 01/30 09:08:58 Job submitted from host: <193.206.208.141:9632>
...
001 (118.000.000) 01/30 09:09:01 Job executing on host: <193.206.208.205:9680>
...
005 (118.000.000) 01/30 09:09:01 Job terminated.
        (1) Normal termination (return value 0)
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Local Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Total Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Total Local Usage
        3035  -  Run Bytes Sent By Job
        1581578  -  Run Bytes Received By Job
        3035  -  Total Bytes Sent By Job
        1581578  -  Total Bytes Received By Job
...
$> cat nsort.out
488936095
492384844
695267639
707128557
1477109292
Borramos los ficheros generados para que no haya confusión.
$> ~/condor/clean

Vamos a aumentar el tamaño del fichero de entrada para que la ordenación sea más lenta y nos permita utilizar los checkpoints.

$> ./ngen 7000 > nsort.in

Antes de volver a mandar el trabajo, vamos lanzar otra terminal que nos permita ver la evolución del programa mientras ejecutamos comandos. Desde la segunda terminal, entramos al directorio del ejercicio y bloquemos la terminal mostrándonos el final del fichero nsort.error, donde se imprime el porcentaje de fichero ordenado.

$> cd ~/condor/nsort
$> tail -F nsort.error

El comando tail da un error. Sin embargo, cuando el fichero se cree nos lo comenzará a mostrar.

Nota

Durante la ejecución de un programa en el universo standard podemos ver lo que se está escribiendo en los ficheros de salida gracias al sistema de llamadas remotas al sistema de E/S que ofrecen las librerías de condor.
Volvemos a lanzar el trabajo desde la primera terminal.
$> condor_submit nsort.sub
Submitting job(s).
Logging submit event(s).
1 job(s) submitted to cluster 119.
$> condor_q


-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.infn.it
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD
 119.0   ruf             1/30 09:24   0+00:00:00 R  0   1.7  nsort

1 jobs; 0 idle, 1 running, 0 held

Si observamos los servicios que se están ejecutando comprobaremos que el condor_shadow está monitorizando la ejecución de nuestro trabajo

$> ps aux | grep condor
ruf       5273  2.7  0.0  6668 2736 ?        S    09:24   0:00 condor_shadow <193.206.208.141:9669 ...
ruf       5280  0.0  0.0 51104  676 pts/4    S+   09:25   0:00 grep condor
condor   21597  0.0  0.0  7244 3052 ?        Ss   Jan29   0:17 condor_master
condor   21598  0.0  0.1  8568 4192 ?        Ss   Jan29   0:00 condor_schedd -f
root     21599  0.0  0.0  3684 2032 ?        S    Jan29   0:16 condor_procd -A ...

Primer vamos a pausar la ejecución del trabajo, para lo cual debes fijarte en el número de cluster.proceso que tiene asignado. También podemos indicar -all para que lo haga con todos nuestros trabajos.

$> condor_hold -all
All jobs held.

Observa como ha cambiado el estado del trabajo.

$> condor_q


-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.infn.it
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD
 119.0   ruf             1/30 09:24   0+00:00:00 H  0   1.7  nsort

1 jobs; 0 idle, 0 running, 1 held

Reanudamos su ejecución.

$> condor_release -all
All jobs released.

Comprueba con condor_q el estado del trabajo y espera hasta que vuelva a estar en ejecución.

Ahora vamos a migrar el trabajo. Este proceso detiene la ejecución del trabajo y busca una nueva máquina donde ejecutarlo. A continuación realiza la migración a la nueva máquina. Es posible y probable que la nueva máquina donde ejecute el trabajo sea la misma que donde se estaba ejecutando anteriormente.

$> condor_vacate_job -all
All jobs vacated.

Hasta que termine la migración, el trabajo pasa a estado idle y su ejecución se detiene (observa la segunda terminal).

$> condor_q


-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.infn.it
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD
 119.0   ruf             1/30 09:24   0+00:00:50 I  0   3.2  nsort

1 jobs; 1 idle, 0 running, 0 held
$> ps aux | grep condor
ruf       5288  0.0  0.0 51104  676 pts/4    S+   09:25   0:00 grep condor
condor   21597  0.0  0.0  7244 3052 ?        Ss   Jan29   0:17 condor_master
condor   21598  0.0  0.1  8568 4192 ?        Ss   Jan29   0:00 condor_schedd -f
root     21599  0.0  0.0  3684 2032 ?        S    Jan29   0:16 condor_procd -A ...

Si comprobamos el fichero de log del trabajo podremos observar como se ha hecho un checkpoint del trabajo.

$> cat nsort.log
000 (119.000.000) 01/30 09:24:40 Job submitted from host: <193.206.208.141:9632>
...
001 (119.000.000) 01/30 09:24:42 Job executing on host: <193.206.208.205:9680>
...
006 (119.000.000) 01/30 09:25:31 Image size of job updated: 3207
...
004 (119.000.000) 01/30 09:25:32 Job was evicted.
        (1) Job was checkpointed.
                Usr 0 00:00:43, Sys 0 00:00:00  -  Run Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Local Usage
        2484234  -  Run Bytes Sent By Job
        2036754  -  Run Bytes Received By Job
...

La migración en Condor puede tardar hasta 10 minutos, y puede dar como resultado que vuelva a ejecutar el trabajo sobre la misma máquina.

Nota

Recuerda que condor es un sistema diseñado par HTC, es decir, donde los trabajos se ejecutan durante mucho tiempo. Diez minutos en hacer la migración es un tiempo despreciable.

Mientras esperamos que el trabajo se reanude, vamos a observar los ficheros de log y de checkpoint. En primer lugar necesitamos saber donde se crean.

$> condor_config_val SPOOL
/var/condor/spool

Si observamos el directorio spool veremos el fichero de checkpoint que condor ha creado para nuestro trabajo.

$> ls `condor_config_val SPOOL`
cluster119.ickpt.subproc0  history        job_queue.log.7
cluster119.proc0.subproc0  job_queue.log  local_univ_execute

También se puede examinar el contenido de los ficheros de log.

$> condor_config_val LOG
/var/condor/log
$> more  `condor_config_val LOG`/MasterLog

...

$> more  `condor_config_val LOG`/ShadowLog

...

$> more  `condor_config_val LOG`/SchedLog

...

Con el comando condor_q se puede ver el ClassAd que ha generado un trabajo.

$> condor_q -l

-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.i
nfn.it
MyType = "Job"
TargetType = "Machine"
ClusterId = 121
QDate = 1233335825
CompletionDate = 0
Owner = "ruf"
RemoteWallClockTime = 0.000000
LocalUserCpu = 0.000000
LocalSysCpu = 0.000000
RemoteUserCpu = 0.000000
RemoteSysCpu = 0.000000
ExitStatus = 0
NumCkpts_RAW = 0

...

Espera a que el trabajo termine y examina su log.

Nota

Mientras esperas aprovecha para consultar las dudas que te hayan surgido o para repetir algunos de los pasos anteriores si no te han quedado claros. También puedes echar un vistazo a la página web de condor, donde se encuentra su manual online.
$> condor_q


-- Submitter: glite-tutor.ct.infn.it : <193.206.208.141:9632> : glite-tutor.ct.infn.it
 ID      OWNER            SUBMITTED     RUN_TIME ST PRI SIZE CMD

0 jobs; 0 idle, 0 running, 0 held
$> cat nsort.log
000 (119.000.000) 01/30 09:24:40 Job submitted from host: <193.206.208.141:9632>
...
001 (119.000.000) 01/30 09:24:42 Job executing on host: <193.206.208.205:9680>
...
006 (119.000.000) 01/30 09:24:44 Image size of job updated: 3207
...
012 (084.000.000) 01/30 09:24:45 Job was held.
        via condor_hold (by user ruf)
        Code 1 Subcode 0
...
013 (084.000.000) 01/30 09:24:46 Job was released.
        via condor_release (by user ruf)
...
001 (084.000.000) 01/30 09:24:52 Job executing on host: <193.206.208.205:9680>
...
004 (119.000.000) 01/30 09:25:32 Job was evicted.
        (1) Job was checkpointed.
                Usr 0 00:00:43, Sys 0 00:00:00  -  Run Remote Usage
                Usr 0 00:00:00, Sys 0 00:00:00  -  Run Local Usage
        2484234  -  Run Bytes Sent By Job
        2036754  -  Run Bytes Received By Job
...
001 (119.000.000) 01/30 09:34:43 Job executing on host: <193.206.208.205:9680>
...
005 (119.000.000) 01/30 11:22:29 Job terminated.
        (1) Normal termination (return value 0)
                Usr 0 01:46:42, Sys 0 00:00:14  -  Run Remote Usage
                Usr 0 00:00:03, Sys 0 00:00:09  -  Run Local Usage
                Usr 0 01:47:25, Sys 0 00:00:14  -  Total Remote Usage
                Usr 0 00:00:03, Sys 0 00:00:09  -  Total Local Usage
        12241028  -  Run Bytes Sent By Job
        5377388  -  Run Bytes Received By Job
        14725262  -  Total Bytes Sent By Job
        7414142  -  Total Bytes Received By Job
...

Atención

Cuando termines la sesión de prácticas, borra los ficheros que se han ido generando durante la ejecución de los trabajos con ~/condor/clean y guarda una copia del resto (Puede usar el WinSCP).