Definición del trabajo



Vamos a ver como se crea la definición de un trabajo para poder enviar a "Magerit" trabajos para ejecutar. En este caso vamos a utilizar un sencillo código que calcula la media de dos números enteros pasados como primer y segundo argumento. Podemos observar el código :

#include <stdio.h>
#include <stdlib.h>

/*CALCULA LA MEDIA ENTRE DOS NUMEROS*/

int media(int a, int b)
{
  return(a + b)/2;
}

int main(int argc, char *argv[]){
  int a, b, i;
  int resp;
  a = atoi(argv[1]);
  b = atoi(argv[2]);
  resp = media(a,b);
  printf("La media de %d y %d es %d\n", a,b, resp);
  return 0;
}


Nota
La solución está definida como "int", por lo que el resultado de la media será truncado a las unidades. Ejemplo: Media(2,9)=5

Lo primero que hacemos es compilar el código mediante gcc mecia.c -o media teniendo en cuenta que en el vídeo estamos en un nodo Power, y que se estará compilando para la arquitectura Power, por lo que en la directiva @arch (que explicamos mas adelante), tendremos que poner power

Una vez que tenemos el ejecutable abrimos un editor de texto para editar nuestra definición del trabajo o jobfile (siempre con la extensión de archivo .sh ). En el caso del video parto de una plantilla guardada en un fichero llamado jobfile.sh como la siguiente.


#!/bin/bash
#----------------------- Start job description -----------------------

#@ arch = 
#@ total_tasks = 
#@ wall_clock_limit  = 
#@ output = 
#@ error = 


#------------------------ End- job description ------------------------
#-------------------------- Start execution --------------------------
# Run our program

srun ./media 2 8

#--------------------------- End execution ---------------------------


Comenzaremos a ir rellenando según las explicaciones.

  • @arch define donde queremos que se ejecute nuestro programa, si en nodos Intel o nodos Power, rellenando con los valores "intel", o "power". (En el caso del video ponemos "power", ya que el ejecutable media ha sido compilado desde un nodo Power.)
  • @total_task define el numero de procesadores que vamos a solicitar para la ejecución de nuestro trabajo. En este caso solo pongo "1", ya que mi programa media es un programa de ejemplo que no contiene paralelismo.
  • @wall_clock_limit define el tiempo máximo de ejecución de nuestro programa, es importante rellenar este valor, con una estimación de la duración de la ejecución de nuestro programa más una pequeña holgura para tener margen de error. Si rellenamos esta directiva con un valor muy alto, el proceso se verá penalizado por el gestor de colas en la espera anteas de su ejecución, y si el valor de la directiva es demasiado pequeño, podremos abortar el proceso antes de que finalice su ejecución.
  • @output define la ubicación del fichero donde queremos que se vuelquen los resultados de salida de nuestra ejecución. Si utilizamos %j en el nombre del fichero, será sustituido por el identificador del proceso.
  • @error define la ubicación del fichero donde queremos que se vuelquen los resultados de error de nuestra ejecución. Si utilizamos %j en el nombre del fichero, será sustituido por el identificador del proceso.

La ejecución de "media" la establecemos en el "jobfile" mediante srun ./media 2 8 (calculando así la media entre 2 y 8). Es importante destacar que srun es un comando de Slurm (el gestor de colas de Magerit) que ejecuta un trabajo paralelo, en este caso como no hay paralelismo no sería necesario. Para entender mejor lo que hace srun, podemos consultar el tutorial Uso de MPI y OpenMP.


Nota
Las únicas directivas obligatorias para la definición de un "jobfile", son total_task y wall_clock_limit, pero es recomendable usar las demás directivas que acabamos de explicar.

Una vez guardado el "jobfile", mandaremos nuestro trabajo a ejecución mediante el comando de slurm jobsubmit <nombre de mi jobfile >.sh en mi caso jobfile.sh

Cuando el trabajo haya finalizado podremos recoger los resultados de la ejecución en los ficheros de salida y error que se hayan volcado en la ubicación que hayamos puesto en las directivas "output" y "error".


En el vídeo veremos que volvemos a abrir el archivo jobfile.sh para editarlo y volver a mandarlo a ejecución a Magerit. Esto se hace para explicar las siguientes directivas:

  • @requeue que define si el trabajo es re-encolado en caso de fallo hardware, sus opciones poisbles son "yes" y "no", y por defecto si no se pone esta directiva se toma el valor "no". Cabe destacar que el consumo final del trabajo será la suma de el primer intento más los sucesivos re-encolados.
  • @task_per_node Indica cuántas tareas deben asignarse como máximo en cada nodo. El gestor de colas asignará bloques de tasks_per_node tareas a cada uno de los nodos asignados.
  • @initialdir Permite establecer el directorio de trabajo del script y todas las rutas especificadas (output, error...) se consideran relativas a este directorio inicial. En el video se ve que completo esta directiva con el valor "Carpeta", por lo que antes de enviar el jobfile a ejecución, tendré que crear dicha carpeta en caso de que no exista ya, e introducir el ejecutable media en dicha carpeta. Ya que ahora, "Carpeta" es nuestro directorio de trabajo.

Nota
Existe una documentación más detalla de las directivas en el "Manual de usuario de Magerit"

Nota
Existe una directiva @cpus_per_task que es utilizada para el uso de OpenMP y por lo tanto se explicará en el capítulo de "Uso de MPI y OpenMP"