Comenzando con openmp

Compilacion

Hay muchos compiladores que admiten diferentes versiones de la especificación OpenMP. OpenMP mantiene una lista aquí con el compilador que lo admite y la versión compatible. En general, para compilar (y vincular) una aplicación compatible con OpenMP, solo necesita agregar un indicador de compilación y, si usa la API de OpenMP, debe incluir el encabezado OpenMP (omp.h). Si bien el archivo de encabezado tiene un nombre fijo, el indicador de compilación depende del compilador. La siguiente es una lista no exhaustiva de compiladores y el indicador que habilita OpenMP.

  • GCC (incluidos gcc, g++ y gfortran): -fopenmp
  • LLVM: -fopenmp
  • Conjunto de compiladores Intel (incluidos icc, icpc e ifort): -qopenmp (y -fopenmp para compatibilidad con GCC/LLVM)
  • Conjunto de compiladores IBM XL (incluidos xlc, xlC y xlf): -xlsmp=omp
  • Conjunto de compiladores PGI (incluido pgcc pgc++ pgfortran): ‘-mp’

Hola mundo en paralelo usando OpenMP

#include <omp.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
   #pragma omp parallel
   {
     printf ("Hello world! I'm thread %d out of %d threads.\n",
             omp_get_thread_num(), omp_get_num_threads());
   }
   return 0;
}

Este código simplemente crea un equipo de hilos (según la variable de entorno OMP_NUM_THREADS - y si no se define creará uno por núcleo lógico en el sistema) y cada hilo se identificará además de imprimir el típico mensaje de Hola mundo.

Estructura de trabajo compartido: ejemplo de bucle For

double  res[MAX];  int i;
#pragma omp parallel 
{    
    #pragma omp for
    for (i=0;i< MAX; i++) {
        res[i] = huge();
    } 
}    

El bucle for se ejecutará en paralelo. great() es un método que puede tardar demasiado en ejecutarse. OpenMP admite un atajo para escribir el código anterior como:

double  res[MAX];  int i;
#pragma omp parallel for
for (i=0;i< MAX; i++) {
    res[i] = huge();
} 

También podemos tener una cláusula de programación que afecte la forma en que las iteraciones de bucle se asignan a los hilos. Por ejemplo:

#pragma omp parallel
#pragma omp for schedule(static)
for(i=0;I<N;i++) {
    a[i] = a[i] + b[i];
}

Los diferentes estilos de programación son:

horario(estático [,fragmento])
Reparta bloques de iteraciones de tamaño “trozo” para cada subproceso.
Si no se especifica: asigne lo más uniformemente posible a los subprocesos disponibles

horario(dinámico[,fragmento])
Cada subproceso toma iteraciones de “trozos” de una cola hasta que se han manejado todas las iteraciones.

horario(guiado[,fragmento])
Los subprocesos toman dinámicamente bloques de iteraciones. El tamaño del bloque comienza grande y se reduce a un tamaño de “trozo” a medida que avanza el cálculo.

horario(tiempo de ejecución)
Horario y tamaño de fragmento tomados de la variable de entorno OMP_SCHEDULE.

Ejemplo de reducción

#include <omp.h>
void main ()
{     
    int i;       
    double ZZ, func(), res=0.0;

    #pragma omp parallel for reduction(+:res) private(ZZ) 
    for (i=0; i< 1000; i++){
        ZZ = func(I);
        res = res + ZZ; 
    }
}

En la última línea: en realidad se agregó a una copia privada, luego se combinó después del bucle. El compilador se encarga de los detalles.