OpenMP

De Wikipedia, la enciclopedia libre
Saltar a: navegación, búsqueda

OpenMP es una interfaz de programación de aplicaciones (API) para la programación multiproceso de memoria compartida en múltiples plataformas. Permite añadir concurrencia a los programas escritos en C, C++ y Fortran sobre la base del modelo de ejecución fork-join. Está disponible en muchas arquitecturas, incluidas las plataformas de Unix y de Microsoft Windows. Se compone de un conjunto de directivas de compilador, rutinas de biblioteca, y variables de entorno que influyen el comportamiento en tiempo de ejecución.

Definido conjuntamente por proveedores de hardware y de software, OpenMP es un modelo de programación portable y escalable que proporciona a los programadores una interfaz simple y flexible para el desarrollo de aplicaciones paralelas, para plataformas que van desde las computadoras de escritorio hasta supercomputadoras. Una aplicación construida con un modelo de programación paralela híbrido se puede ejecutar en un cluster de computadoras utilizando OpenMP y MPI, o a través de las extensiones de OpenMP para los sistemas de memoria distribuida.

Modelo de ejecución[editar]

OpenMP se basa en el modelo fork-join, paradigma que proviene de los sistemas Unix, donde una tarea muy pesada se divide en K hilos (fork) con menor peso, para luego "recolectar" sus resultados al final y unirlos en un solo resultado (join).

Cuando se incluye una directiva de compilador OpenMP esto implica que se incluye una sincronización obligatoria en todo el bloque. Es decir, el bloque de código se marcará como paralelo y se lanzarán hilos según las características que nos dé la directiva, y al final de ella habrá una barrera para la sincronización de los diferentes hilos (salvo que implícitamente se indique lo contrario con la directiva nowait). Este tipo de ejecución se denomina fork-join.

OpenMP también soporta el modelo de paralelismo de tareas. El equipo de hilos del bloque de código paralelo ejecuta las tareas especificadas dentro de dicho bloque. Las tareas permiten un paralelismo asíncrono. Desde la versión 4.0 lanzada en 2013 admite la especificación de dependencias entre tareas, relegando a la biblioteca de tiempo de ejecución de OpenMP el trabajo de planificar las tareas y ponerlas en ejecución. Los hilos de ejecución irán ejecutando las tareas a medida que éstas estén disponibles (sus dependencias ya estén satisfechas). El uso de tareas da lugar a sincronización con una granularidad más fina. El uso de barreras no es estrictamente necesario, de manera que los hilos pueden continuar ejecutando tareas disponibles sin necesidad de esperar a que todo el equipo de hilos acabe un bloque paralelo. El uso de tareas con dependencias crea un grafo, pudiéndose aplicar propiedades de grafos a la hora de escoger tareas para su ejecución.

Salvo uso de implementaciones hardware de la biblioteca de tiempo de ejecución OpenMP (p.ej. en FPGAs), los sobrecostes de las tareas es mayor. Éste sobrecoste ha de ser amortizado mediante el potencial paralelismo adicional que las tareas exponen.

Sintaxis básica[editar]

La sintaxis básica que nos encontramos en una directiva de OpenMP es para C/C++:

# pragma omp <directiva> [cláusula [ , ...] ...]

para Fortran:

!$OMP  PARALLEL <directiva> [cláusulas]
    [ bloque de código ]
!$OMP END <directiva>

A continuación se presentan algunas de las directivas disponibles y cláusulas aplicables a las directivas que ofrece OpenMP.

Directivas[editar]

También se suelen llamar constructores:

  • parallel: Esta directiva nos indica que la parte de código que la comprende puede ser ejecutada por varios hilos. Se crea una tarea implícita para cada hilo perteneciente al equipo de hilos creado por el parallel.

En este fragmento de código se trata de explotar el potencial del paralelismo en una tarea de una serie geométrica que tiende al infinito para la ecuación:

/* Juan Carlos Lanuza Lazo
   MGA-NI 27 / Apr / 2017
   
   Ejemplo de sumatoria paralela de una serie Armonica
*/
#include <omp.h>
#include <stdio.h>

#define LIMIT 1000000000000

int main(void)
{
        double serie = 0;
        long long i;
        #pragma omp parallel
        {
                #pragma omp for reduction(+:serie)
                for(i = 1;i <= LIMIT;i++)
                serie += 1.0/i;
        }

        printf("Valor de la Serie: %.5f\n",serie);
return 0;
}
  • for: El equipo de hilos que se encuentra con el for ejecuta una o más fracciones de iteraciones como resultado de dividir el bucle delimitado por la directiva entre los hilos del equipo (el tamaño de cada partición dependerá de las cláusulas opcionales añadidas al for). Su formato es:
    #pragma omp parallel for [cláusula, ... , cláusula]
    
    . Cada fracción de iteraciones es una tarea implícita (el programador no ha particionado el bucle manualmente y anotado una tarea por cada trozo).
  • section y sections: Indica secciones que pueden ejecutarse en paralelo pero por un único hilo.
  • single: La parte de código que define esta directiva, sólo se puede ejecutar un único hilo de todos los lanzados, y no tiene que ser obligatoriamente el hilo padre.
  • master: La parte de código definida, sólo se puede ejecutar por el hilo padre.
  • critical: Sólo un hilo puede estar en esta sección. Definen secciones críticas o condiciones de carrera.
  • atomic: Se utiliza cuando la operación atañe a sólo una posición de memoria, y tiene que ser actualizada solo por un hilo simultáneamente. Operaciones tipo x++ o --x son las que usan esta cláusula.
  • flush: Esta directiva resuelve la consistencia, al exportar a todos los hilos un valor modificado de una variable que ha realizado otro hilo en el procesamiento paralelo.
  • barrier: Crea una barrera explícita en la que los hilos se quedan esperando hasta que todo el equipo la haya alcanzado.
  • task: Permite la ejecución asíncrona mediante tareas explícitas. El bloque de código dentro de la directiva task es ejecutado por un único hilo, y la tarea es instanciada por el hilo que se encuentra con la directiva. Por ello es recomendable utilizar esta directiva dentro de una directiva single, evitando crear (y ejecutar) la misma tarea tantas veces como hilos haya. Su formato es: #pragma omp task [cláusulas]. Cuando la tarea se instancia ésta es insertada en una cola de pendientes. Las tareas de la cola de pendientes son seleccionadas por la implementación de OpenMP en función de sus dependencias cumplidas y prioridad. Las tareas seleccionadas pasan a la cola de listas para ejecutar. Los hilos del equipo activo cogen tareas de dicha cola y las ejecutan. Uso de task con single:
#define NUM_ITERS 1000000
#pragma omp parallel
{
    int32_t BS =  NUM_ITERS/omp_get_num_threads();
    #pragma omp single
    {
        for (int i = 0; i < NUM_ITERS; i+= BS) {
            int32_t upper = i+((NUM_ITERS-BS >= 0) ? BS : NUM_ITERS-BS);
            #pragma omp task firstprivate(i,upper)
            {
                for (int ii = i; ii < upper; ii++)
                    a[ii] += b[ii]*c[ii];
            }
        }
        #pragma omp taskwait
    }
}
  • taskyield: Permite a una tarea ceder el control del núcleo del procesador a otra tarea.
  • taskwait: Similar a barrier. El hilo instanciador de tareas se queda esperando en el taskwait hasta que todas las tareas previas al taskwait hayan terminado su ejecución. No sirve para esperar a las tareas anidadas, que requerirán un taskwait anidado. Todos los hilos, sean los que sean, mientras permanecen en una barrera, sea ésta implícita o explícita, comprueban la cola de tareas listas para ejecutar. Si hay tareas pendientes, las ejecutarán.

Cláusulas de visibilidad de datos[editar]

  • shared(valor-i_1, ..., valor-i_N): Los datos de la región paralela son compartidos, lo que significa que son visibles y accesibles por todos los hilos. Por definición, todas las variables que trabajan en la región paralela son compartidas excepto el contador de iteraciones.
  • private(valor-i_1, ..., valor-i_N): Los datos de la región paralela nombrados por private son copiados al área de almacenamiento local del hilo (principalmente su pila), lo que significa que cada hilo los usará como variable temporal. Una variable privada no es inicializada y tampoco se mantiene fuera de la región paralela. Por definición, el contador de iteraciones en OpenMP es privado.
  • firstprivate(valor-i_1, ..., valor-i_N): Cada hilo tiene una copia local del dato. La copia local se inicializa con el valor de la copia global en el momento de encontrarse con la directiva a la que se aplica la cláusula.
  • lastprivate(valor-i_1, ..., valor-i_N): Cada hilo tiene una copia local del dato. La copia global será actualizada por el hilo que ejecuta la última iteración según el orden secuencial de programa.
  • default: Permite al programador que todas las variables de la región paralela sean shared o no para C/C++, o shared, firstprivate, private, o none para Fortran. La opción none fuerza al programador a declarar de que tipo será cada variable en la región paralela.

Las siguientes cláusulas definen operaciones colectivas:

  • reduction(tipo:valor-i_1, ..., valor-i_N): Cada hilo privatiza las variables listadas y al finalizar la sección de la directiva en la que aparece la cláusula, los distintos hilos actualizan la variable global de la que deriva la copia privada realizando la operación indicada por la clásulua reduction. Esto evita condiciones de carrera. El tipo puede ser: +, -, *, /, min, max ó definido por el usuario.

Cláusulas de Planificación (Scheduling)[editar]

  • schedule(omp_sched_t tipo, int chunk_size): Esto es útil si la carga procesal es un bucle do o un bucle for. Las iteraciones son asignadas a los threads basándose en el método definido en la cláusula. Los tres tipos de scheduling son:
  1. static: Aquí todas las iteraciones se reparten entre los threads antes de que estos ejecuten el bucle. Se reparten las iteraciones contiguas equitativamente entre todos los threads. Especificando un integer como parámetro de chunk serán repartidas tantas iteraciones contiguas al mismo thread como el chunk indique.
  2. dynamic: Aquí al igual que en static se reparten todas las iteraciones entre los threads. Cuando un thread en concreto acaba las iteraciones asignadas, entonces ejecuta una de las iteraciones que estaban por ejecutar. El parámetro chunk define el número de iteraciones contiguas que cada thread ejecutará a la vez.
  3. guided: Un gran número de iteraciones contiguas son asignadas a un thread. Dicha cantidad de iteraciones decrece exponencialmente con cada nueva asignación hasta un mínimo especificado por el parámetro chunk.

Si no se pone ninguna clausula schedule, la planificacion por defecto es schedule(static,1). Esto es, se reparten las iteraciones del bucle de forma round-robin de una en una.

Claúsulas de dependencias[editar]

  • depends(tipo:valor-i_1,valor-i_2...): Según el tipo de dependencia (entrada, salida o ambos), las tareas serán puestas en la cola de disponibles antes o después de otras tareas, decisión que toma la biblioteca de tiempo de ejecución. Hay tres tipos de dependencias:
  1. in: La dependencia es de lectura. La tarea (task) lee el valor almacenado en la dirección de memoria del valor-i.
  2. out: La dependencia es de escritura. La tarea (task) escribe en la dirección de memoria del valor-i.
  3. inout: La dependencia es de escritura y lectura. La tarea (task) lee y escribe en la dirección de memoria del valor-i.

Si una tarea tiene una dependencia in, y otra tarea instanciada anteriormente tiene una dependencia out sobre el mismo valor-i, entonces la tarea con el in se ejecutará después de la out. Como las lecturas no modifican la memoria, dos tareas con un in sobre el mismo valor-i se pueden ejecutar en cualquier orden y por cualquier hilo disponible. En cambio, dos dependencias de escritura sobre el mismo valor-i serán siempre serializadas, puesto que modifican la memoria. Estos conceptos se asemejan con las dependencias existentes entre instrucciones en un microprocesador con ejecución fuera de orden, en los que se pueden dar tres tipos de dependencias:

  1. RAW: (Read After Write). Lectura después de escritura.
  2. WAR: (Write After Read). Escritura después de lectura.
  3. WAW: (Write After Write). Escritura después de escritura.

La RAW es la única dependencia verdadera e insalvable. Las WAR y WAW se tienen como falsas dependencias puesto que la dependencia existe por tener un mismo nombre (dirección de memoria del valor-i). Renombrando la dirección del valor-i (copiándolo en otra dirección de memoria) se pueden eliminar las falsas dependencias. Si la tarea no lee dicha dirección de memoria, sólo la escribe, a efectos prácticos le da igual que otra instrucción anterior la lea. También le da igual que otra instrucción anterior escriba en la misma dirección puesto que no necesita el valor actualizado. Sin embargo, si se utiliza siempre la misma dirección de memoria, hay que preservar el orden de programa para que el último valor sea el que indica el orden de instanciación de las tareas. Así se evita en una ejecución en desorden que una lectura anterior lea un dato que tendría que aparecer más tarde desde el punto de vista de dicha lectura. También se evita el caso en el que la última escritura adelanta a la escritura más vieja, de manera que la vieja será el último valor que quede reflejado cuando el que ha de permanecer debería ser el de la escritura más nueva. Si se renombra la dirección de memoria el orden de las instrucciones no importará, puesto que las tareas dependientes preservarán el orden de ejecución con respecto a la nueva dirección de memoria, eliminando las dependencias WAR y WAW.

Funciones[editar]

La API de OpenMP dispone de una serie de funciones para obtener información y configurar el entorno paralelo. También permite manejar candados (locks) y tomar mediciones de tiempo. Además de las funciones aquí mostradas, cada implementación de OpenMP tiene funciones y variables de entorno propias. Por ejemplo, el OpenMP de GNU (GOMP, GNU OpenMP) dispone de variables de entorno propias.[1]​ Hay partes de la especificación que son dependientes de la implementación por lo que el programa no tiene porqué comportarse igual si el binario se genera primero con una implementación y luego por otra. Por ejemplo, la creación de regiones paralelas anidadas no especifica cómo se han de suministrar los hilos para las regiones anidadas. En el caso de GNU OpenMP mantiene un único equipo de hilos y lo hace crecer o decrecer en función de la cantidad de hilos demandada por la región paralela activa. Esto es una optimización que ayuda a mantener la localidad de datos y disminuir los sobrecostes de creación y destrucción de hilos. Sin embargo, una implementación podría no mantener un equipo único y crear nuevos equipos enteros. Esto provoca la expulsión de los hilos de regiones paralelas predecesoras. La asignación de identificadores a procesadores no sigue siempre el mismo orden salvo que se indique lo contrario. Si el código del programa depende del identificador del hilo para la asignación de datos a procesar, se puede perder la localidad espacial del programa. Crear y destruir múltiples equipos de hilos requiere también de más tiempo que reutilizar equipos de hilos ya existentes.

Las funciones aquí listadas se corresponden con la versión 4.5 del estándar OpenMP.

Funciones para controlar hilos, procesadores y el entorno paralelo[editar]

Estas funciones se enlazan según las normas del lenguaje C y no lanzan excepciones.

  • omp_get_active_level(): Regiones paralelas activas en el momento de invocar la función.
  • omp_get_ancestor_thread_num(int level): Devuelve el TID (Thread ID) en el nivel de anidamiento de paralelismo en cuestión que se corresponde con el hilo que invoca la función.
  • omp_get_cancellation(): ¿Soporta cancelación la implementación de OpenMP en uso? Controlado por la variable de entorno OMP_CANCELLATION.
  • omp_get_default_device(): Obtener el dispositivo por defecto en las regiones target que no tienen cláusula device.
  • omp_get_dynamic(): ¿Está activa la funcionalidad de creación de equipos de tamaño dinámico? Valor controlado por variable de entorno OMP_DYNAMIC o omp_set_dynamic().
  • omp_get_level(): Obtener el nivel de anidamiento en el momento de invocar la función.
  • omp_get_max_active_levels(): ¿Cuál es número máximo de regiones paralelas activas permitido?
  • omp_get_max_task_priority(): ¿Cuál es la prioridad máxima permitida para una tarea explícita?
  • omp_get_max_threads(): ¿Cuál es el número máximo de hilos de la actual región paralela, que no usa num_threads?
  • omp_get_nested(): ¿Se permiten regiones paralelas anidadas? Valor controlado por la variable de entorno OMP_NESTED o función omp_set_nested().
  • omp_get_num_devices(): ¿Cuántos dispositivos aceleradores hay?
  • omp_get_num_procs(): ¿Cuántos procesadores (núcleos) hay disponibles en el dispositivo actual?
  • omp_get_num_teams(): ¿Cuántos equipos de hilos hay en la región paralela actual?
  • omp_get_num_threads(): ¿Cuántos hilos forman el equipo de hilos activo actual? En una sección secuencial devolverá 1. El tamaño por defecto se puede inicializar con la variable OMP_NUM_THREADS. Durante la ejecución se puede usar la cláusula num_threads o la función omp_set_num_threads(int num_threads). Si no se usa nada de lo anterior y el valor de OMP_DYNAMIC está desactivado, se configura un total de hilos correspondiente con el total de procesadores disponibles.
  • omp_get_proc_bind(): ¿Están los hilos anclados a unos procesadores en concreto? La función devolverá el tipo de anclaje (binding), que puede ser uno de los siguientes: omp_proc_bind_false, omp_proc_bind_true, omp_proc_bind_master, omp_proc_bind_close ó omp_proc_bind_spread. El tipo de anclaje se establece al inicio de programa con la variable de entorno OMP_PROC_BIND.
  • omp_get_schedule(): ¿Cuál es el método de planificación por defecto?
  • omp_get_team_num(): ¿Cuál es el identificador del equipo de hilos actual?
  • omp_get_team_size(): ¿Cuál es el tamaño del equipo de hilos activo?
  • omp_get_thread_limit(): ¿Cuál es el máximo número de hilos admitido?
  • omp_get_thread_num(): ¿Cuál es el identificador dentro del equipo activo del hilo que invoca la función?
  • omp_in_parallel(): ¿El hilo se encuentra dentro de una región paralela?
  • omp_in_final(): ¿Estamos dentro de una tarea explícita (task) o la región de la tarea explícita se está ejecutando como final?
  • omp_is_initial_device(): En el momento de invocar la función, ¿estamos en el anfitrión o en un acelerador?
  • omp_set_default_device(int device_num): Configura el dispositivo por defecto para las regiones target que no tienen cláusula device.
  • omp_set_dynamic(int dynamic_threads): Activar/desactivar la regulación dinámica del tamaño de los equipos de hilos.
  • omp_set_max_active_levels(int max_levels): Limita el número de regiones paralelas activas.
  • omp_set_nested(int nested): Permitir o no regiones paralelas anidadas.
  • omp_set_num_threads(int num_threads): Configura el número de hilos máximo en un equipo de hilos.
  • omp_set_schedule(omp_sched_t kind, int chunk_size): Configura el método de planificación (schedule) por defecto. El valor de kind puede ser omp_sched_static, omp_sched_dynamic, omp_sched_guided ó omp_sched_auto.

Funciones para inicializar, activar, desactivar, comprobar y destruir candados simples y anidados[editar]

  • omp_init_lock(omp_lock_t *lock): Inicializar un candado.
  • omp_set_lock(omp_lock_t *lock): Esperar a que el candado esté inactivo y activarlo para el hilo invocante.
  • omp_test_lock(omp_lock_t *lock): Comprobar si el candado está inactivo y activarlo para el hilo invocante si la comprobación es positiva.
  • omp_unset_lock(omp_lock_t *lock): Desactivar un candado simple.
  • omp_destroy_lock(omp_lock_t *lock): Destruir un candado simple.
  • omp_init_nest_lock(omp_lock_t *lock): Inicializar un candado anidado.
  • omp_set_nest_lock(omp_lock_t *lock): Esperar a que el candado anidado esté inactivo y activarlo para el hilo invocante.
  • omp_test_nest_lock(omp_lock_t *lock): Comprobar si el candado está inactivo y activarlo para el hilo invocante si la comprobación es positiva.
  • omp_unset_nest_lock(omp_lock_t *lock): Desactivar un candado anidado.
  • omp_destroy_nest_lock(omp_lock_t *lock): Destruir un candado anidado.

Funciones para medir el tiempo[editar]

  • omp_get_wtick: Obtener la precisión del cronómetro: cuántos segundos pasan entre dos ticks de reloj.
  • omp_get_wtime: Obtener el tiempo del cronómetro. El tiempo se corresponde con el real, es decir, tiempo de ejecución de programa, no tiempo de proceso. El tiempo de proceso sería la suma de los tiempos de actividad de todos los hilos. La unidad de medida son los segundos. No hay garantía de que dos hilos distintos den el mismo tiempo.

Variables de entorno[editar]

  • OMP_CANCELLATION: Configura la posibilidad de utilizar la directiva #pragma omp cancel
  • OMP_DISPLAY_ENV: Muestra la versión de OpenMP y las variables de entorno.
  • OMP_DEFAULT_DEVICE: Configura el dispositivo utilizado en las regiones target
  • OMP_DYNAMIC: Activa el ajuste dinámico de hilos.
  • OMP_MAX_ACTIVE_LEVELS: Configura la máxima cantidad de regiones paralelas anidadas.
  • OMP_MAX_TASK_PRIORITY: Configura la prioridad máxima de una task.
  • OMP_NESTED: Activa el uso de regiones paralelas anidadas. Si TRUE entonces los miembros de un equipo de hilos pueden crear nuevos equipos de hilos.
  • OMP_NUM_THREADS: Fija el número de hilos simultáneos.
  • OMP_PROC_BIND: Configura si se pueden mover los hilos entre procesadores.
  • OMP_PLACES: Configura las CPUs en las que los hilos deben quedar fijados.
  • OMP_STACKSIZE: Configura el tamaño de la pila de cada hilo.
  • OMP_SCHEDULE: Configura el tipo de schedule por defecto.
  • OMP_THREAD_LIMIT: Configura el máximo número de hilos.
  • OMP_WAIT_POLICY: Configura el algoritmo de espera en las barreras (barrier). Puede ser espera activa o pasiva.

Versiones[editar]

La última versión de OpenMP es la 4.5. A lo largo de más de 20 años se han publicado las siguientes versiones:[2]

  • OpenMP 1.0: Publicada en octubre de 1997, sólo para Fortran. Regiones paralelas, bucles for, barreras y otros mecanismos básicos de sinconización de hilos.
  • OpenMP 1.1: Publicada en noviembre de 1999, una fe de erratas interpretativas.
  • OpenMP 2.0: Publicada en noviembre del 2000 (Fortran) y marzo de 2002 (C/C++). Adiciones como las cláusulas num_threads, y copyprivate o las funciones de obtención de tiempo omp_get_wtime y omp_get_wtick. Permitidos los vectores de longitud variable de C99, pudiéndose usar con ellos las cláusulas que actuan sobre tipos de datos como firstprivate, lastprivate y private.
  • OpenMP 2.5: Publicada en mayo de 2005. Fusiona C, C++ y Fortran. Introduce variables de control internas (ICVs). Redefinición de terminología, clarificación de las explicaciones de la directivas y corrección de erratas.
  • OpenMP 3.0: Publicada en mayo de 2008. Añade tareas explícitas (task). Añadida directiva taskwait. Añadida la planificación auto. Añadida variable de entorno OMP_STACKSIZE y OMP_WAIT_POLICY. Funciones adicionales, cambios en la definición de algunos conceptos.
  • OpenMP 3.1: Publicada en julio e 2011. Adición de clásulas final, mergeable y taskyield para las tareas explícitas. Directiva atomic extendida con las cláusulas read,write, capture y update. Operadores de reducción min y max añadidos en C y C++. OMP_PROC_BIND añadido.
  • OpenMP 4.0: Publicada en julio de 2013. Añade la especificación de dependencias (depends) en las tareas explícitas así como la posibilidad de especificar regiones de código para ejecutar en dispositivos aceleradores (device offload). Añadida cláusula proc_bind junto con variable de entorno OMP_PLACES y función omp_get_proc_bind. Añadidas directivas para soporte de paralelismo SIMD y aceleradores. Variable de entorno OMP_DEFAULT_DEVICE. Directiva taskgroup. Directiva declare reduction. Directivas cancel y cancellation point junto con la función omp_get_cancellation y variable OMP_CANCELLATION. Variable de entorno OMP_DISPLAY_ENV. Los ejemplos (apéndice A) ahora residen en un documento separado.
  • OpenMP 4.5: Publicada en noviembre de 2015. Añade soporte para algunas características de Fortran 2003. Se añade un parámetro a la cláusula ordered de la directiva de bucles junto con clásusulas nuevas a la directiva ordered para permitir anidar bucles con dependencias entre iteraciones. Con este mismo propósito se añaden las dependencias de tipo source y sink a la cláusula depend. Se añade la cláusula priority para dar pistas a la biblioteca de tiempo de ejecución sobre la prioridad de las tareas. Consecuentemente se añadió la función omp_get_max_task_priority y la variable de entorno OMP_MAX_TASK_PRIORITY. Se añade la cláusula use_device_ptr a la directiva target data y la cláusula is_device_ptr a la directiva target para permitir interactuar con el código nativo de un dispositivo acelerador. Hay más cláusulas relacionadas con dispositivos aceleradores para permitir SIMD, mapear datos desestructurados (no consecutivos en memoria) en aceleradores, funciones de gestión explícita de memoria en aceleradores (reservar memoria, liberar memoria, transferir datos y asociar memoria). Aparte de estas adiciones para aceleradores se mejoran otras directivas y cláusulas ya existentes.

Compiladores y entornos de programación que soportan OpenMP[editar]

  • GCC de GNU, hasta OpenMP 4.5.
  • XL C/C++/Fortran de IBM, hasta OpenMP 3.1 y OpenMP 4.5 parcialmente (aceleración con GPUs NVIDIA).
  • Intel C/C++/Fortran, hasta OpenMP 4.5.
  • Oracle C/C++/Fortran, hasta OpenMP 4.0.
  • PGI C/C++/Fortran, hasta OpenMP 3.1.
  • Absoft Pro Fortran Fortran, hasta OpenMP 3.1.
  • Lahey/Fujitsu Fortran 95 C/C++/Fortran, hasta OpenMP 3.1.
  • PathScale C/C++/Fortran, hasta OpenMP 2.5, parcialmente OpenMP 3.x y OpenMP 4.0.
  • Cray C/C++/Fortran, hasta OpenMP 4.0 y parcialmente OpenMP 4.5.
  • NAG nagfor, hasta OpenMP 3.1.
  • OpenHU Research Compiler C/C++/Fortran, hasta OpenMP 2.5, parcialmente OpenMP 3.0.
  • LLVM clang, hasta OpenMP 4.0 y OpenMP 4.5 parcialmente (falta el soporte para uso de aceleradores).
  • LLNL Rose Research Compiler C/C++/Fortran, hasta OpenMP 3.0 y algunas características de aceleradores de OpenMP 4.0.
  • Appentra Solutions parallware compiler Parallware Suite C/C++, hasta OpenMP 4.0.
  • Texas Instruments C, hasta OpenMP 3.0 con las directivas de aceleradores de OpenMP 4.0.
  • Mercurium C/C++/Fortran del Barcelona Supercomputing Center, OpenMP 3.1 y OpenMP 4.0, ambos parcialmente.
  • ARM C/C++/Fortran, hasta OpenMP 3.1 y OpenMP 4.0/4.5 parcialmente (faltan las características de uso de aceleradores).

Esta lista de compiladores[3]​ muestra que los únicos compiladores y entornos de programación que soportan plenamente el estándar OpenMP son GCC y el Intel Compiler. Las tareas con dependencias (disponibles desde OpenMP 4.0) sólo están disponibles en GCC, Intel Compiler, Oracle compiler, PathScale compiler, Cray compiler, clang, Parallware Suite, Mercurium y ARM compiler.

Véase también[editar]

Web relacionadas[editar]

Sitio Oficial de OpenMP

Referencias[editar]

  1. GNU. «GNU libgomp» (en inglés). Consultado el 18 de agosto de 2017. 
  2. OpenMP Architecture Review Board. «Specifications» (en inglés). Consultado el 16 de agosto de 2017. 
  3. OpenMP Architecture Review Board. «OpenMP Compilers» (en inglés). Consultado el 16 de agosto de 2017.