AIC P 9 10 Barreras en Multiprocesadores Objetivo
AIC – P 9 -10 Barreras en Multiprocesadores
Objetivo • Programar el acceso a variables compartidas en multiprocesadores • Uso de cerrojos en el acceso a las variables • Problema de la falsa compartición (false sharing) • Desarrollo de códigos paralelos
Macros ANL - Generales • Permite la creación de varios Hilos • CREATE(nombre_funcion) Crea un hilo que ejcuta una función. • WAIT_FOR_END(numero) Espera hasta que acaben los hijos antes de entrar en otr a sección temporal. • CLOCK(variable) Tiempo. Lo usaremos para medir el rendimiento.
Macros ANL - Cerrojos • LOCKDEC(nombre_cerrojo) declara un cerrojo con el nombre_cerrojo. • LOCKINIT(nombre_cerrojo) inicializa nombre_cerrojo a un estado libre. macro antes de lanzar ningún otro proceso. • LOCK(nombre_cerrojo) toma posesión del cerrojo nombre_cerrojo. La ejecución se para hasta que se consigue el cerrojo. • UNLOCK(nombre_cerrojo) libera el cerrojo para que otros lo puedan adquirir.
Macros ANL – Barreras • ALOCKDEC(nombre_cerrojo, tamaño_vector) cerrojo con el nombre_cerrojo. Protege a un vector de tamaño_vector. • ALOCKINIT(nombre_cerrojo, tamaño_vector) inicializa el cerrojo nombre_cerrojo a un estado libre. Este cerrojo protege a un vector de tamaño_vector. • ALOCK(nombre_cerrojo, elemento) toma posesión del cerrojo nombre_cerrojo que protege al elemento de un vector. La ejecución se para aquí hasta que se consigue el cerrojo. • AULOCK(nombre_cerrojo, elemento) libera el cerrojo para que otros lo puedan adquirir.
Makefile y variables de entorno • Abrimos sesión en “limes”, alumno@maquina: ~> ssh –X limes • Creamos un directorio para nuestra aplicación y bajamos el código de ejemplo alumno@limes: ~> mkdir barrera_1 alumno@limes: ~/barrera_1> wget http: //informatica. uv. es/docencia/iiguia/asignatu/2000/AC/lab/ejemplo. c • Copiamos un makefile para modificarlo alumno@limes: ~/barrera_1> cp $LIMESDIR/applications/fft/makefile. • Usando un editor, cambiamos TARGET y las variables APPCS • Nota: Para usar vi comodamente, copiar el archivo alumno@limes: ~> wget www. uv. es/serhocal/. vimrc
Barreras “Sense-Reversing” • Partimos de una matriz de 4 filas y n columnas (n procesadores) • Se realizan 4 iteraciones • Primera Iteración: se rellena la primera fila con el número de cada procesador • Resto: se asigna a cada elemento de la fila i el elemento de la fila i-1 pero de la columna anterior • Al final de cada iteracción hay que poner una barrera
Barreras “Sense-Reversing” • Al final del programa, sacamos por pantalla el resultado. • Implementación de barrera simple • Lanzar el algoritmo usando barrera y sin usarla. • Visto en teoría • Programamos en C, compilamos con gcc usando el makefile
Barreras – Código I /* Programa de ejemplo */ #include <stdio. h> #include <math. h> #include <unistd. h> #define LONGIT 10000 #define PROC_MAX 64 /* Longitud del vector */ /* Numero de procesadores */ MAIN_ENV /* No es necesario con Limes */ unsigned int inicio, final; double vector[LONGIT]; /* Vector compartido*/ int Pr. Id; /* Identificador de proceso */ LOCKDEC(Pr. Id. Lock) /* Cerrojo para la variable anterior */
Barreras – Código II /* Este es la rutina ejecutada por cada hilo lanzado */ void Proceso(void) { int i, trozo, pr; LOCK(Pr. Id. Lock); pr=Pr. Id; /* Cada identificador debe ser unico */ Pr. Id++; /* por eso se protege con un cerrojo */ UNLOCK(Pr. Id. Lock); trozo=LONGIT/PROC_MAX; for (i=trozo*pr; (i<trozo*(pr+1)) && (i<LONGIT) ; i++) /* Consecutivo */ /*for (i=pr; i<LONGIT; i=i+PROC_MAX)*/ /* Entrelazado */ { vector[i]=M_PI; /* valor de pi */ vector[i]=sqrt(vector[i]); /* Gastamos tiempo */ } }
Barreras – Código III main() { int i; MAIN_INITENV(); /* Inicio de la parte principal */ memsim_init(); /* Inicia la memoria del simulador */ CLOCK(inicio); /* tomamos cuenta del tiempo inicial*/ Pr. Id=0; /* El padre es el proceso # 0 */ LOCKINIT(Pr. Id. Lock); /* Inicializa cerrojo */ for (i=1; i<PROC_MAX; i++) { CREATE(Proceso); /* Este bucle lanza PROC_MAX-1 hilos*/ } Proceso(); /* El padre tambien hace su faena */ WAIT_FOR_END(PROC_MAX-1); /* Esperamos a los hijos */ CLOCK(final); /* Medimos el tiempo al terminar */ printf("%14 ldn", final-inicio); MAIN_END; /* Fin de la parte principal */ }
Barreras en árbol • Más difícil de implementar • Más eficiente Proceso raíz 1 2 4 3 5 6 Procesadores hoja 7
Barreras en árbol - Implementación • Seudo-algoritmo Al inicio cada proceso pone su contador y su variable de liberación a cero. Cuando un proceso “hoja” (sin hijos) entra en la barrera debe incrementar el contador de su padre y se espera hasta la liberación. Cuando un proceso con hijos entra en la barrera se espera a que su contador alcance el número de hijos que tiene. Cuando el contador de un proceso con hijos alcanza el número de hijos que tiene, entonces incrementa el contador de su padre, pone el suyo propio a cero y se espera hasta que sea liberado. Cuando el contador del proceso raíz (proceso 1) es igual al número de hijos que tiene, entonces pone a uno la variable de liberación de cada uno de sus hijos saliendo de la barrera. Cuando un proceso detecta que su variable de liberación está a uno, pone a cero la suya y a uno la de sus hijos saliendo de la barrera.
- Slides: 13