Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
C++OpenCl: kann CL_MEM READ_WRITE zum Überschreiben benutzt werden?
kann ich das Attribut CL_MEM READ_WRITE bei clCreateBuffer() setzen, um Daten einer Variable in den Kernel zu schaufeln, der Kernel überarbeitet sie, und gibt sie dann in der gleichen Variable zurück?
Oder ist CL_MEM_READ_WRITE nur dazu gedacht, um innerhalb der WorkItems des Kernels zu kommunizieren?
Soweit ich (aus meinem eher theoretischen Wissen zu OpenCL) weiß dient CL_MEM READ_WRITE dazu, dem Kernel Lese- und Schreibrechte für das erzeugte Speicherobjekt (hier: memObjects[8]), das dann auf dem Device benutzt wird, zu geben. Dabei werden die Parameter, die in lifeStadium stehen, auf das Device kopiert. Das Zurücklesen der Ergebnisse erfolgt dann über clEnqueueReadBuffer(), wobei das Ergebnis dann in dem dafür erzeugten Speicherobjekt memObjects[9] steht.
Eine Anmerkung: müsste bei CL_MEM READ_WRITE nicht noch CL_MEM_COPY_HOST_PTR stehen (mit einem | getrennt)? Denn nur so werden die Daten auch auf das Device kopiert, sonst werden sie wahrscheinlich vom RAM gelesen (bin nicht ganz sicher), was sehr langsam sein kann.
CL_MEM_READ_WRITE bezieht sich rein auf den kernel und sagt dass im Kernel-Code sowohl Lese- wie Schreibzugriffe auf den buffer möglich sind. Es hat nichts mit der Beziehung zwischen host-memory und device-memory (buffer) zu tun.
Was du meinst ist ev. das CL_MEM_USE_HOST_PTR flag, da entspricht der buffer mehr oder weniger dem angegebenen host memory. Aber: 1) Entweder host oder OpenCL greifen auf die geteilte memory-Region zu, nicht beide, was synchronisiert werden muss (clEnqueueMapBuffer / clEnqueueUnmapMemObject), und 2) die Kommunikation kann sehr langsam sein (etwa über PCIe Bus). Außerdem darf die OpenCL Implementierung nach wie vor eine Kopie vom buffer am device anlegen (nicht mal die Speichereinsparung am device ist garantiert). Unter normalen Umständen nimmt man dieses flag nicht, nur wenn irgendwelche Randbedingungen einen dazu zwingen.
Sogar wenn das bei OpenCL immer etwas Stochern im Nebel ist, und unter der Annahme es handelt sich um eine Diskrete-PCIE-GPU:
1. Bei CL_MEM_USE_HOST_PTR oder CL_MEM_ALLOC_HOST_PTR können (!!!) OpenCL-Implementierungen den Host-Speicherbereich in pinned Memory verwandeln, so dass das Device Zugriff per DMA hat. Dadurch geht das Kopieren über PCI-E zwischen diesem pinned Bufferobjekt und einem Bufferobjekt im Device-Memory schneller. (siehe http://www.nvidia.com/content/cudaz...s/papers/NVIDIA_OpenCL_BestPracticesGuide.pdf)
2. Zusätzlich besitzen manche Devices die Möglichkeit des Zero-Copys bei pinned Memory. Das heißt, dass die OpenCL Implementierung nicht erst den Buffer komplett im Device cachen muss, sondern dass ein Kernel direkt wahlfreien Zugriff auf den pinned-Memory-Bereich auf den Host hat. Dadurch spart man sich wiederum das Kopieren der Daten. (Siehe http://www.naic.edu/~phil/hardware/nvidia/doc/src/simpleZeroCopy/doc/CUDA2.2PinnedMemoryAPIs.pdf) Allerdings weiß ich das nur von NVIDIA-GPUs und ich weiß nicht ob NVIDIA dieses Feature in OpenCL überhaupt implementiert hat, da es seinen OpenCL-Support eingestellt hat.
Anmerkung: Hier versagt OpenCL m.E. wieder komplett durch seine Allgemeintheit und die daraus resultierenden Obskurität komplett. Zum Teufel noch mal - Wie kann man nur eine 400 Seiten API für heterogene Systeme schreiben ohne die Wöter DMA oder pinned Memory zu verwenden?
1. Bei CL_MEM_USE_HOST_PTR oder CL_MEM_ALLOC_HOST_PTR können (!!!) OpenCL-Implementierungen den Host-Speicherbereich in pinned Memory verwandeln, so dass das Device Zugriff per DMA hat.
2. Zusätzlich besitzen manche Devices die Möglichkeit des Zero-Copys bei pinned Memory. Das heißt, dass die OpenCL Implementierung nicht erst den Buffer komplett im Device cachen muss, sondern dass ein Kernel direkt wahlfreien Zugriff auf den pinned-Memory-Bereich auf den Host hat.
Unterscheide zwischen Theorie und Praxis. Theoretisch können OpenCL Implementierungen alles mögliche wundervolle und magische machen, genauso muss der Standard aber auch weniger spezifisch bzgl. Garantien sein, da ja alle möglichen devices unterstützt werden sollen (Systeme die 'weniger' können wie auch welche die anders als 'klassisch' sind, etwa APUs).
Praktisch gesehen und quasi 'inoffizieller OpenCL Standard' entspricht CL_MEM_ALLOC_HOST_PTR pinned memory für DMA solange es für den device sinnvoll ist; bei diskreten GPUs kann man davon ausgehen, muss aber die Bedingungen in den vendor-Docs (AMD / Nvidia) nachlesen. CL_MEM_USE_HOST_PTR und pinned memory ist ziemlich widersprüchlich (praktisch gesehen schließen sie sich aus).
Ob eine Implementierung zero-copy macht oder nicht ist aus Sicht des Programmierers ziemlich irrelevant, und bei diskreten GPUs bleibt der PCIe-Bus sowieso das bottleneck. Genauso ist es fallabhängig ob pinned memory ein Programm schneller oder langsamer macht. In meinen Augen ist CL_MEM_ALLOC_HOST_PTR eine Optimierung, und wie heißts so schön, never optimize.
Unterscheide zwischen Theorie und Praxis. Theoretisch können OpenCL Implementierungen alles mögliche wundervolle und magische machen, genauso muss der Standard aber auch weniger spezifisch bzgl. Garantien sein, da ja alle möglichen devices unterstützt werden sollen (Systeme die 'weniger' können wie auch welche die anders als 'klassisch' sind, etwa APUs).
Mein Problem bei dem Standard liegt weniger daran, dass OpenCL-Implementierungen dank der allgemeinen Spezifikation alles mögliche und wunderbare machen können, sondern daran, dass man nur kaum abfragen kann, was sie genau tut oder wie ihr Device tickt - gerade wenn man als Device soetwas hat wie eine GPU, wo einem wenn man es ungeschickt anstellt die Performance in den Keller sinkt. Denn in diesem Fall könnte man prinzipiell sein Programm optimieren, wenn man die Eigenschaften der Implementierung abfrägt und dann dementsprechend handelt. Aktuell muss man ohne die Möglichkeit der Abfrage die Vendor-Specs studieren und danach optimieren. Dann hat man hardgecodet eine Optimierung für ein paar Vendors (z.B. if(AMDGPU) if(NVIDIAGPU) if(STANDARD) ), allerdings hat man dadurch keinerlei Garantie, dass diese Optimierung für den spezifischen Vendor auch immer ihre Gültigkeit haben wird. Wegen solchen Optimierungen lief auch das mein letztes OpenCL-Programm fehlerfrei nur noch auf NVIDIA-GPUs und das war auch letztendlich der Grund dafür, dass ich OpenCL den Rücken gekehrt habe.
CL_MEM_USE_HOST_PTR und pinned memory ist ziemlich widersprüchlich (praktisch gesehen schließen sie sich aus).
Da NVIDIA OpenCL irgendwie auf seine CUDA Architektur abbildet ist es möglich, dass man dadurch ebenfalls an pinned Memory bei NVIDIA kommt.
Ob eine Implementierung zero-copy macht oder nicht ist aus Sicht des Programmierers ziemlich irrelevant, und bei diskreten GPUs bleibt der PCIe-Bus sowieso das bottleneck. Genauso ist es fallabhängig ob pinned memory ein Programm schneller oder langsamer macht. In meinen Augen ist CL_MEM_ALLOC_HOST_PTR eine Optimierung, und wie heißts so schön, never optimize.
Naja an sich eine Frage was man gerade tun will (oder soll wenn man wo eingestellt ist): Will man einfach nur ein Programm irgendwie parallel haben und auf der GPU/CPU/Wasweißich laufen haben, mag das tatsächlich so sein. Will man optimieren, dann wird es an sehr viel Stellen interessant was die Implementierung genau tut - wie hier mit dem Zero Copy. Z.B. kann man bei Zero-Copy "problemlos" eine größere Datenstruktur zwischen Host und Device teilen ohne dass man sie eben komplett rüberladen müsste, wodurch man sich (kostbaren) Device-Memory und PCIE-Bandbreite spart. Eben deshalb weil PCI-E der Bottleneck ist, kann man dadurch prinzipiell die Performance erhöhen.
@nai:
Du bist v.a. mit CUDA unterwegs, oder?
Im allgemeinen heißt es das CUDA technisch gesehen OpenCL etwas überlegen ist (wobei man streiten kann ob klar oder nur marginal), aber eben zum Preis der Bindung an Nvidia und entsprechende Hardware / Plattformen. Für die von dir genannten Funktion cudaHostRegister fällt mir beim Durchlesen ihrer Spezifikation etwa kein OpenCL-Äquivalent ein (ich wüsste nicht wie man unter OpenCL host-memory nachträglich pinned machen kann).
Die Stärke von OpenCL ist Portabilität, und ich denke wenn man diese Portabilität im Auge hat muss man auch bereit sein Abstriche bzgl. Detailoptimierungen zu machen (die performance-wichtigen Dinge wie coalesced memory access oder voll ausgeladene work-groups gelten eh für z.B. alle diskreten GPUs, fallen bei mir also keineswegs unter Detailoptimierungen. Lästiger ist da etwa der Unterschied zwischen einer GPU und einer CPU als device, denn optimale memory-access-patterns sind da unterschiedlich). Man kann aber natürlich auch OpenCL nutzen und das Programm trotzdem für eine bestimmten device-Typ trimmen.
In meinen Augen ist das größte praktische Problem der kleinste gemeinsame Nenner den man ansetzen muss. Intel und AMD haben etwa OpenCL 1.2 in ihren SDKs implementiert (2.0 ist ja schon verabschiedet), Nvidia ist nach wie vor bei 1.1 -> ein portables Programm darf daher nicht über 1.1 hinausgehen.Ditto sollte man nicht davon ausgehen dass Zero Copy existiert, oder etwa out-of-order command queues wirklich out-of-order sind.
Für die von dir genannten Funktion cudaHostRegister fällt mir beim Durchlesen ihrer Spezifikation etwa kein OpenCL-Äquivalent ein (ich wüsste nicht wie man unter OpenCL host-memory nachträglich pinned machen kann).
Die Stärke von OpenCL ist Portabilität, und ich denke wenn man diese Portabilität im Auge hat muss man auch bereit sein Abstriche bzgl. Detailoptimierungen zu machen (die performance-wichtigen Dinge wie coalesced memory access oder voll ausgeladene work-groups gelten eh für z.B. alle diskreten GPUs, fallen bei mir also keineswegs unter Detailoptimierungen. Lästiger ist da etwa der Unterschied zwischen einer GPU und einer CPU als device, denn optimale memory-access-patterns sind da unterschiedlich). Man kann aber natürlich auch OpenCL nutzen und das Programm trotzdem für eine bestimmten device-Typ trimmen.
Mein Problem dabei ist, dass Coalescing bereits extrem von den Warps oder Wavefronts abhängig ist, welche in OpenCLs Abstraktion nicht mehr existieren - wenigstens lässt sich bei NVIDIA die Warp-Größe per Extension abfragen; bei AMD jedoch nicht. Dann gibt es noch Intel-GPUs bei welchen die Warp-Größe von Kernel zu Kernel verschieden ist und Mali-GPUs bei welchen weder Warps noch Wavefronts existieren. Wenn man versucht nur das Coalescing auf ein Device zu optimieren, dann geht nur auf anderen Devices Performance verloren. Allerdings gibt es fortgeschrittenere Optimierungen, wo man eben auch versucht den Kontroll-Fluss auf Warp/Wavefrontbasis zu optimieren. Dafür verwendet man Entscheidungsprozesse: Wie sieht es im Warp aus? Was ist für den Warp am sinnvollsten als Nächstes zu tun? Hierfür bietet CUDA spezielle Warp-Vote-Functions (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#warp-vote-functions). Diese kann man zwar auch in OpenCL über den local Memory nachprogrammieren, allerdings benötigt man dafür dann unbedingt die nicht gegebene Warp-Größe. Ist die Warp-Größe bei der Entscheidung falsch dann geht nicht nur die Performance sondern viel schlimmer auch die Korrektheit des Programms verloren.
Im allgemeinen heißt es das CUDA technisch gesehen OpenCL etwas überlegen ist (wobei man streiten kann ob klar oder nur marginal), aber eben zum Preis der Bindung an Nvidia und entsprechende Hardware / Plattformen.
. . .
In meinen Augen ist das größte praktische Problem der kleinste gemeinsame Nenner den man ansetzen muss. Intel und AMD haben etwa OpenCL 1.2 in ihren SDKs implementiert (2.0 ist ja schon verabschiedet), Nvidia ist nach wie vor bei 1.1 -> ein portables Programm darf daher nicht über 1.1 hinausgehen.
Die Problematik der Bindung ist mir bewusst, vor allem da AMD-GPUs auch ganz gut sind. Allerdings ist in meinen Augen das Grundkonzept von OpenCL bereits komplett kaputt. Man versucht alles mögliche unter einen Hut zu bringen. Eine API für alle Device-Typen. Eine eierlegende Wollmilchsau. Es mag Fälle geben, wo so etwas praktisch ist. Jedoch in den meisten Use-Cases will man doch nur GPGPU machen oder alternativ spezifisch für ein anderen Device-Typ wie eine CPU oder einen CELL programmieren. Da bringt einem die Portabilität zu anderen Devices nichts. Bei GPGPU wird man jedoch mangels Alternativen zu OpenCL gezwungen - selbst AMD "verkauft" einem OpenCL mehr oder weniger als die offizielle GPGPU-API für seine GPUs. Deshalb würde ich mir dementsprechend eben eine spezifische reine GPGPU-API wünschen, welche eben versucht auf die wichtigsten GPU-Eigenschaften wie Occupancy, Register, Warps, Wavefronts, Coalescing, DMA und etc. einzugehen. Wenn man dann gleich noch die beiden größten anderen Design-Schwächen von OpenCL - nämlich die Trennung zwischen Device- und Hostcode und die Verwendung von Buffern statts Pointern beseitigen könnte - wäre ich komplett zu Frieden.
Sorry ich verstehe kaum was, so sehr mit der internen Funktion habe ich mich noch nicht beschäftigt. Da meine Zeit begrenzt ist, könnt ihr mir nen Tipp geben ob es nun nen einfachen weg gibt oder nicht?
Sorry ich verstehe kaum was, so sehr mit der internen Funktion habe ich mich noch nicht beschäftigt. Da meine Zeit begrenzt ist, könnt ihr mir nen Tipp geben ob es nun nen einfachen weg gibt oder nicht?
Sag GENAU was du erreichen willst und man kann dir ev. den richtigen Tipp geben
Ergänzung ()
Nai schrieb:
Hier meint beispielhaft jemand auf einem größeren GPGPU-Blog, dass CL_MEM_USE_HOST_PTR pinned Memory sei (auf welcher Implementierung sagt er leider nicht, auch sonst kommt mir sein Geschreibsel etwas "komisch" vor): ...Hier wird auch gesagt dass es "most likely" pinned sei: ...
Kann man im allgemeinen als Falschaussagen abtun (wie auch in in einigen Kommentarten am stackoverflow Artikel erklärt). In OpenCL ist CL_MEM_ALLOC_HOST_PTR für pinned memory gedacht [prinzipiell ist einer Implementierung nicht verboten, bei CL_MEM_USE_HOST_PTR das memory auch pinned zu machen, und keine ist gezwungen es bei CL_MEM_ALLOC_HOST_PTR zu machen. Der Sinn ist es aber nicht, und eine normale Implementierung auf einer normalen Plattform wird sich an den Sinn halten].
Nai schrieb:
Mein Problem dabei ist, dass Coalescing bereits extrem von den Warps oder Wavefronts abhängig ist, welche in OpenCLs Abstraktion nicht mehr existieren - wenigstens lässt sich bei NVIDIA die Warp-Größe per Extension abfragen; bei AMD jedoch nicht. Dann gibt es noch Intel-GPUs bei welchen die Warp-Größe von Kernel zu Kernel verschieden ist und Mali-GPUs bei welchen weder Warps noch Wavefronts existieren. ... Warp-Vote-Functions, diese kann man zwar auch in OpenCL über den local Memory nachprogrammieren, allerdings benötigt man dafür dann unbedingt die nicht gegebene Warp-Größe. Ist die Warp-Größe bei der Entscheidung falsch dann geht nicht nur die Performance sondern viel schlimmer auch die Korrektheit des Programms verloren.
Diese Eigenschaften (und Tonnen weitere) sind sehr wohl zur run-time abfragbar -> genau weil sie von device zu device abhängig sind und die performance maßgeblich beeinflussen können, aber der device zum Zeitpunkt des Programmierens ja nicht unbedingt bekannt sein muss bzw. eine ganze Menge in Frage kommen können. clGetKernelWorkGroupInfo(CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE) etwa gibt die ideale work-group size (quasi warp-Größe bei Nvidia bzw. wavefront bei AMD) pro device und kernel zurück und per get_global_size / get_local_size etc. kann man im kernel die work-group Größen auslesen.
Ein sauber, generisch geschriebenes OpenCL Programm wird also diese Attribute (wie zig andere -> schau mal durch was die Funktionen clGetxxxInfo alles bereit stellen, sind Tonnen !) zur run-time abfragen und gemäß diesen entsprechend die Datenstrukturen aufsetzen bzw. kernel-aufrufe parameterisieren. Ein Programm und trotzdem device-spezifisch optimiert.
Nai schrieb:
Die Problematik der Bindung ist mir bewusst, vor allem da AMD-GPUs auch ganz gut sind.
Nicht nur AMD-GPUs, die Idee ist ja von allen möglichen devices Gebrauch machen zu können, etwa der integrierten Grafikeinheit in APUs. Und damit dann Otto-normal Programme zu beschleunigen.
Nai schrieb:
Allerdings ist in meinen Augen das Grundkonzept von OpenCL bereits komplett kaputt. Man versucht alles mögliche unter einen Hut zu bringen. Eine API für alle Device-Typen. Eine eierlegende Wollmilchsau. Es mag Fälle geben, wo so etwas praktisch ist. Jedoch in den meisten Use-Cases will man doch nur GPGPU machen oder alternativ spezifisch für ein anderen Device-Typ wie eine CPU oder einen CELL programmieren. Da bringt einem die Portabilität zu anderen Devices nichts.
Kann dem überhaupt nicht zustimmen. Wer nur GPGPU braucht kann sich ja auf die GPGPU-relevanten Aspekte beschränken, ansonsten hat man ein tool um alle mögichen devices zu nutzen, inkl. optional falls vorhanden ohne deren Präsenz vorauszusetzen. Warum sollte eine normale Anwendung nicht von APUs oder GPUs jeden Herstellers profitieren können falls die in einem System sitzen, wie etwa schon gemacht bei Grafikprogrammen oder Kompressionsprogrammen.
Mit OpenCL kann man zwar GPGPU machen, aber OpenCL an sich ist nicht GPGPU. Das sollte nicht verwechselt werden und OpenCL sollte von Haus aus als device-unabhängiges Instrument angesehen und erlernt werden (leider wird es das zu selten), selbst wenn es im Endeffekt nur für GPGPU eingesetzt wird, denn der codestil ist ein anderer (so wie der Code-stil in C++ auch ein anderer ist als in C).
Und die Portabilität bringt sogar nur bei GPGPU schon was wichtiges, nämlich zwischen Nvidia und AMD hardware wechseln zu können.
Nai schrieb:
Wenn man dann gleich noch die beiden größten anderen Design-Schwächen von OpenCL - nämlich die Trennung zwischen Device- und Hostcode und die Verwendung von Buffern statts Pointern beseitigen könnte - wäre ich komplett zu Frieden.
Derzeit ist da einiges im Fluss, API-seitig wie hardware-bedingt.
Selbstverständlich hat OpenCL genug Schwachstellen, es gibt also auch meinerseits nichts in den Himmel zu reden. Die fehlenden Zeiger sind IMHO eine der allergrößten. Bin selbst gespannt wie das in Zukunft weitergehen wird (sowohl bei OpenCL wie auch möglichen Alternativen), denn die zunehmende Verschmelzung von CPU, GPU, Speicher, und anderer Ressourcen hardware-seitig bringt nicht wirklich viel wenn nicht auch die Software- und Programmiertools ähnliche und v.a. für den Programmierer leicht anzunehmende Schritte und flüssige Integrationen bereitstellen.
Ich möchte ein memObject erstellen, der Host soll reinschreiben, der Kernel dann rauslesen und wieder das Ergebnis reinschreiben. Dann soll das Ergebnis vom Host wieder ausgelesen werden.
Am einfachsten - wenn du dir keinerlei Gedanken über die Performance machen willst - dann geht das so wie du es bereits gehabt hast: clenqueuereadbuffer / clenqueuewritebuffer
Ja genau dafür ist CL_MEM_READ_WRITE da -> um im kernel aus dem entsprechenden buffer sowohl Daten zu lesen als auch reinzuschreiben.
Sorry, ich hab dein OP misverstanden gehabt, ich dachte es ging dir darum dass Schreiboperationen vom kernel direkt in C++ sichtbar werden, ohne den buffer jemals rücklesen zu müssen. Du kannst unsere abschweifende Fachdiskussion ruhig vergessen
Übrigens: CL_MEM_READ_ONLY heißt der kernel darf Daten aus dem buffer nur lesen, und CL_MEM_WRITE_ONLY der kernel darf Daten in den buffer nur schreiben. Alle drei beziehen sich rein auf den kernel; wenn du einen buffer mit z.b. CL_MEM_READ_ONLY erstellst so darfst du dort host-seitig sehr wohl Daten reinschreiben, wie etwa über ein clEnqueueWriteBuffer.
The CL_MEM_ALLOC_HOST_PTR and CL_MEM_USE_HOST_PTR buffers are:
– zero copy buffers that resides on the host.
– directly accessible by the host at host memory bandwidth.
– directly accessible by the device across the interconnect.
– a pre-pinned sources or destinations for CL read, write, and copy
commands into device memory at peak interconnect bandwidth.
In OpenCL ist CL_MEM_ALLOC_HOST_PTR für pinned memory gedacht [prinzipiell ist einer Implementierung nicht verboten, bei CL_MEM_USE_HOST_PTR das memory auch pinned zu machen, und keine ist gezwungen es bei CL_MEM_ALLOC_HOST_PTR zu machen. Der Sinn ist es aber nicht, und eine normale Implementierung auf einer normalen Plattform wird sich an den Sinn halten.
Eben weil die Specs nicht einmal Richtlinien und Empfehlungen enthalten, können die Implementierer prinzipiell alles mögliche hineininterpretieren und das nach gutdünken machen. Das Ganze endet dann im Chaos, dass niemand weiß wie genau etwas tendentiell implementiert ist, wie man auch gerade an unserer Diskussion und an anderen Diskussionen/Guides im Internet bemerkt.
Diese Eigenschaften (und Tonnen weitere) sind sehr wohl zur run-time abfragbar -> genau weil sie von device zu device abhängig sind und die performance maßgeblich beeinflussen können, aber der device zum Zeitpunkt des Programmierens ja nicht unbedingt bekannt sein muss bzw. eine ganze Menge in Frage kommen können.
clGetKernelWorkGroupInfo(CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE) etwa gibt die ideale work-group size (quasi warp-Größe bei Nvidia bzw. wavefront bei AMD) pro device und kernel zurück und per get_global_size / get_local_size etc. kann man im kernel die work-group Größen auslesen.
Mir ist das bewusst, dass man solche Informationen auslesen kann und daraus eventuell irgendwelche Sachen *vermuten* oder *hineininterpretieren* kann, allerdings ist es keine Garantie, dass etwas so ist. Ein gutes Beispiel sind atm Mali GPUs. Diese besitzen keine Warps oder Wavefronts. Allerdings wird dennoch folgendes empfohlen:
Use work-group sizes that are a multiple of 4. These are more efficient on the Mali-T600 Series GPUs.
und deshalb eventuell auch bei OpenCL als preferred workgroup Size ausgegeben. Nimmt man nun an, dass es eine Warpgröße von 4 hätte und baut darauf die Korrektheit seines Programms auf führt das zu Problemen. Oder alternativ, was passiert, wenn auf zukünftigen GPUs eine Workgroup aus einem Vielfachen von 2 oder 4 Warps bestehen muss? Dann würde die Vermutung dass dieser Wert der Warpgröße entsprechen würde ebenfalls fatal.
Nicht nur AMD-GPUs, die Idee ist ja von allen möglichen devices Gebrauch machen zu können, etwa der integrierten Grafikeinheit in APUs. Und damit dann Otto-normal Programme zu beschleunigen. Kann dem überhaupt nicht zustimmen. Wer nur GPGPU braucht kann sich ja auf die GPGPU-relevanten Aspekte beschränken, ansonsten hat man ein tool um alle mögichen devices zu nutzen, inkl. optional falls vorhanden ohne deren Präsenz vorauszusetzen.
Ich widerspreche auch nicht, dass es Anwendungsgebiete gibt, in welchen man etwas eben "irgendwie" parallel rechnen möchte, wofür sich OpenCL auch gut eignet. Allerdings beschränken sich viele Anwendungsfälle eben auf reines GPGPU, wo man sich nur Portabilität zwischen verschiedenen GPU-Herstellern wünscht - eben momentan vor allem NVIDIA und AMD. Da ist es dann im vorneherein auch klar, dass nur GPUs als Devices gefordert sind und die Anwendung nie auf einer CPU oder einem FGPA laufen wird, wodurch die Portabilität zu anderen Device-Typen nichts bringt. Allerdings wünscht man sich dann in solchen Fällen eine möglichst spezifische, gut dokumentierte, performante GPGPU-API. Eben das kann OpenCL dann (z.B. im Vergleich zu CUDA) wie bereits von mir erläutert nur noch eingeschränkt erfüllen.
Du baust das Programm so auf das es mit quasi jeder work-group size korrekt funktioniert. Allgemein gesehen ist es eine Variable die erst zur run-time ihren Wert kriegt, etwa so als ob sie ein user input wäre (fall-back Code kann ja irgendwelche strange cases handhaben). Sollte man den device-typ, Plattform etc. kennen kann man ja noch immer selber gewisse Einschränkungen machen oder sogar als Extremfall eine Konstante ansetzen. Im übrigen gilt das auch für reines GPGPU, denn z.b. eine Nvidia Karte mag 32 als ideale warp-size haben, deine Mali 4, eine Tahiti hat 64, und zukünftige Karten haben halt irgendwas.
Es ist ABSICHT dass manche Dinge eher vage spezifiziert sind, weil man eine Balance schaffen muss zwischen Funktionalität / Garantien und Generalität im Sinne der Portabilität und nicht Plattformen wegen zu stringenter Bedingungen gleich mal ausgrenzen will. Geht ja gar nicht anders, irgendein Spagat muss her, und in der Praxis pendelt sich ein gewisses Gleichgewicht ein was man erwarten kann. Dies mag einem für die eigenen Zwecke genügen, oder man greift eben auf Alternativen zurück. Ich meine das übrigens vollkommen wertfrei, denn einer mag konkrete Spezifikationen vorziehen und damit etwa CUDA wählen, für wen anderen ist Portabilität wichtiger, und wer dritter nimmt z.B. OpenCL samt allen AMD-Garantien und beschränkt sich auf AMD Karten.
Ich kann die Idee deiner reinen GPGPU-API an sich nachvollziehen, aber ich sehe nicht wie man das umsetzen soll ohne qualitativ in dieselbe Problematik in klein wie hier gerade diskutiert zu laufen. Denn auch so eine API muss generell denken, nicht nur etwa im Sinne von aktuellen Nvidia und AMD Karten, sondern etwa auch hypothetische Karten und Plattformen in Betracht ziehen, kleine Hersteller mit ins Boot nehmen etc. Dann kommen genau wieder Abstraktionen und Kompromisse zum Tragen, was auf Kosten von klaren Spezifikationen läuft, und dann sind wir wieder beim selben Thema. Nvidia kann sich leisten seine CUDA API und seine Hardware aufeinander zu synchronisieren und eng zu spezifizieren, weil es über beide die volle Kontrolle hat. Aber wenn diese Kontrolle verloren geht muss irgendein Spagat her.
Du baust das Programm so auf das es mit quasi jeder work-group size korrekt funktioniert. Allgemein gesehen ist es eine Variable die erst zur run-time ihren Wert kriegt, etwa so als ob sie ein user input wäre (fall-back Code kann ja irgendwelche strange cases handhaben). Sollte man den device-typ, Plattform etc. kennen kann man ja noch immer selber gewisse Einschränkungen machen oder sogar als Extremfall eine Konstante ansetzen.
Es geht mir hier primär nicht um die optimale Workgroupsize (welche eher sowieso ein Gefriggel ist) sondern um die Warp/Wavefront-Size des Devices, da mandiese für diverse mächtige Optimierungen braucht (z.B. wie bereits erwähnt um Warp-Vote Functions zu implementieren; siehe Link aus meinen vorherigen Post). Da bei NVIDIA-GPUs die Warp-Size abfragbar ist kann man in der Tat eine solche Implementierung machen (wie mein letztes OpenCL Programm auch war). Nur die AMD-GPUs bereiten einem Kopfzerbrechen, da die Warp/Wavefront-Size eben bei ihnen *nicht* abfragbar ist. Man kann sie zwar auch aus den AMD-Docus hardcoden. Dann stößt man allerdings auf das Problem, dass man zukünftige GPUs eben nicht unterstützen kann, da sich die Wave-Front size eben prinzipiell auch ändern kann. . . . .
Dadurch habe ich insgesamt keine möglichkeit Warp/Wavefront Optimierungen allgemein und gut für GPUs in OpenCL zu implementieren.
Im übrigen gilt das auch für reines GPGPU, denn z.b. eine Nvidia Karte mag 32 als ideale warp-size haben, deine Mali 4, eine Tahiti hat 64, und zukünftige Karten haben halt irgendwas.
Dieser Satz lässt mich allerdings etwas zweifeln, in wie weit du dich mit der GPU-Programmierung gut auskennst oder verstanden hast, was ich geschrieben habe: Bei NVIDIA und AMD GPUs ist die Warp-Size/Wave-Front-Size eine Hardwarekonstante des SIMT-Modells. Damit hat sie keinen "idealen" sondern einen festen Wert, welcher auf allen modernen NVIDIA GPUs 32 und bei AMD GPUs 64 ist. Mali GPUs haben jedoch keine Warps/Wavefronts, wodurch dieser Wert und Optimierungen bezüglich Warps/Wavefronts auch keinen Sinn ergeben. Aus dem Mali-Guide:
Warps or wavefronts
Mali GPUs do not use warps or wavefronts. Remove any optimizations for these.
OpenCL liefert jedoch wieder keine Möglichkeit dies herauszufinden durch Device-Queries, ob die GPU Warps/Wavefronts besitzt.
Es ist ABSICHT dass manche Dinge eher vage spezifiziert sind, weil man eine Balance schaffen muss zwischen Funktionalität / Garantien und Generalität im Sinne der Portabilität und nicht Plattformen wegen zu stringenter Bedingungen gleich mal ausgrenzen will.
Ich kritisierte nicht, dass die garantierten Grundlagen von OpenCL zu abstrakt sind. Sondern eben, dass die Sepcs "bei Bedarf" eben nicht spezifisch genug werden, wie dass es z.B. neben einer generischen GPU eine Warp/Wave-Front GPU als Device-Typ oder "Warps vorhanden" als Device-Eigenschaft gibt. Auch wie bereits geschrieben fehlen imo Richtlinien und Empfehlungen für die Programmierer und Implementierer wie z.B: "Dies sollte DMA/Zero Copy etc sein falls es für die Art des Devices sinnvoll ist und falls das Device es unterstützt.". Denn dies hilft beim Anwenden der API ungemein.
Ich kann die Idee deiner reinen GPGPU-API an sich nachvollziehen, aber ich sehe nicht wie man das umsetzen soll ohne qualitativ in dieselbe Problematik in klein wie hier gerade diskutiert zu laufen. Denn auch so eine API muss generell denken, nicht nur etwa im Sinne von aktuellen Nvidia und AMD Karten, sondern etwa auch hypothetische Karten und Plattformen in Betracht ziehen, kleine Hersteller mit ins Boot nehmen etc.
Die Problematik sehe ich kaum. Denn das Ziel einer solchen API sollte es sein nur die wichtigsten GPGPU-Anwendungsfälle abzudecken, diese dafür aber möglichst gut. Ihr Ziel sollte es nicht sein zu versuchen alle Anwendungsfälle abzudecken, da dadurch die Qualität der Abdeckung vor allem der wichtigsten Anwendungsfälle dann leidet.
Man müsste zum Beispiel nur aktuelle diskrete NVIDIA und AMD GPUs unterstützen; schon hätte man wohl 75 Prozent aller Anwendungsfälle abgedeckt. Nimmt man noch integriete Intel,AMD und NVIDIA-GPUs hinzu würde man wohl auf 95 Prozent kommen. Da diese GPUs prinzipiell alle viele grundlegende Ähnlichkeiten besitzen (bei Intel bin ich mir etwas unsicher, da ihre Docu teils spärlich ist), wäre es wahrscheinlich machbar die API gut auf diese GPUs zurechtzuschneiden.
Das Ganze führt nun in der Tat dazu, dass man prinzipiell exotischere GPUs, welche nicht in das Schema passen (z.B. die Mali GPU) ausschließt. Hier müssten sich dann die exotischen Hersteller "zum Wohle der Merhheit" nach der API und dem Mainstream richten und nicht die API nach der exotischen Herstellern. Entweder sie passen ihre Hardware an die API an oder sie finden sich damit ab, dass man ihre GPUs eben nur unter OpenCL und nicht mit der neuen hypothetischen GPGPU-API ansteuern kann.
Offen gesagt finde ich die Diskussion hier nicht mehr zielführend. Wir kommen auf keinen grünen Zweig, und schnippische Bemerkungen sind bei mir rote Linien welche weitere Kommentare erübrigen.
Technisch gesehen aber sei für den neutralen Leser wiederholt: OpenCL bietet einen Haufen Möglichkeiten um, im abstrahierten OpenCL Konzept, properties von devices, platforms etc. abzufragen. Die kann jeder in der offenen OpenCL Spezifikation nachlesen und sich selbst ein Bild machen was zur Verfügung steht, ist eine Menge (Abstraktionslevel dahinter auch verinnerlichen). Aussagen, das generelle Fehlen dieser Abfragemöglichkeiten sprechen gegen OpenCL, haben also keine fundierte Grundlagen.