2012-04-12 14 views
1

Ich entwickle eine numerische Simulation, die parallel laufen kann, um die Geschwindigkeit zu erhöhen. Normalerweise lasse ich die Simulation mehrere Male laufen und mittle dann die einzelnen Ergebnisse. Diese Schleife, die mehrere Durchläufe, parallelisiert wird mit openmp:Warum ist die Parallelisierung mit openmp auf manchen Maschinen langsamer?

// set the number of threads 
    omp_set_num_threads (prms.nthreads); 

#pragma omp parallel if(prms.parallel) shared(total) private(iRun) 
    { 
#pragma omp for schedule(dynamic) 
     for (iRun = 1; iRun <= prms.number_runs; iRun++) 
     { 
      // perform the simulation 
     } 
    } 

Es gibt buchstäblich keine freigegebenen Variablen, mit der Ausnahme total, der ein Array der Größe iRun wobei jedes Element das Ergebnis der entsprechenden Lauf hält. Bei allen Maschinen, die ich bisher getestet habe, stieg die Geschwindigkeit proportional mit der Anzahl der Kerne; Es ist also 4 mal so schnell bei Verwendung von 4 Threads als ohne Parallelisierung. Doch auf unserem Computer-Cluster dann ist dies nicht der Fall ist (der zweite Lauf ist mit Parallelisierung und verwendet 2 Verknüpfungen, so dass es doppelt so schnell sein soll):

$ time hop ... 

real 0m50.595s 
user 0m50.484s 
sys 0m0.088s 

$ time hop ... -P 

real 1m35.505s 
user 3m9.238s 
sys 0m0.134s 

Wie Sie sehen, sind die parallelen Berechnungen wesentlich langsamer als die serialisierten, sogar insgesamt. Ich bin sicher, dass dies kein Speicherproblem ist und dass der Computer mehrere Kerne hat.

Was könnte das Problem sein? Ist es vielleicht die Openmp-Implementierung? Oder ist etwas im System falsch konfiguriert? Ich weiß wirklich nicht, wonach ich suchen soll.

+1

sein kann, was ich sehe, ist, dass der Cluster-Implementierungen von real, Benutzer und sys höhere Zeiten berichten als die entsprechenden Werte auf Ihrer Testmaschine. Welche Zeitpläne erhalten Sie, wenn Sie die Uhr an der Wand Ihres Büros verwenden? Oder, genauer gesagt, welche Zeiten bekommen Sie, wenn Sie am Anfang und am Ende des Programms Anrufe in eine Uhrroutine einfügen? –

+0

Beide Läufe sind auf der gleichen Maschine, ich habe nur einmal die -P-Flag gesetzt, so dass das Programm parallel läuft. Der zweite Lauf war wirklich länger. Auf meinem Laptop zum Beispiel würde der zweite Lauf ungefähr 25 oder 30 Sekunden zeigen, doppelt so schnell wie der erste ... – janoliver

+0

siehe http://stackoverflow.com/questions/556405/what-do-real-user-- and-sys-mean-in-the-output-of-time1 für einen Teil einer Erklärung –

Antwort

0

Es scheint wie Cache-Kohärenz ein Problem sein würde. Wenn total Ihr freigegebenes Array ist und jeder Thread seine eigene Zelle in total aktualisiert, ist es sehr wahrscheinlich, dass die Threads benachbarte Werte in total aktualisieren, die sich möglicherweise in derselben Cachezeile befinden, da die Threads dynamisch arbeiten.

Auf Ihren Testmaschinen wird dies wahrscheinlich nicht sehr weh tun, da total wahrscheinlich in einem gemeinsamen L3 kohärent ist, aber in einem Cluster, wo es über das Netzwerk hin und her gehen muss, sollte dies wehtun.

0

Da ich nicht genug Ruf, ich bin, diese als Antwort anstatt ein Kommentar:

Haben Sie sorgen dafür, dass Sie die Daten für Ihre verschiedene Simulationen auch parallel und nicht seriell initialisieren?

Ich weiß, dass dies je nach Ihrer Architektur einen großen Unterschied machen kann. Vielleicht können Sie einen Hinweis auf die Architekturen geben.

Um genau zu sein: Wenn Sie

for(i = 1; i < prms.number_runs; ++i) 
    allocAndInitializeSimulationData(i) 

#pragma omp parallel if(prms.parallel) shared(total) private(iRun) 
{ 
#pragma omp for schedule(dynamic) 
    for (iRun = 1; iRun <= prms.number_runs; iRun++) 
    { 
     // perform the simulation 
    } 
} 

tun, die wirklich viel langsamer als

#pragma omp parallel if(prms.parallel) shared(total) private(iRun) 
{ 
    #pragma omp for schedule(dynamic) 
    for(i = 1; i < prms.number_runs; ++i) 
     initializeAndAllocSimulation(i) 

    #pragma omp for schedule(dynamic) 
    for (iRun = 1; iRun <= prms.number_runs; iRun++) 
    { 
     // perform the simulation 
    } 
} 
+1

Ich löste das Problem, wie in den Kommentaren zu meiner Frage erläutert. Danke trotzdem. – janoliver

Verwandte Themen