2011-11-07 12 views
5

Tengo un problema muy raro el uso de OpenMP en mi código C++:OpenMP - Easy Loop, pero sigue siendo infinito?

void update(double *source, double *target, int n) 
{ 
    target[0] = source[0]; 
    target[n-1] = source[n-1]; 
    #pragma omp parallel for 
    for(int i = 1; i < n-1; ++i) 
     target[i] = (1.0/3.0) * (source[i-1] + source[i] + source[i+1]); 
} 

Tanto origen y el destino son matrices dobles con n elementos. El código funciona bien cuando se usa sin OpenMP. Pero tan pronto como uso el pragma, el código parece quedarse atascado en este ciclo. La cosa es: no tengo absolutamente IDEA por qué. Espero que alguien me puede ayudar

+0

Compila y ejecuta bien con GCC 4.6.1. ¿Qué compilador usas? –

+0

¿Puede agregar algunos detalles sobre el compilador y el sistema operativo? – talonmies

+0

gcc 4.2.1 en MacOS Snow Leopard, precisamente: 686-apple-darwin10-g ++ - 4.2.1 (GCC) 4.2.1 (Apple Inc. compilación 5666) (punto 3) – Chris

Respuesta

2

¿Qué tan grande es n?

La programación predeterminada para una directiva OpenMP parallel for es específica de la implementación. Parece que en GOMP (la implementación OpenMP utilizada por gcc), el valor predeterminado es (dynamic,1) de acuerdo con documentation here. Esto significa que cada subproceso está accediendo (en i-1 y i+1) a ubicaciones de memoria cargadas por subprocesos vecinos, lo que podría provocar una utilización de memoria caché deficiente. En las arquitecturas de CPU modernas, las operaciones de esténciles como esta suelen estar unidas a la memoria y son sensibles al almacenamiento en caché. Usted podría tratar de especificar un horario con trozos más grandes, por ejemplo, mediante:

#pragma omp parallel for schedule(dynamic,1024) 

sólo estoy usando 1024 como ejemplo. En la práctica, debe experimentar para encontrar el factor de fragmentación óptimo (o buscar sistemáticamente con un barrido de parámetros, un proceso que a menudo se denomina "autoajuste"). O puede elegir un valor basado más en teoría, por ejemplo derivandolo del tamaño de caché L1 o L2 de su CPU.

O podría intentar la programación estática, ya que la cantidad de computación dentro del bucle for es uniforme entre los hilos, y la sobrecarga del planificador dinámico puede estar causando un cuello de botella. Si especifica

#pragma omp parallel for schedule(static) 

sin tamaño del trozo, a continuación, cada hilo se asignará un único trozo de aproximadamente el mismo tamaño.

Finalmente, es posible que también desee fijar los hilos OpenMP a sus propios núcleos de CPU. Puede hacerlo utilizando la variable de entorno GOMP_CPU_AFFINITY.

Editar:

sólo estaba jugando con el siguiente programa de prueba compilado con gcc 4.2.1, y creo que la documentación he vinculado al anterior es incorrecta. Parece que GOMP está predeterminado en schedule(static).

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

int main(int argc, char** argv) 
{ 
    int i; 
    #pragma omp parallel for 
    for (i=0; i<15; i++) { 
     int id = omp_get_thread_num(); 
     printf("%d assigned to thread %d\n", i, id); 
    } 
} 

Y la salida con dos hilos es:

$ ./test_sched | sort -n 
0 assigned to thread 0 
1 assigned to thread 0 
2 assigned to thread 0 
3 assigned to thread 0 
4 assigned to thread 0 
5 assigned to thread 0 
6 assigned to thread 0 
7 assigned to thread 0 
8 assigned to thread 1 
9 assigned to thread 1 
10 assigned to thread 1 
11 assigned to thread 1 
12 assigned to thread 1 
13 assigned to thread 1 
14 assigned to thread 1 
+0

La configuración predeterminada cuando no se define la programación depende de la implementación, pero AFAIK usualmente es 'estático'. El enlace GOMP que sugiere '(dynamic, 1)' es el valor predeterminado en realidad se refiere al caso en el que se usa 'schedule (runtime)'. – eran

Cuestiones relacionadas