2012-09-19 11 views
5

Estoy usando openMP para ejecutar instancias de mi simulación en paralelo.Cómo forzar a openMP a ejecutar iteraciones en un orden específico

#pragma omp parallel for private(part) shared(P,lfcc,temp) 
for (part = 0; part < P->Parts; part++) 

parte de los controles de bucle si el archivo de salida con número de índice "parte" ya existen (para que pueda ejecutar la simulación para un determinado valor de "Partes", y más tarde aumentarlo sin sobrescribir los resultados existentes) . Sin embargo, esto requiere que la iteración se ejecute en orden. Es decir, para n subprocesos, primero debe ejecutar simultáneamente las partes (1) - (n), seguidas por las partes (n + 1) - (2n) y así sucesivamente. en este momento (con 3 hilos ejecutándose en paralelo, y "partes" configuradas en N), el comportamiento es diferente, ejecuta las primeras partes (0), (N/3), (2N/3) seguido de (1), (N/3 + 1), (2N/3 + 1) y así sucesivamente.

Supongamos ahora que inicialmente quería 30 piezas que se completaron todas. Luego decido que necesito más partes y cambio "Partes" a 45. Luego, los primeros hilos obtienen partes (1) - (15), el segundo (16) - (30) y el tercero (31-45). Los dos primeros hilos descubren rápidamente que todas sus partes asignadas ya se han completado y dejarán que el último hilo funcione solo (si pongo una cláusula de barrera antes de que el programa finalice).

Una solución simple es dejar que la variable "parte" comience no con 0 sino con m + 1, donde m es el número de partes completadas previamente. Pero me preguntaba si era posible obligar a openMP a ejecutar la iteración en el orden que se muestra en negrita arriba.

+1

Probablemente no hay una mejor manera distinta a tirar un lazo externo sobre la región paralela que los bucles sobre todos sus bloques secuenciales. – Mysticial

+0

¿Entonces quieres una partición en bloque? Al igual que si quiero procesar 40 elementos con 4 hilos, trabajarán en 0..9, 10..19, 20..29 y 30..39 respectivamente? – Tudor

+0

Tudor, necesito el otro camino. con 4 hilos, haga 1-4,5-8,9-12 ... –

Respuesta

7

Puede cambiar el tamaño de los bloques de iteración que cada subproceso obtiene en 1 dentro de la cláusula schedule, p. schedule(static,1). Con 3 hilos, el primero procesaría las iteraciones 0, 3, 6, 9, etc., el segundo hilo procesaría las iteraciones 1, 4, 7, 10, etc., y el tercero procesaría las iteraciones 2, 5, 8, 11 y así sucesivamente. Todavía necesita sincronizar en algún lugar del ciclo ya que no hay garantía de que los subprocesos ejecuten todos los pasos al mismo tiempo y a la misma velocidad (puede poner una barrera al final de cada iteración para sincronizar antes de que comience el siguiente bloque de iteraciones))

Otra solución es usar la construcción de tareas OpenMP. Con él puede ejecutar un gran bucle en un hilo, generando tareas computacionales. Se puede poner comprueba la existencia del archivo de salida dentro de este bucle y crear nuevas tareas sólo si es necesario (por ejemplo, el archivo de salida no existe):

#pragma omp parallel 
{ 
    ... 
    #pragma omp single 
    for (part = 0; part < P->Parts; part++) 
    { 
     if (!output_file_exists(part)) 
      #pragma omp task 
      { 
       ... computation for that part ... 
      } 
    } 
    #pragma omp taskwait 
    ... 
} 

esperanza he entendido su problema correctamente.

+0

Es una buena solución. Lo intentaré, o intentaré probar :) –

0

Si queremos que los hilos OpenMP se ejecuten en orden debemos usar la cláusula ordered. Sin embargo, debemos ser cuidadosos. Lo siguiente imprimirá i 's (y el hilo de Identificación) en orden (i0-19, tid 0-omp_get_num_threads() - 1):

#pragma omp parallel 
    #pragma omp for ordered 
     for (i = 0; i < 20; i++) 
      #pragma omp ordered 
       printf("i=%d - tid=%d\n", i, omp_get_thread_num()); 

de salida (en mi 8 base de la máquina Intel x86_64):

i=0 - tid=0 
i=1 - tid=0 
i=2 - tid=0 
i=3 - tid=1 
i=4 - tid=1 
i=5 - tid=1 
i=6 - tid=2 
i=7 - tid=2 
i=8 - tid=2 
i=9 - tid=3 
i=10 - tid=3 
i=11 - tid=3 
i=12 - tid=4 
i=13 - tid=4 
i=14 - tid=5 
i=15 - tid=5 
i=16 - tid=6 
i=17 - tid=6 
i=18 - tid=7 
i=19 - tid=7 

Pero aviso:

#pragma omp parallel 
    #pragma omp for ordered 
     for (i = 0; i < 20; i++) 
     { 
      // the threads enter this for() section in order but won't 
      // print this statement in order! 
      printf("other i=%d - tid=%d\n", i, omp_get_thread_num()); 
      #pragma omp ordered 
       // these are printed in order 
       printf("i=%d - tid=%d\n", i, omp_get_thread_num()); 
     } 

salida:

other i=16 - tid=6 
other i=18 - tid=7 
other i=12 - tid=4 
other i=0 - tid=0 
i=0 - tid=0 
other i=1 - tid=0 
i=1 - tid=0 
other i=2 - tid=0 
i=2 - tid=0 
other i=3 - tid=1 
other i=6 - tid=2 
other i=14 - tid=5 
i=3 - tid=1 
other i=4 - tid=1 
i=4 - tid=1 
other i=5 - tid=1 
i=5 - tid=1 
i=6 - tid=2 
other i=7 - tid=2 
i=7 - tid=2 
other i=8 - tid=2 
i=8 - tid=2 
other i=9 - tid=3 
i=9 - tid=3 
other i=10 - tid=3 
i=10 - tid=3 
other i=11 - tid=3 
i=11 - tid=3 
i=12 - tid=4 
other i=13 - tid=4 
i=13 - tid=4 
i=14 - tid=5 
other i=15 - tid=5 
i=15 - tid=5 
i=16 - tid=6 
other i=17 - tid=6 
i=17 - tid=6 
i=18 - tid=7 
other i=19 - tid=7 
i=19 - tid=7 

Por último, tenga en cuenta que esta matriz se está rellenando en orden (la verifico más tarde cuando la imprimo en serie desde el hilo principal para asegurarse).

// threads filling up array 
    int Arr[20] = {0}; 
#pragma omp parallel for ordered 
    for (i = 0; i < 20; i++) 
     Arr[i] = i; 

    printf("\n\n"); 
    // lets check to see if threads have put values to the array in order 
    for (i = 0; i < 20; i++) 
     printf("Arr[%d]=%d\n", i, Arr[i]); 

Salida:

A[0]=0 
A[1]=1 
A[2]=2 
A[3]=3 
A[4]=4 
A[5]=5 
A[6]=6 
A[7]=7 
A[8]=8 
A[9]=9 
A[10]=10 
A[11]=11 
A[12]=12 
A[13]=13 
A[14]=14 
A[15]=15 
A[16]=16 
A[17]=17 
A[18]=18 
A[19]=19 
Cuestiones relacionadas