Practica1 AC
Practica1 AC
Practica1 AC
(b) ¿Cuántos cores físicos y cuántos cores lógicos tiene atcgrid4?, ¿cuántos tienen atcgrid1, atcgrid2 y atcgrid3?
y ¿cuántos tiene el PC? Razonar las respuestas
RESPUESTA:
Atcgri4: tiene 16 cores físicos de 2 hilos en cada socket (2*16 = 32), lo que compone 64 cores lógicos
Atcgrid1/2/3: tiene 6 cores físicos de 2 hilos en cada socket (2*6 = 12), lo que compone 24 cores lógicos
PC: tiene 4 cores físicos de 1 hilo por socket (1*4 = 4), lo que compone 4 cores lógicos ya que hay un solo socket
(b) Justificar el número de “Hello world” que se imprimen en pantalla teniendo en cuenta la salida que devuelve
lscpu en el PC.
RESPUESTA:
El programa imprime el identificador del hilo, por lo tanto, como hay 4 hilos, imprime del primero al último
identificador junto con “¡¡¡Hello world!!!”
3. Copiar el ejecutable de HelloOMP.c que ha generado anteriormente y que se encuentra en el directorio ejer2
del PC al directorio ejer2 de su home en el front-end de atcgrid. Ejecutar este código en un nodo de cómputo
de atcgrid (de 1 a 3) a través de cola ac del gestor de colas utilizando directamente en línea de comandos (no use
ningún script):
(d) ¿Qué orden srun usaría para que HelloOMP utilice todos los cores físicos de atcgrid4 (se debe imprimir un
único mensaje desde cada uno de ellos)?
srun -p ac4 -n1 –cpus-per-task=32 –hint=nomultithread HelloOMP
4. Modificar en su PC HelloOMP.c para que se imprima “world” en un printf distinto al usado para “Hello”. En
ambos printf se debe imprimir el identificador del thread que escribe en pantalla. Nombrar al código resultante
HelloOMP2.c. Compilar este nuevo código en el PC y ejecutarlo. Copiar el fichero ejecutable resultante al
front-end de atcgrid (directorio ejer4). Ejecutar el código en un nodo de cómputo de atcgrid usando el script
script_helloomp.sh del seminario (el nombre del ejecutable en el script debe ser HelloOMP2).
(a) Utilizar: sbatch script_helloomp.sh. Adjuntar capturas de pantalla que muestren el nuevo código, la
compilación, el envío a la cola de la ejecución y el resultado de esta ejecución tal y como la devuelve el gestor de
colas.
3
Cuaderno de prácticas de Arquitectura de Computadores, Grados Ingeniería Informática
RESPUESTA:
(b) ¿Qué nodo de cómputo de atcgrid ha ejecutado el script? Explicar cómo ha obtenido esta información.
RESPUESTA: Lo ha ejecutado atcgrid1. Nos lo indica el propio script con la variable
$SLURM_JOB_NODELIST ( “Nodos asignados al trabajo: ” )
(c) ¿Qué órdenes para el gestor de colas slurm incluye el script? Explicar cómo ha obtenido esta información.
RESPUESTA:
Las ordenes vienen dadas en el propio script.
1. Asignar al trabajo un nombre
SBATCH --job-name=helloOMP
2. Asignar el trabajo a una partición (cola)
SBATCH --partition=ac
3. Asignar el trabajo a un account
SBATCH --account=ac
4. Para que el trabajo no comparta recursos
SBATCH --exclusive
5. Para que se genere un único proceso del sistema operativo que pueda usar un máximo de 12 núcleos
SBATCH --ntasks 1 --cpus-per-task 12
(d) Haga los cambios necesarios en el script para que se utilice atcgrid4. Comentar los cambios realizados y los
motivos por los que se han hecho.
RESPUESTA: En el script se debe modificar la orden 2 ( Mostrada en el apartado anterior ) y se indica que se
use la partición ac4 en vez de ac, para que así se use atcgrid4. ( SBATCH –partition=ac4 )
NOTA: Utilizar siempre con sbatch las opciones -n1 y -c, --exclusive y, para usar cores físicos y no
lógicos, no olvidar incluir --hint=nomultithread. Utilizar siempre con srun, si se usa fuera de un script,
las opciones -n1 y -c y, para usar cores físicos y no lógicos, no olvidar incluir --hint=nomultithread.
Recordar que los srun dentro de un script heredan las opciones incluidas en el sbatch que se usa para enviar el
script a la cola slurm. Se recomienda usar sbatch en lugar de srun para enviar trabajos a ejecutar a través
slurm porque éste último deja bloqueada la ventana hasta que termina la ejecución, mientras que usando sbatch
la ejecución se realiza en segundo plano.
5
Cuaderno de prácticas de Arquitectura de Computadores, Grados Ingeniería Informática
(c) ¿Qué información devuelve exactamente la función clock_gettime()en la estructura de datos descrita en
el apartado (b)? ¿qué representan los valores numéricos que devuelve?
RESPUESTA: Devuelve un struct con una hora en específico, representando el número de segundos y
nanosegundos transcurridos.
7. Rellenar una tabla como la Tabla 1 en una hoja de cálculo con los tiempos de ejecución del código
SumaVectores.c para vectores locales, globales y dinámicos (se pueden obtener errores en tiempo de ejecución o
de compilación, ver ejercicio 9). Obtener estos resultados usando scripts (partir del script que hay en el
seminario). Debe haber una tabla para un nodo de cómputo de atcgrid con procesador Intel Xeon E5645 y otra
para su PC en la hoja de cálculo. En la columna “Bytes de un vector” hay que poner el total de bytes reservado
para un vector. (NOTA: Se recomienda usar en la hoja de cálculo el mismo separador para decimales que usan
los códigos al imprimir ‒”.”‒. Este separador se puede modificar en la hoja de cálculo.)
RESPUESTA:
MI PC:
ATCGRID:
Nº de Bytes de un Tiempo para vect. Tiempo para vect. Tiempo para vect.
Componentes vector locales globales dinámicos
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
8. Con ayuda de la hoja de cálculo representar en una misma gráfica los tiempos de ejecución obtenidos en atcgrid
y en su PC para vectores locales, globales y dinámicos (eje y) en función del tamaño en bytes de un vector (por
tanto, los valores de la segunda columna de la tabla, que están en escala logarítmica, deben estar en el eje x).
Utilizar escala logarítmica en el eje de ordenadas (eje y). ¿Hay diferencias en los tiempos de ejecución?
RESPUESTA:
9. Contestar a las siguientes preguntas:
(a) Cuando se usan vectores locales, ¿se obtiene error para alguno de los tamaños?, ¿a qué cree que es debido lo
que ocurre? (Incorporar volcados de pantalla como se indica en las normas de prácticas)
RESPUESTA:
(b) Cuando se usan vectores globales, ¿se obtiene error para alguno de los tamaños?, ¿a qué cree que es debido lo
que ocurre? (Incorporar volcados de pantalla como se indica en las normas de prácticas)
RESPUESTA:
(c) Cuando se usan vectores dinámicos, ¿se obtiene error para alguno de los tamaños?, ¿a qué cree que es debido
lo que ocurre? (Incorporar volcados de pantalla como se indica en las normas de prácticas)
RESPUESTA:
10. (a) ¿Cuál es el máximo valor que se puede almacenar en la variable N teniendo en cuenta su tipo? Razonar
respuesta.
RESPUESTA:
(b) Modificar el código fuente C (en el PC) para que el límite de los vectores cuando se declaran como variables
globales sea igual al máximo número que se puede almacenar en la variable N y generar el ejecutable. ¿Qué
ocurre? ¿A qué es debido? (Incorporar volcados de pantalla que muestren lo que ocurre)
RESPUESTA:
7
Cuaderno de prácticas de Arquitectura de Computadores, Grados Ingeniería Informática
Listado 1. Código C que suma dos vectores. Se generan aleatoriamente las componentes para vectores de tamaño mayor
que 8 y se imprimen todas las componentes para vectores menores que 10.
/* SumaVectoresC.c
Suma de dos vectores: v3 = v1 + v2
Para compilar usar (-lrt: real time library, no todas las versiones de gcc necesitan que se incluya
-lrt):
gcc -O2 SumaVectores.c -o SumaVectores -lrt
gcc -O2 -S SumaVectores.c -lrt //para generar el código ensamblador
//Sólo puede estar definida una de las tres constantes VECTOR_ (sólo uno de los ...
//tres defines siguientes puede estar descomentado):
//#define VECTOR_LOCAL // descomentar para que los vectores sean variables ...
// locales (si se supera el tamaño de la pila se ...
// generará el error "Violación de Segmento")
//#define VECTOR_GLOBAL // descomentar para que los vectores sean variables ...
// globales (su longitud no estará limitada por el ...
// tamaño de la pila del programa)
#define VECTOR_DYNAMIC // descomentar para que los vectores sean variables ...
// dinámicas (memoria reutilizable durante la ejecución)
#ifdef VECTOR_GLOBAL
#define MAX 33554432 //=2^25
double v1[MAX], v2[MAX], v3[MAX];
#endif
int i;
struct timespec cgt1,cgt2; double ncgt; //para tiempo de ejecución
v3 = (double*) malloc(N*sizeof(double));
if ( (v1==NULL) || (v2==NULL) || (v3==NULL) ){
printf("Error en la reserva de espacio para los vectores\n");
exit(-2);
}
#endif
//Inicializar vectores
if (N < 9)
for (i = 0; i < N; i++)
{
v1[i] = N * 0.1 + i * 0.1;
v2[i] = N * 0.1 - i * 0.1;
}
else
{
srand48(time(0));
for (i = 0; i < N; i++)
{
v1[i] = drand48();
v2[i] = drand48(); //printf("%d:%f,%f/",i,v1[i],v2[i]);
}
}
clock_gettime(CLOCK_REALTIME,&cgt1);
//Calcular suma de vectores
for(i=0; i<N; i++)
v3[i] = v1[i] + v2[i];
clock_gettime(CLOCK_REALTIME,&cgt2);
ncgt=(double) (cgt2.tv_sec-cgt1.tv_sec)+
(double) ((cgt2.tv_nsec-cgt1.tv_nsec)/(1.e+9));
#ifdef VECTOR_DYNAMIC
free(v1); // libera el espacio reservado para v1
free(v2); // libera el espacio reservado para v2
free(v3); // libera el espacio reservado para v3
#endif
return 0;
}