2012-05-14 36 views
5

Intento escribir aplicaciones simples usando OpenMP. Desafortunadamente tengo un problema con la aceleración. En esta aplicación tengo un ciclo while. El cuerpo de este ciclo consta de algunas instrucciones que deben hacerse secuencialmente y uno para el ciclo. Yo uso #pragma omp parallel for para hacer esto para loop paralelo. Este ciclo no tiene mucho trabajo, pero se llama con mucha frecuencia.OpenMP - crear hilos solo una vez

Preparo dos versiones de for loop, y ejecuto la aplicación en 1, 2 y 4 cores.
versión 1 (4 iteraciones en el ciclo for): 22sec, 23sec, 26sec.
versión 2 (100000 iteraciones en for loop): 20sec, 10sec, 6sec.

Como puede ver, cuando para el bucle no tiene mucho trabajo, el tiempo en 2 y 4 núcleos es mayor que en 1core. Supongo que la razón es que #pragma omp parallel for crea nuevos subprocesos en cada iteración del ciclo while. Entonces, me gustaría preguntarle: ¿hay alguna posibilidad de crear subprocesos una vez (antes de while loop), y asegurar que algún trabajo en while loop se realice secuencialmente?

#include <omp.h> 
#include <iostream> 
#include <math.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 
int main(int argc, char* argv[]) 
{ 
    double sum = 0; 
    while (true) 
    { 
     // ... 
     // some work which should be done sequentially 
     // ... 

     #pragma omp parallel for num_threads(atoi(argv[1])) reduction(+:sum) 
     for(int j=0; j<4; ++j) // version 2: for(int j=0; j<100000; ++j) 
     { 
      double x = pow(j, 3.0); 
      x = sqrt(x); 
      x = sin(x); 
      x = cos(x); 
      x = tan(x); 
      sum += x; 

      double y = pow(j, 3.0); 
      y = sqrt(y); 
      y = sin(y); 
      y = cos(y); 
      y = tan(y); 
      sum += y; 

      double z = pow(j, 3.0); 
      z = sqrt(z); 
      z = sin(z); 
      z = cos(z); 
      z = tan(z); 
      sum += z; 
     } 

     if (sum > 100000000) 
     { 
      break; 
     } 
    } 
    return 0; 
} 

Respuesta

5

Se podía mover la región paralela fuera del bucle while (true) y utilizar la directiva single para hacer la parte de serie del Código que se ejecuta en un solo hilo. Esto eliminará la sobrecarga del modelo de tenedor/unión. Además, OpenMP no es realmente útil en bucles thight con muy pocas iteraciones (como su versión 1). Básicamente estás midiendo la sobrecarga de OpenMP ya que el trabajo dentro del ciclo se realiza realmente rápido, incluso 100000 iteraciones con funciones trascendentales tardan menos de segundo en la CPU de generación actual (a 2 GHz y aproximadamente 100 ciclos por instrucción FP aparte de la suma, tomar ~ 100 ms).

Por eso OpenMP proporciona la cláusula if(condition) que se puede utilizar para desactivar selectivamente la paralelización de bucles pequeños:

#omp parallel for ... if(loopcnt > 10000) 
for (i = 0; i < loopcnt; i++) 
    ... 

También es recomendable utilizar schedule(static) para los bucles regulares (es decir para los bucles en el que cada la iteración toma aproximadamente el mismo tiempo para calcular).

8

La mayoría de las implementaciones de OpenMP crean una serie de subprocesos en el inicio del programa y los mantienen mientras dure el programa. Es decir, la mayoría de las implementaciones no crean y destruyen dinámicamente subprocesos durante la ejecución; hacerlo afectaría el rendimiento con costos severos de administración de hilos. Este enfoque de gestión de subprocesos es coherente con, y apropiado para, los casos de uso habituales para OpenMP.

Es mucho más probable que la ralentización que ve cuando aumenta el número de subprocesos OpenMP se reduzca a la imposición de una sobrecarga paralela en un ciclo con un número pequeño de iteraciones. La respuesta de Hristo cubre esto.