2016-06-06 66 views
11

Ho due versioni di codice che producono risultati equivalenti dove sto provando a parallelizzare solo il ciclo interno di un ciclo nidificato for. Non sto ottenendo molta accelerazione, ma non mi aspettavo un 1-a-1 dal momento che sto provando solo a parallelizzare il ciclo interno.come evitare l'overhead di openMP nei loop nidificati

La mia domanda principale è perché queste due versioni hanno runtime simili? La seconda versione non esegue il fork dei thread solo una volta ed evita il sovraccarico di iniziare nuovi thread su ogni iterazione su i come nella prima versione?

La prima versione del codice avvia discussioni su ogni iterazione del ciclo esterno simili:

for(i=0; i<2000000; i++){ 
    sum = 0; 
    #pragma omp parallel for private(j) reduction(+:sum) 
    for(j=0; j<1000; j++){ 
    sum += 1; 
    } 
    final += sum; 
} 
printf("final=%d\n",final/2000000); 

Con questa uscita e compressione:

OMP_NUM_THREADS = 1

final=1000 
real 0m5.847s 
user 0m5.628s 
sys  0m0.212s 

OMP_NUM_THREADS = 4

final=1000 
real 0m4.017s 
user 0m15.612s 
sys  0m0.336s 
.515.053.691,36321 milioni

La seconda versione del codice inizia fili volta prima l'anello esterno e parallelizza il ciclo interno simili (?):

#pragma omp parallel private(i,j) 
for(i=0; i<2000000; i++){ 
    sum = 0; 
    #pragma omp barrier 
    #pragma omp for reduction(+:sum) 
    for(j=0; j<1000; j++){ 
    sum += 1; 
    } 
    #pragma omp single 
    final += sum; 
} 
printf("final=%d\n",final/2000000); 

Con questa uscita e compressione:

OMP_NUM_THREADS = 1

final=1000 
real 0m5.476s 
user 0m4.964s 
sys  0m0.504s 

OMP_NUM_THREADS = 4

final=1000 
real 0m4.347s 
user 0m15.984s 
sys  0m1.204s 

Perché i la seconda versione è più veloce della prima? Non evita il sovraccarico di iniziare discussioni su ogni iterazione del ciclo o sto facendo qualcosa di sbagliato?

+3

Probabilmente perché l'implementazione di OpenMP ha tradotto in modo efficace la prima versione nella seconda versione. La maggior parte delle implementazioni è abbastanza intelligente da mantenere vivi i thread se vede che vengono costantemente creati all'interno di un ciclo esterno. – NoseKnowsAll

+0

La tua seconda versione è migliore anche con i pool di thread, vedi [qui] (https://stackoverflow.com/questions/71/openmp-nested-for-loop-becomes-faster-when-having-parallel-before-outer- loop/31382775 # 31382775). –

+0

Oh, sono sorpreso che la tua seconda versione sia più lenta. Hai compilato con l'ottimizzazione? Ho provato il tuo codice con l'ottimizzazione e senza OpenMP il ciclo interno è ottimizzato a 1000 ma con OpenMP non lo è. Probabilmente non hai compilato con l'ottimizzazione. –

risposta

1

Un'implementazione di OpenMP può utilizzare il pooling di thread per eliminare il sovraccarico di thread iniziali durante l'incontro con un costrutto parallelo. Un pool di thread OMP_NUM_THREADS viene avviato per il primo costrutto parallelo e, dopo il completamento del costrutto, i thread slave vengono restituiti al pool. Questi thread inattivi possono essere riallocati quando viene rilevato un costrutto parallelo successivo.

Vedere ad esempio questa spiegazione di thread pooling in the Sun Studio OpenMP implementation.

+0

@nick, non interessa, quale implementazione del compilatore/OpenMP C stai usando? –

0

Sembra che si stiano seguendo i passaggi di Amdahl's Law: Si parla di processo parallelo rispetto al proprio overhead. Una cosa che Amadhl ha trovato è stata indipendentemente da quanto parallelismo hai inserito in un programma, avrà sempre la stessa velocità per cominciare. Il parallelismo inizia solo a migliorare il tempo di esecuzione/prestazioni quando il programma richiede lavoro sufficiente a compensare la potenza di elaborazione extra.