2012-05-14 16 views
5

Provo a scrivere una semplice applicazione usando OpenMP. Purtroppo ho problemi con l'accelerazione. In questa applicazione ho un ciclo while. Il corpo di questo ciclo consiste in alcune istruzioni che dovrebbero essere eseguite in sequenza e una per ciclo. Io uso #pragma omp parallel for per rendere questo per ciclo parallelo. Questo ciclo non ha molto lavoro, ma viene chiamato molto spesso.OpenMP - crea thread solo una volta

Preparo due versioni di ciclo for ed eseguo l'applicazione su 1, 2 e 4cores.
versione 1 (4 iterazioni in ciclo for): 22 sec, 23 sec, 26 sec.
versione 2 (100000 iterazioni in ciclo for): 20 sec, 10 sec, 6 sec.

Come si può vedere, quando per ciclo non ha molto lavoro, il tempo su 2 e 4 core è superiore a quello su 1 core. Suppongo che il motivo sia che #pragma omp parallel for crea nuovi thread in ogni iterazione del ciclo while. Quindi, vorrei chiederti: esiste la possibilità di creare thread una volta (prima del ciclo while) e assicurare che un po 'di lavoro nel ciclo while venga eseguito in sequenza?

#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; 
} 

risposta

5

Si potrebbe spostare la regione parallelo all'esterno del ciclo while (true) e utilizzare la direttiva single per rendere la parte seriale del codice da eseguire in un solo filo. Ciò rimuoverà l'overhead del modello fork/join. Anche OpenMP non è veramente utile su thight loop con un numero molto piccolo di iterazioni (come la tua versione 1). In pratica stai misurando l'overhead di OpenMP poiché il lavoro all'interno del loop è fatto molto velocemente - anche 100000 iterazioni con funzioni trascendentali impiegano meno di secondo sulla CPU di generazione attuale (a 2 GHz e circa 100 cicli per instruciton FP oltre all'aggiunta, sarà prendere ~ 100 ms).

Ecco perché OpenMP fornisce la clausola if(condition) che può essere utilizzato per attivare selettivamente fuori la parallelizzazione per piccoli cicli:

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

Si consiglia di utilizzare schedule(static) cicli for regolari (cioè per i cicli anche in cui ogni l'iterazione impiega circa lo stesso tempo per calcolare).

8

La maggior parte delle implementazioni OpenMP crea un numero di thread all'avvio del programma e li mantiene per la durata del programma. Cioè, la maggior parte delle implementazioni non crea e distrugge dinamicamente i thread durante l'esecuzione; fare ciò colpirebbe le prestazioni con gravi costi di gestione dei thread. Questo approccio alla gestione dei thread è coerente e appropriato per i soliti casi di utilizzo di OpenMP.

È molto più probabile che il rallentamento visualizzato quando si aumenta il numero di thread OpenMP sia ridotto all'imposizione di un overhead parallelo su un loop con un numero minimo di iterazioni. La risposta di Hristo copre questo.