OpenMP-Parallelisierung der Matrixmultiplikation durch eine dreifache for-Schleife (performance-Problem)
Ich Schreibe ein Programm für die matrix-Multiplikation mit OpenMP, dass, für den cache die Bequemlichkeit, implementiert die Multiplikation A x B(transponiert) Zeilen X Zeilen anstelle der klassischen A-x B Zeilen x Spalten, für eine bessere cache-Effizienz. Dies zu tun, vor denen ich Stand, eine interessante Tatsache für mich ist das illogic: wenn in diesem code habe ich parallelisieren der extern-Schleife das Programm ist langsamer als wenn ich die OpenMP-Anweisungen in der innersten Schleife, in meinem computer die Zeiten sind 10.9 vs 8,1 Sekunden.
//A and B are double* allocated with malloc, Nu is the lenght of the matrixes
//which are square
//#pragma omp parallel for
for (i=0; i<Nu; i++){
for (j=0; j<Nu; j++){
*(C+(i*Nu+j)) = 0.;
#pragma omp parallel for
for(k=0;k<Nu ;k++){
*(C+(i*Nu+j))+=*(A+(i*Nu+k)) * *(B+(j*Nu+k));//C(i,j)=sum(over k) A(i,k)*B(k,j)
}
}
}
- Von tweaking omp Parameter habe ich 200% Geschwindigkeit auf meiner Maschine. original: llcomp.googlecode.com/hg/examples/mxm.c Strom: codepad.org/nSfZHp03
- Schöne Lösung. Ja, OpenMP, ist ein bischen tricky
- Code, der verwendet
'fortran'
Speicher-layout für dieB
matrix läuft 4-8 schneller (der größte Vorteil) für 1000x1000-Matrizen (Gewinde-version nimmt0.5
Sekunden). gist.github.com/790865 - Haben Sie schätzt Ihren Gflops/s? Sollte es 2.0*n^3/Zeit. Vergleichen Sie das mit den max für deine CPU: Häufigkeit * (SIMD_width)* (2 ILP) * (Anzahl der Kerne). e.g auf meinem 2600k ist (4GHz) * 4(AVX) * 2 (ILP) * 4 Kerne = 128 DP-Gflops/s. Wahrscheinlich, Ihr Wirkungsgrad ist weniger als 10%.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Versuchen zu schlagen, die dadurch weniger Häufig. Dies bedingt eine cacheline-sharing und verhindert, dass der Betrieb parallel laufen. Verwenden eine lokale variable, sondern erlauben die meisten der schreibt in den einzelnen Kern-L1 cache.
Auch, die Verwendung von
restrict
helfen kann. Ansonsten der compiler kann nicht garantieren, dass schreibtC
ändern sich nichtA
undB
.Versuchen:
Außerdem denke ich, Elalfer ist Recht Geschehnissen zu reduzieren, wenn Sie parallelisieren, wird die innerste Schleife.
Bcol = B + i*Nu
es solltej
.Könnten Sie wahrscheinlich einige Abhängigkeiten in den Daten, wenn Sie parallelisieren der äußeren Schleife und der compiler ist nicht in der Lage, um es herauszufinden, und fügt zusätzliche sperren.
Wahrscheinlich entscheidet, dass unterschiedliche äußere schleifendurchläufe schreiben konnte, in der gleichen
(C+(i*Nu+j))
und es fügt access-sperren zu schützen.Compiler könnte wahrscheinlich herausfinden, dass es keine Abhängigkeiten gibt, wenn Sie werden parallelisieren, die 2. Schleife. Aber herauszufinden, dass es keine Abhängigkeiten gibt, die Parallelisierung der äußeren Schleife ist nicht so trivial für einen compiler.
UPDATE
Einige performance-Messungen.
Hallo, mal wieder. Es sieht aus wie 1000 Doppelzimmer
*
und+
ist nicht genug, um die Kosten zu decken von threads-Synchronisation.Ich habe getan, einige kleine tests und einfache Vektor-Skalar-Multiplikation ist nicht wirksam, mit der openmp-es sei denn, die Anzahl der Elemente ist weniger als ~10'000. Im Grunde größer das array ist, mehr Leistung bekommst du von der Verwendung von openmp.
So Parallelisierung der innersten Schleife müssen Sie separate Aufgabe zwischen verschiedenen threads und sammeln Daten wieder 1'000'000 mal.
PS. Versuchen Sie, Intel ICC, es ist ein bisschen frei für Studenten und open-source-Projekte. Ich erinnere mich, dass mit openmp für die kleineren, die 10'000-Elemente-arrays.
UPDATE 2: Reduzierung Beispiel
reduction
- Klausel für die innere Schleife? Ich werde versuchen, diesen code später. Es sieht aus wie Spaß, sich zu erinnern, wie die Arbeit mit OpenMP. Welche compiler verwenden Sie? gcc oder icc? Und was ist die Größe der matrix?omp_get_wtime()
?time ./bin
. Es war vor 6 Jahren 😉