nicht sicher, was FREIGEGEBEN werden soll oder PRIVAT in der openmp-Schleife
Ich habe eine Schleife, welche updates Sie eine matrix a und ich will es machen openmp, aber ich bin mir nicht sicher, welche Variablen geteilt werden sollte und private. Ich hätte gedacht, dass nur ii und jj arbeiten würde, aber es funktioniert nicht. Ich glaube, ich brauche eine !$OMP ATOMIC UPDATE irgendwo zu...
Die Schleife nur berechnet den Abstand zwischen N und N-1 Teilchen und updates einer matrix A.
!$OMP PARALLEL DO PRIVATE(ii,jj)
do ii=1,N-1
do jj=ii+1,N
distance_vector=X(ii,:)-X(jj,:)
distance2=sum(distance_vector*distance_vector)
distance=DSQRT(distance2)
coff=distance*distance*distance
PE=PE-M(II)*M(JJ)/distance
A(jj,:)=A(jj,:)+(M(ii)/coff)*(distance_vector)
A(ii,:)=A(ii,:)-(M(jj)/coff)*(distance_vector)
end do
end do
!$OMP END PARALLEL DO
InformationsquelleAutor Griff | 2013-01-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die goldene Regel von OpenMP ist, dass alle Variablen (mit einigen Ausnahmen), definiert sind, die in einem äußeren Umfang, geteilt werden standardmäßig in der parallelen region. Da in Fortran vor 2008 gibt es keine lokalen Bereiche (d.h. es gibt keine
BLOCK ... END BLOCK
in früheren Versionen), alle Variablen (außerthreadprivate
) geteilt werden, das ist sehr natürlich für mich (im Gegensatz zu Ian Bush, ich bin kein großer fan der Verwendung vondefault(none)
und dann redeclaring die Sichtbarkeit aller 100+ lokale Variablen in verschiedenen komplexen wissenschaftlichen codes).Hier ist wie Sie bestimmen die sharing-Klasse für jede variable:
N
- geteilt, denn es sollten die gleichen in allen threads und Sie nur Lesen seinen Wert.ii
- es wird der Zähler der Schleife, unterliegen einer worksharing-Richtlinie, so seine sharing-Klasse ist vorbestimmt zu seinprivate
. Es tut nicht weh, ausdrücklich erklären, es in einemPRIVATE
- Klausel, aber das ist nicht wirklich notwendig.jj
- Zählvariable einer Schleife, die nicht Gegenstand eines worksharing-Richtlinie, daherjj
sollteprivate
.X
- geteilt, da alle threads verweisen und nur Lesen zu können.distance_vector
- offensichtlich sollteprivate
wie jeder thread arbeitet auf verschiedenen Paaren von Teilchen.distance
,distance2
, undcoff
- dito.M
- der freigegeben werden soll, aus den gleichen Gründen wieX
.PE
- fungiert als eine Akkumulator-variable (ich glaube, das ist die potentielle Energie des Systems) und sollte ein Gegenstand von einer Reduktion operation, d.h., sollte in einenREDUCTION(+:....)
- Klausel.A
- das ist heikel. Es könnte entweder gemeinsame und updates zuA(jj,:)
geschützt mit Synchronisation baut, oder verwenden Sie die Reduktion (OpenMP ermöglicht Reduktionen über array-Variablen in Fortran anders als in C/C++).A(ii,:)
nie geändert werden, um mehr als einen thread, damit es nicht eine Besondere Behandlung benötigen.Mit Reduktion über
A
im Ort, jeder thread bekommen würde, seine private KopieA
- und dies könnte ein memory hog, obwohl ich bezweifle, verwenden Sie diesen direkten O(N2) simulation code zur Berechnung von Systemen mit sehr große Anzahl von Teilchen. Es gibt auch einen bestimmten overhead in Zusammenhang mit der Reduzierung Umsetzung. In diesem Fall müssen Sie einfach hinzufügenA
auf die Liste derREDUCTION(+:...)
- Klausel.Mit synchronisieren Konstrukte haben Sie zwei Möglichkeiten. Entweder Sie verwenden die
ATOMIC
konstruieren oder dieCRITICAL
konstruieren. AlsATOMIC
ist nur anwendbar auf Skalare Kontexten, Sie würde zu "unvectorise" die Zuordnung Schleife und geltenATOMIC
zu jeder Anweisung separat, z.B.:Sie können auch schreiben dies als eine Schleife - vergessen Sie nicht zu erklären, den Schleifenzähler
private
.Mit
CRITICAL
es gibt keine Notwendigkeit, unvectorise der Schleife:Benennung von kritischen Regionen ist optional und ein bisschen unnötig, in diesem speziellen Fall, aber im Allgemeinen ist es erlaubt zu trennen unabhängigen kritischen Regionen.
Welche ist schneller? Abgerollt mit
ATOMIC
oderCRITICAL
? Es hängt von vielen Dingen ab. In der RegelCRITICAL
ist viel langsamer, da es oft mit Funktionsaufrufen die OpenMP-Laufzeitumgebung während der atomic-Schritten, zumindest auf x86-Systemen umgesetzt werden gesperrt, neben Anweisungen. Sie sagen oft: YMMV.Zu rekapitulieren, eine funktionierende version deiner Schleife sollte so etwas wie:
Ich bin davon ausgegangen, dass Ihr system ist 3-dimensional.
Mit all dies sagte, ich, die zweite Ian Bush, dass Sie brauchen, um zu überdenken, wie position und Beschleunigung Matrizen im Speicher angeordnet sind. Die richtige cache-Nutzung könnte steigern Sie Ihre code und würde auch ermöglichen, dass für bestimmte Operationen, z.B.
X(:,ii)-X(:,jj)
werden vektorisiert, d.h. implementiert mit Vektor-SIMD-Anweisungen.in C/C++ können diese Variablen deklariert werden, die innerhalb der innersten Schleife und dann sind Sie automatisch private. Dass Sie freigegeben werden, ergibt sich aus dem Wunsch die Semantik des OpenMP-match, dass der serial-code. Übrigens, Sie können loszuwerden, die atomics, wenn Sie vergessen, für eine Sekunde über Newtons drittes Gesetz, und führen Sie beide Schleife über
1,N
mit Zuordnung zuA(ii,:)
nur (wirkungslos).Gibt es trotzdem kann ich Ihnen zeigen, einen neuen code, ohne dass es post als Frage für Sie zu überprüfen? Es ist etwas einfacher, aber länger, und ich möchte nur, um es zu überprüfen, indem Sie sicherstellen, dass verstehe ich es richtig in Worte zu fassen. Danke.
Sie können laden Sie Sie auf Pastebin und dann poste einen link zum teilen hier. Aber ich kann nicht reagieren, bis morgen.
Übrigens, es ist die
DEFAULT(PRIVATE)
- Klausel. Es macht alle Variablen, die standardmäßig privat, und dann haben Sie beschreiben die gemeinsamen und reduzierten Bedingungen. Ich passe meine Antwort morgen, wenn ich meine Hände auf einem computer.InformationsquelleAutor Hristo Iliev
Wie geschrieben, du brauchst einiges an synchronisation zu vermeiden, eine race-condition. Betrachten Sie die 2-thread-Fall. Sagen, thread 0 gestartet mit ii=1, und so hält jj=2,3,4, .... und thread 1 startet mit ii=2, und so hält jj=3,4,5,6. Also wie geschrieben ist es möglich, dass thread 0 erwägt, ii=1,jj=3 und thread 1 anschaut, ii=2,jj=3 zur gleichen Zeit. Dies könnte zu Problemen bei der Linie
da beide threads den gleichen Wert von jj. Also ja, Sie brauchen, um synchronisieren Sie die Aktualisierungen Ein, um zu vermeiden, ein Rennen, aber ich muss zugeben, dass ich gut Weg, ist nicht sofort ersichtlich für mich. Ich denke, auf es und zu Bearbeiten, wenn etwas fällt mir ein.
Aber ich habe 3 andere Kommentare:
1) das memory access pattern ist schrecklich, und korrigieren wird, erwarte ich, dass geben mindestens so viel beschleunigen, wie jeder openmp-mit viel weniger Aufwand. In Fortran, die Sie wollen, zu gehen der erste index am schnellsten dadurch wird sichergestellt, dass der Speicher-Zugriffe sind räumlich lokalen und sorgen so für eine gute Nutzung der Speicher-Hierarchie. Gegeben, dass dies das wichtigste für eine gute Leistung auf einer modernen Maschine, die Sie sollten wirklich versuchen, dieses Recht zu bekommen. Also das würde besser sein, wenn Sie arrangieren können, die arrays, so dass die oben kann geschrieben werden als
Hinweis, wie das geht runter der erste index, eher als die zweite, weil Sie haben.
2) Wenn Sie wollen, verwenden Sie die openmp-ich empfehle, verwenden Sie default(None), es hilft zu vermeiden böse bugs. Wenn Sie einer meiner Schüler, die Sie verlieren würden, Lasten von Marken, dies nicht zu tun!
3) Dsqrt archaisch - modernes Fortran (also alles, was nach 1967) in alle, aber ein paar obskuren Fällen sqrt ist ausreichend gut genug, und ist flexibler
Yeah - fair Kommentar. ii und jj sollten private wie jeder thread arbeitet seine eigene Kombination von Iterationen. Die einfachste Lösung für das Rennen zu verwenden omp critical to schützen Sie die problem-Zeile. Ich muss zugeben, ich bin nicht sicher, ob Sie verwenden können, atomic mit Linien, die Einbeziehung der array-syntax - meine Vermutung ist, dass Sie nicht können.
Als Zwischenfrage: ist die Potenzierung schneller mit
a*a*a
statta**3
?Neben Ian Bush die Antwort, die Sie benötigen, im Auge zu behalten, dass jede variable, die in ein Gewinde envornment, Sie machen eine Zuordnung zu entweder zugegriffen atomic thread oder privat. So distance_vector, distanz2 -, Distanz -, Kaff -, PE -, müssen alle thread_private.
eineingegen eine3? Schreiben3 als klarer wer liest den code. Es ist sehr wahrscheinlich, dass der compiler emittieren Maschine Anweisungen für eineneinein, wenn, die ist deutlich schneller.
InformationsquelleAutor Ian Bush