M.C. Gerardo Beltrán Gutiérrez
UNIVERSIDAD AUTÓNOMA DE SINALOA Facultad de Informática Culiacán
Licenciatura en Informática
Taller de Programación
Avanzadas
Programación con OpenMP
¿Qu´e es OpenMP?
El OpenMP Application Program Interface (API) es:
– Conjunto de directivas de compilación, bibliotecas y
variables de entorno que permiten expresar el
paralelismo de tareas en programas escritos en C, C++
y Fortran.
– Toda la información está disponible en la página web:
¿Quién define OpenMP?
El estándar es definido y revisado por el comité
OpenMP Architecture Review Board compuesto por:
– U.S. DoD: Aeronautical Systems Center
– cOMPunity (Comunidad de usuarios de OpenMP)
– Edinburgh Parallel Computing Centre (EPCC)
– Laboratorio NASA Ames
– ST Microelectronics: The Portland Group
– Fujitsu
¿Quién define OpenMP?
– Hewlett Packard
– International Business Machines (IBM)
– Intel Corporation
– KAI Software Lab (KSL)
– NEC Corporation
– Silicon Graphics Inc. (SGI)
– Sun Microsystems
– Universidad RWTH Aachen
Antecedentes de OpenMP
Antes de la introducción de OpenMP:
– Cada fabricante tenía su propio “estándar”
– Los programas tenían portabilidad nula
– El estándar ANSI X3H5 fracasó por falta de apoyo
– Se perdió interés en las máquinas SMP
Antecedentes de OpenMP
El estándar OpenMP se introdujo para resolver
lo anterior:
– En 1997 se publicó la versión 1.0
– En 1999 se publicó la versión 1.1
– En 2000 se publicó la versión 2.0
– En 2005 se publicó la versión 2.5
Características fundamentales de OpenMP
• OpenMP se fundamenta en directivas y cláusulas:
– Las directivas especifican qué hacer
– Las cláusulas indican cómo hacerlo
• Tipos de directivas en OpenMP:
– Directivas de distribución de trabajo
– Directivas de sincronización de tareas
• Tipos de cláusulas en OpenMP:
– Cláusulas de datos
– Cláusulas de comportamiento
– Cláusulas de sincronía
Características fundamentales de OpenMP
• Ventajas de OpenMP:
– Sencillo: no requiere el envío de mensajes como en MPI
– La descomposición de los datos es automática
– Admite la paralelización incremental del código
– Mismo código fuente para las versiones serial y paralela
– Permite implementar granularidad gruesa y fina
– Elevada portabilidad
Características fundamentales de OpenMP
• Inconvenientes de OpenMP:
– Requiere un compilador que entienda OpenMP
– El estándar sólo contempla C y Fortran
– Sólo es eficiente en máquinas de memoria compartida
– En general la eficiencia paralela es baja
– La escalabilidad está limitada por el acceso a memoria
– Aumentar la eficiencia requiere reestructurar el código
Compiladores que soportan OpenMP
– SGI MIPSpro
– IBM XL
– Sun Studio
– Portland Group Compilers and Tools
– Absoft Pro FortranMP
– Lahey/Fujitsu Fortran 95
– Fujitsu-Siemens Fortran 95 (Solaris)
Compiladores que soportan OpenMP
– Intel Software Development Products
– PathScale
– GNU GCC (a partir de la versión 4.2)
– HP
Compilando con GNU GCC
El soporte para OpenMP ha de ser activado:
• Versión serial de un programa:
[gerardo@profesor~]$ gcc ejemplo.c -o ejemplo
• Versión paralela de un programa:
– [gerardo@profesor~]$ gcc -fopenmp ejemplo.c -o ejemplo
–
• En casi todos los compiladores la opción es -
openmp
El modelo de programación en OpenMP
• El paralelismo en OpenMP se especifica a través de directivas que se insertan en el código de C.
• Básicamente un programa en OpenMP es un programa secuencias que se añaden directivas OpenMP en el punto adecuado.
• En Lenguaje C una directiva OpenMP tiene la forma:
• #pragma omp <directiva OpenMP especificada>
• Todos los programas OpenMP deben incluir el archivo cabecera #include <omp.h>
El modelo de programación en OpenMP
• Una compilador secuencias ignora la sentencia
#pragma y generará el código ejecutable secuencial
habitual.
• Un compilador OpenMP reconocerá la directiva
#pragma y generará un código ejecutable
paralelizado que se podrá ejecutar en una máquina
de memoria compartida.
• OpenMP implementa un paralelismo basado en
múltiples hebras o hilos sobre el paradigma de
programación de memoria compartida
El modelo de programación en OpenMP
• La ejecución de los múltiples hilos o hebras sigue el
modelo fork-join.
El modelo de programación en OpenMP
• Conceptualmente, la programación de aplicaciones
con OpenMP consiste en definir zonas del código
que serán ejecutadas por un número determinado de
hilos.
• Estas zonas de código reciben el nombre de
regiones paralelas.
• Todos los programas OpenMP comienzan con una
única hebra, llamada maestra.
Ejemplo
#include <stdio.h>
#include <omp.h>
int main( int argc, char * argv[] ) {
printf("Hola mundo \n");
#pragma omp parallel
{
printf("Hola desde desde el hilo \n");
}
return 0;
}
Variable de Ambiente
Establece del numero máximo de hilos de
ejecución
$ export OMP_NUM_THREADS=2
Biblioteca de funciones
• Establece el numero de hilos a utilizar en la siguiente región paralela
void omp_set_num_threads(int num_hilos);
• Obtiene el ID del hilo actual
• int omp_get_thread_num();
• Obtiene el numero CPUs/cores disponibles
• int omp_get_num_threads();
• obtiene el numero total de hilos requeridos
• int omp_get_num_procs();
•
Ejemplo
#include <stdio.h>
#include <omp.h>
int main(int argc, char *argv[]){
#pragma omp parallel {
int IdHilo,NumHilos, NumCPUs;
/* obtiene el ID de la hilo actual */
IdHilo = omp_get_thread_num();
NumHilos = omp_get_num_threads();
NumCPUs = omp_get_num_procs();
printf("Hola yo soy el hilo %d \n", IdHilo);
if (IdHilo == 0) {
printf("Num. de CPUs = %d \n", NumCPUs);
printf("Num. de Hilos Totales = %d \n", NumHilos);
}
}
return(0);
}
Ejercicio
• Desarrolle un programa que lea en paralelo 4
archivos que contienen una serie de números
de tipo flotante, es necesario saber cual es el
valor menor de cada archivo además de
saber cual es el mayor de los 4.
• Procese los archivos en paralelo.
Gestión de Datos
• La compartición de variables es el punto clave en un
sistema paralelo de memoria compartida, por lo que es
necesario controlar correctamente el ámbito de cada
variable.
• Las variables globales son compartidas por todos los
hilos. Sin embargo, algunas variables deberán ser propias
de cada hilo, privadas.
• Para poder especificar adecuadamente el ámbito de
validez de cada variable, se añaden una serie de
cláusulas a la directiva parallel, en las que se indica el
carácter de las variables que se utilizan en dicha región
paralela.
Gestión de Datos
• Para la gestión de datos en las directivas
paralelas se dispone de las siguientes cláusulas.
• private (lista_variables). Indica que la Lista de
variables es local a cada hilo sin inicializar.
• shared (Lista_variables). Indica que las variables de
la lista serán compartidas por todos los hilos de
ejecución. Sólo existe una copia, y todos los hilos
acceden y modifican dicha copia.
Gestión de Datos
Ejemplo
x = 2;
y = 1;
z = 3;
#pragma omp parallel
shared(y) private(x,z)
{ z = x * x + 3;
x = y * 3 + z;
}
printf(“x = %d \n”, x);
X no está
inicializada
X no mantiene
el nuevo valor
Gestión de Datos
• Se declaran objetos completos: no se puede
declarar un elemento de un arreglo como compartido
y el resto como privado.
• Por defecto, las variables son shared.
• Cada hilo utiliza su propia pila, por lo que las
variables declaradas en la propia región paralela son
privadas.
Gestión de Datos
• Para la gestión de datos en las directivas
paralelas se dispone de las siguientes cláusulas.
• firstprivate (Lista_variables). Es similar a private
solo que las variables se inicializan al entrar a los
hilos paralelos con los valores que contenía antes de
la directiva paralela.
Gestión de Datos
Ejemplo:
X = Y = Z = 2;
#pragma omp parallel
private(Y) firstprivate(Z)
{
...
X = Y = Z = 1;
}
...
valores dentro de la
región paralela? X =2 Y =? Z =2
valores fuera de la
región paralela? X = 1 Y = 2 Z = 2
Gestión de Datos
default (none / shared)
none: obliga a declarar explícitamente el ámbito de
todas las variables. Útil para no olvidarse de declarar
ninguna variable (provoca error al compilar).
shared: las variables sin declarar son shared (por
defecto).
Clausula if
if (expresión)
• La región paralela sólo se ejecutará en paralelo si la
expresión es distinta de 0.
• Dado que paralelizar código implica costos añadidos
(generación y sincronización de los hilos), la cláusula
permite decidir en ejecución si merece la pena la
ejecución paralela según el tamaño de las tareas (por
ejemplo, en función del tamaño de los vectores a
procesar).
Clausula num_threads
num_threads(expresión)
Indica el número de hilos que hay que utilizar en la
región paralela.
Distribución de tareas
• Las opciones de que disponemos son:
• Directiva for, para repartir la ejecución de las iteraciones
de un ciclo entre todos los hilos (número de iteraciones
conocida).
• Directiva sections, para definir trozos o secciones de una
región paralela a repartir entre los hilos.
• Directiva single, para definir un trozo de código que sólo
debe ejecutar un hilo.
Directiva for
#pragma omp parallel [...]
{ …
#pragma omp for [clausulas]
for (i=0; i<1000; i++) A[i] = A[i] + 1;
…
}
0..249
250..499
500..749
759..999
barrera
Directiva for
Las directivas parallel y for pueden juntarse en
#pragma omp parallel for
cuando la región paralela contiene únicamente un ciclo.
La decisión de paralelizar un ciclo debe tomarse tras el
correcto análisis de las dependencias.
Directiva for
Dependencias de datos
a[0] = val;
for( i = 1; i < N; i++ ){
a[i] = a[i-1] + 1;
}
¿Es posible paralelizar este fragmento de código?
Directiva for
Serial Paralelo for (i=0; i<N; i++) Z[i] = a * X[i] + b;
#pragma omp parallel for for (i=0; i<N; i++) Z[i] = a * X[i] + b;
Directiva for
• El ciclo puede paralelizarse sin problemas, ya que
todas las iteraciones son independientes.
• La directiva parallel for implica la generación de
hilos, que se repartirán la ejecución del ciclo.
• Hay una barrera de sincronización implícita al final
del ciclo. El máster retoma la ejecución cuando todos
terminan.
• El índice del ciclo, i, es una variable privada (no es
necesario declararla como tal).
Directiva for
Se ejecutará en paralelo el ciclo externo, y los hilos ejecutarán el ciclo interno.
Las variables j y X deben declararse como privadas.
Serial Paralelo
for (i=0; i<N; i++) for (j=0; j<M; j++){ X = B[i][j] * B[i][j]; A[i][j] = A[i][j] + X; C[i][j] = X * 2 + 1; }
#pragma omp parallel for private (j,X) for (i=0; i<N; i++) for (j=0; j<M; j++){ X = B[i][j] * B[i][j]; A[i][j] = A[i][j] + X; C[i][j] = X * 2 + 1; }
Directiva for
Los hilos ejecutarán en paralelo el ciclo interno (el externo se ejecuta en serie).
La variable X debe declararse como privada.
Serial Paralelo for (i=0; i<N; i++) for (j=0; j<M; j++){ X = B[i][j] * B[i][j]; A[i][j] = A[i][j] + X; C[i][j] = X * 2 + 1; }
for (i=0; i<N; i++) #pragma omp parallel for private (X) for (j=0; j<M; j++){ X = B[i][j] * B[i][j]; A[i][j] = A[i][j] + X; C[i][j] = X * 2 + 1; }
Directiva for
Las cláusulas de ámbito de una directiva for son (como
las de una región paralela):
private, firstprivate, default
Y se añade más cláusula:
lastprivate
reduction
Directiva for
lastprivate(Lista_variables)
Permite guardar el valor de la variable privada
correspondiente a la última iteración del ciclo.
Ejercicio
• Se cuenta con un archivo que contiene un
numero determinado de datos de tipo
flotante, los cuales se requieren procesar en
un programa para determinar cuantos son
primos.
Tarea
• Desarrolle el algoritmo de multiplicación de
matrices utilizando las OpenMP, los datos de
las matrices están contenidos en un par de
archivos.
Directiva for
reduction(operador:Lista_variables)
Las operaciones de reducción son típicas en muchas
aplicaciones paralelas. Utilizan variables a las que
acceden todos los procesos y sobre las que se efectúa
alguna operación de acumulación. Ejemplo: En la suma
de los elementos de un vector, es capaz de acumular
todos los resultados parciales y sumarlos al final.
Operador pueden ser: +, -, *
Directiva sections
• Permite usar paralelismo de función. Reparte
secciones de código independiente a hilos diferentes.
• Cada sección paralela es ejecutada por un sólo hilo,
y cada hilo ejecuta ninguna o alguna sección.
• Una barrera implícita sincroniza el final de las
secciones o tareas.
Directiva sections
Ejemplo:
#pragma omp parallel [clausulas]
{
#pragma omp sections [clausulas]
{
#pragma omp section
funcion_A();
#pragma omp section
funcion_B();
#pragma omp section
funcion_C();
}
}
Directiva sections
Al Igual que en el caso del pragma for, si la región
paralela sólo tiene secciones, pueden juntarse ambos
pragmas en uno solo:
#pragma omp parallel sections [cláusulas]
Directiva single
Define un bloque básico de código, dentro de una
región paralela, que no debe ser paralelizado; es
decir, que debe ser ejecutado por un único hilo.
(por ejemplo, una operación de entrada/salida).
No se especifica qué hilo ejecutará la tarea.
Top Related