2016-09-08 2 views
1

Gibt es eine spezielle "Warte auf Ereignis" -Funktion, die auf der Geräteseite gleichzeitig auf 3 Warteschlangen warten kann, so dass nicht seriell auf alle Warteschlangen gewartet wird Host-Seite?3 Warteschlangen + 1 End- oder geräteseitige Kontrollpunkte für alle Warteschlangen

Gibt es einen Checkpoint-Befehl, der in eine Befehlswarteschlange gesendet wird, so dass er warten muss, bis andere Befehlswarteschlangen dieselbe (vertikale) Schranke/denselben Checkpoint abwarten und von der Geräteseite aus fortfahren, sodass kein Host-Round-Trip erforderlich ist ?

Vorerst habe ich versucht, zwei verschiedene Versionen:

clWaitForEvents(3, evt_); 

und

int evtStatus0 = 0; 
clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus0, NULL); 

while (evtStatus0 > 0) 
{ 

    clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus0, NULL); 
    Sleep(0); 
} 

int evtStatus1 = 0; 
clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus1, NULL); 

while (evtStatus1 > 0) 
{ 

    clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus1, NULL); 
    Sleep(0); 
} 


int evtStatus2 = 0; 
clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus2, NULL); 

while (evtStatus2 > 0) 
{ 

    clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus2, NULL); 

    Sleep(0); 
} 

zweite ein bisschen schneller ist (ich sah es von jemand anderem) und beide nach 3 bündig Befehle ausgeführt werden .

Wenn man sich die CodeXL-Profiler-Ergebnisse anschaut, wartet man zuerst länger zwischen Endpunkten und einige Operationen scheinen sich nicht einmal zu überlappen. Die zweite zeigt 3 Endpunkte sind alle innerhalb von 3 Millisekunden, so dass es schneller ist und längere Teile überlappen (lesen + schreiben + berechnen zur gleichen Zeit).

Wenn es eine Möglichkeit gibt, dies mit nur einem Wartebefehl von der Host-Seite zu erreichen, muss es auch eine "Flush" -Version geben, aber ich konnte nicht finden.

Gibt es eine Möglichkeit, unter Bild zu erreichen, anstatt zwischen jedem Pipelineschritt Flushes hinzuzufügen?

queue1 write checkpoint write checkpoint write 
queue2 -    compute checkpoint compute checkpoint compute 
queue3 -      checkpoint read checkpoint read  

Alle Prüfpunkte müssen vertikal synchronisiert sein, und alle diese Aktionen dürfen erst beginnen, wenn ein Signal ausgegeben wird. Wie zum Beispiel: (? Noch besser, nur 1 Finish für alle Warteschlangen)

queue1.ndwrite(...); 
queue1.ndcheckpoint(...); 
queue1.ndwrite(...); 
queue1.ndcheckpoint(...); 
queue1.ndwrite(...); 
queue2.ndrangekernel(...); 
queue2.ndcheckpoint(...); 
queue2.ndrangekernel(...); 
queue2.ndcheckpoint(...); 
queue2.ndrangekernel(...); 
queue3.ndread(...); 
queue3.ndcheckpoint(...); 
queue3.ndread(...); 
queue3.ndcheckpoint(...); 
queue3.ndread(...); 

queue1.flush() 
queue2.flush() 
queue3.flush() 

queue1.finish() 
queue2.finish() 
queue3.finish() 

Checkpoints all in Geräteseite sind und nur 3 Finish Befehle von Host-Seite

Wie binde ich 3 Warteschlangen 3 erforderlich behandelt werden Ereignisse mit "clWaitForEvents (3, evt_);" für jetzt ist:

Wenn diese "Enqueue-Barriere" mit anderen Warteschlangen sprechen kann, wie könnte ich das erreichen? Muss ich hostseitige Ereignisse am Leben erhalten, bis alle Warteschlangen fertig sind, oder kann ich sie löschen oder später wiederverwenden? Aus der Dokumentation, wie es scheint Ereignis die erste Barriere kann auf die zweite Warteschlange und zweite Barriere des Ereignisses gesetzt werden kann zusammen mit ersten Veranstaltung an dritte gesetzt werden, so ist es vielleicht wie:

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[0]); 
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(evt_0, &evt[1]); 
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(evt_0_and_1, &evt[2]); 

in the end wait for only evt[2] maybe or using only 1 same event for all: 

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[0]); 
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[1]); 
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[2]); 

where to get sameEvt object? 

jemand versucht das? Sollte ich alle Warteschlangen mit einer Barriere starten, so dass sie nicht starten, bis ich ein Ereignis von der Host-Seite oder Lazy-Ausführungen von "Enqueue" ist% 100 vertrauenswürdig zu "nicht zu starten, bis ich flush/Finish" sie? Wie hebe ich ein Ereignis von Host zu Gerät an (sameEvt hat keine "raise" -Funktion, ist das clCreateUserEvent?)?

Alle 3 Warteschlangen sind in der richtigen Reihenfolge und in demselben Kontext. Der Out-of-Order-Typ wird nicht von allen Grafikkarten unterstützt. C++ - Bindungen werden verwendet.

Auch gibt es enqueueWaitList (ist dies veraltet?) Und clEnqueueMarker, aber ich weiß nicht, wie man sie verwendet und die Dokumentation hat kein Beispiel in Khronos 'Website.

Antwort

1

Sie haben zu viele Fragen gestellt und zu viele Varianten angegeben, um Ihnen die einzige Lösung zu bieten. Daher werde ich versuchen, allgemein zu antworten, dass Sie die am besten geeignete Lösung finden können.

Wenn die Warteschlangen an denselben Kontext gebunden sind (möglicherweise an verschiedene Geräte im selben Kontext), ist es möglich, sie über die Ereignisse zu synchronisieren. I.e. Sie können ein Ereignis von einem Befehl erhalten, der an eine Warteschlange gesendet wurde, und dieses Ereignis verwenden, um einen Befehl zu synchronisieren, der an eine andere Warteschlange gesendet wurde, z.

queue1.enqueue(comm1, /*dependency*/ NULL, /*result event*/ &e1); 
queue2.enqueue(comm2, /*dependency*/ &e1, /*result event*/ NULL); 

In diesem Beispiel comm2 für comm1 Fertigstellung warten.

Wenn Sie zuerst Befehle in die Warteschlange einreihen müssen, aber nicht, damit sie ausgeführt werden, können Sie ein Benutzerereignis (clCreateUserEvent) erstellen und es manuell signalisieren (clSetUserEventStatus). Die Implementierung kann Befehle verarbeiten, sobald sie in die Warteschlange gestellt wurden (der Treiber muss nicht auf flush warten).

Die Barriere scheint für Ihren Zweck übertrieben, weil sie auf alle Befehle wartet, die zuvor an die Warteschlange übergeben wurden. Sie können wirklich clEnqueueMarker verwenden, mit dem Sie auf alle Ereignisse warten und ein Ereignis für andere Befehle bereitstellen können.

Soweit ich weiß, können Sie das Ereignis jederzeit behalten, wenn Sie es nicht mehr benötigen. Die Implementierung sollte die Lebensdauer des Ereignisses verlängern, wenn es für interne Zwecke benötigt wird.

Ich weiß nicht, was ist enqueueWaitList.

Off-Thema: Wenn Sie nicht-triviale Abhängigkeiten zwischen Berechnungen benötigen, können Sie TBB flow graph und opencl_node betrachten. Die opencl_node verwendet Ereignisse für die Synchronisierung und vermeidet, wenn möglich, "Host-Gerät" -Synchronisationen. Es kann jedoch schwierig sein, mehrere Warteschlangen für dasselbe Gerät zu verwenden.

Soweit ich weiß, unterstützt Intel HD Graphics 530 Out-of-Order-Warteschlangen (mindestens Host-Seite).

+0

Danke, ich benutzte Marker als erste Enqueue dann 1 Sekunde nach dem Flush + Finish, ich setzte es mit clsetusereventstatus. Es begann alle Warteschlangen genau 1 Sekunde. Ich werde das selbe mit dem Endpunkt versuchen, um ein einzelnes Ereignis zu erhalten, auf das gewartet werden muss (mit Marker, aber mit Device Side Event). –

1

Sie machen es viel schwieriger als es sein muss. Nehmen Sie in der Schreibwarteschlange ein Ereignis an. Verwenden Sie dies als Bedingung für die Berechnung in der Rechenwarteschlange, und nehmen Sie ein anderes Ereignis. Verwenden Sie das als Bedingung für das Lesen in der Lesewarteschlange. Es gibt keinen Grund, eine andere Synchronisierung zu erzwingen. Hinweis: Meine Interpretation der Spezifikation besagt, dass Sie clFlush in einer Warteschlange ausführen müssen, aus der Sie ein Ereignis übernommen haben, bevor Sie dieses Ereignis als Bedingung für eine andere Warteschlange verwenden.

+0

Erprobt Ihren Weg, einfach 1-Wege-Event-Kette auf 3 Warteschlangen, Treiber konnte sie nicht überlappende Positionen und daraus resultierende serielle alle kleineren Kernel. Es dauerte 140 ms, während 1 Warteschlange (geordnet) 127 ms dauerte. Wenn ich dasselbe Ereignis zu einer anderen Warteschlange hinzufüge (die in einer eigenen Warteschlange nicht benötigt wird), aktiviert das 2-Wege-Ereignis nur überlappende Ausführungen von Lesen + Schreiben + Berechnen, was 112 ms ergibt. Entweder zeigt CodeXLs Timeline-Diagramm falsch an und auch mein eigener C# Stoppuhr-Timer ist falsch oder der Treiber ist nicht in der Lage. Es schließt die Schreibvorgänge vollständig ab, bevor die Berechnung beginnt. Dann endet die Berechnung, dann beginnt das Lesen. In allen Fällen haben Ereignisse jedoch eine Latenz von 1-2 ms. –

+0

Vielleicht R7-240 ist nicht in der Lage 3-Queue-Parallelität in der Hardware (emuliert Software), da Rechen nicht vorhanden ist, sollte es halbe Zeit (lesen Überlappungen schreiben) haben? Vielleicht nur compute + read oder compute + write fähig? –

+0

Sie hatten Recht, es gab keine Notwendigkeit, es schwieriger zu machen.Ich habe nur 4 Warteschlangen verwendet, das Pipelining horizontal statt vertikal gemacht, und keine Ereignisse, es überlappt effizienter und zeigt keine Lücken zwischen den Befehlen (auch +1 Warteschlange fügt etwas mehr Effizienz hinzu) –