OpenCL, het nieuwe werken voor parallel programmeren

Reading time: 8 minutes

Author:

George van Venrooij is mede-eigenaar van Organic Vectory in Eindhoven, dat zich specialiseert in GPGPU-consultancy en -engineering van (embedded) applicaties. Hij heeft vijftien jaar ervaring in technische-softwareontwikkeling in diverse gebieden, waaronder simulatie- en visualisatiesystemen.

Het verdelen van software over verschillende soorten rekenhardware – CPU‘s, GPU‘s, DSP‘s – is niet eenvoudig, zeker als een programma op verschillende systemen moet draaien. Met de recent ontwikkelde OpenCL-standaard hoeft de programmeur zich niet met de hardwaredetails te bemoeien en is geschreven software op een brede reeks hedendaagse en toekomstige hardware uit te rollen. Met name in embedded systemen kan dit de standaard aanpak worden, betoogt George van Venrooij van Organic Vectory.

GPU‘s hebben de afgelopen jaren een stormachtige ontwikkeling doorgemaakt. Waar ze oorspronkelijk alleen bedoeld waren voor grafische toepassingen, zijn ze nu ook geschikt om algemeen toepasbare code te draaien. De general-purpose GPU‘s (GPGPU‘s) hebben zich ontpopt als efficiënt platform voor dataparallelle toepassingen, met verbluffende prestatiewinsten tot gevolg. De prijs die hiervoor moet worden betaald, is echter dat platform- of fabrikantspecifieke methodes gebruikt moeten worden om ze ten volle te benutten.

Om langetermijninvesteringen in softwareontwikkeling voor deze nieuwe platforms mogelijk te maken, was er een standaard nodig die de parallelle rekenkracht op een uniforme manier aanspreekbaar maakt. Die standaard werd door de Khronos-groep gelanceerd in november 2008. De naam: OpenCL.

OpenCL (Open Compute Language) stelt software-engineers in staat om alle rekeneenheden in een systeem te benutten. De standaard fungeert als abstractie- en managementlaag tussen de applicatie en de verschillende processoren. De grote belofte is dat OpenCL-applicaties qua prestaties dynamisch meeschalen met nieuwe hardware die meer rekenkernen bevat. Zowel op taak- als op dataniveau kan er worden geparallelliseerd.

Hardwareonafhankelijk

Om te begrijpen hoe dit werkt, is het nodig om te kijken naar het model dat OpenCL hanteert om zijn wereld te beschrijven. OpenCL-applicaties bestaan uit een host- en een devicegedeelte: de hostcode fungeert als beheerder, het devicegedeelte voert het zware werk uit.

De hostcode heeft de beschikking over een Api om informatie op te vragen over de verschillende compute devices in het systeem. Hiervoor is een ruime keus aan programmeeromgevingen. Oorspronkelijk is de Api geschreven voor C/C++, maar ondertussen zijn er al legio bibliotheken voor alle grote programmeertalen, waaronder C#, Delphi, Erlang, Java, Python en Ruby.

In OpenCL beheert een hostprogramma de rekenkernels die op de hardware draaien. Deze hardware bestaat in eerste instantie uit devices, zoals een CPU, GPU of dedicated accelerator in IBM‘s Cell-architectuur. Een device is op zijn beurt weer opgebouwd uit compute units. Denk hierbij aan de verschillende cores van een CPU of de multiprocessoren in een GPU. Weer een niveau dieper in de hiërarchie vinden we de processing elements. Een gewone CPU-core zal er hier een van hebben, een core met hyperthreading twee. GPU-multiprocessoren hebben doorgaans veel meer processing elements.

Dat ligt wat anders bij de devicecode. Om de hardware aan het werk te zetten, zijn er kernels nodig, kleine stukjes software die een specifieke berekening uitvoeren. Deze worden geschreven in OpenCL C, een subset van Iso C99 met parallellisatie-extensies.

Een driver van de hardwarefabrikant compileert de kernels geschreven in OpenCL C. Dit kan op twee manieren. Indien het platform van tevoren vastligt, kan de gecompileerde kernel als binary met de applicatie worden gebundeld. De meest flexibele optie is echter om de kernel in broncodevorm in de applicatie op te nemen en tijdens runtime te compileren. Daardoor pakt de toepassing altijd de best beschikbare hardware voor een taak.

Door deze aanpak is de code hardwareonafhankelijk te maken. OpenCL is bovendien terugwaarts compatibel. Kernels geschreven voor de huidige generatie devices draaien daardoor gegarandeerd ook op toekomstige OpenCL-conforme hardware.

Kopieën

De host gebruikt een OpenCL-runtimeomgeving om de verschillende commando‘s naar de hardware te sturen: de kernels, en opdrachten voor bijvoorbeeld geheugenbeheer en synchronisatie. De runtime kan de commando‘s vervolgens op twee manieren uitvoeren: in-order of out-of-order. Het eerste betekent simpelweg dat de commando‘s worden uitgevoerd in de volgorde waarin ze binnenkomen. Een commandowachtrij is dus een beetje als een enkele thread te beschouwen. Parallellisatie is dan mogelijk door met meerdere wachtrijen te werken.

Voor een veel betere schaalbaarheid moet echter de out-of-order-optie worden gekozen. De OpenCL-runtime is hiermee vrij om te bepalen in welke volgorde de commando‘s worden uitgevoerd, zodat de hardware efficiënter kan worden ingezet. De programmeur kan wel afhankelijkheden tussen taken definiëren. Hij kan bijvoorbeeld drie taken in de wachtrij zetten en aangeven dat taak B pas mag starten als taak A klaar is. De runtime zal dan taak A en B sequentieel draaien, maar kan taak C wel parallel hieraan uitvoeren als er hardwarebronnen vrij zijn. Software die ontworpen is voor dit model heeft de potentie om lineair te schalen met het aantal cores in een systeem.

Dataparallellisme wordt bereikt door meerdere kopieën van een kernel te lanceren, waarbij elk duplicaat een deel van de dataset voor zijn rekening neemt. GPU-achtige hardware zal hier het meest efficiënt mee om kunnen gaan, maar het mooie is natuurlijk dat de CPU het werk kan doen als er geen GPU aanwezig is.

Superformule

Bij het ontwikkelen van de OpenCL-specificatie heeft de Khronos-groep zijn pijlen nadrukkelijk ook gericht op de mobiele/embedded markt, waar het al eerder met OpenGL ES een succesvolle standaard wist neer te zetten. Naast het full profile is er het embedded profile van OpenCL. De specificaties voor de vereiste hardware zijn hier omlaag geschroefd om beter overeen te komen met hardware in embedded systemen. Daarnaast is de runtimecompiler niet verplicht. Andere belangrijk verschillen zijn dat 64 bit integers en integervectoren niet verplicht zijn en dat de image en floating point support-vereisten in lijn zijn gebracht met de texture-requirements van OpenGL ES 2.0. Het is zeer goed mogelijk dat OpenCL in dat marktsegment harder zal groeien dan in andere sectoren vanwege de voordelen die het ontwikkelaars biedt en het gebrek aan goede alternatieven.

Het is echter ook belangrijk om te kijken wat de industrie ondersteunt. Hoe meer supporters, hoe groter de kans dat het ook een echte standaard wordt. Als we kijken naar hardware, zien we dat veel partijen al aan boord zijn en drivers hebben gemaakt voor hun producten: AMD, Apple, IBM, Imagination Technologies, Intel, NVidia, S3, Samsung en Ziilabs. Het gerucht gaat dat Arm binnenkort zal toetreden tot dit gezelschap. Hiermee omvat de beschikbare hardware CPU‘s, GPU‘s, Cell-SPU‘s en mediaprocessoren, variërend van oplossingen voor rekencentra tot embedded en mobiele hardware. Alle grote besturingssystemen worden eveneens ondersteund: Linux, Mac OS X, Windows en de mobiele platforms Android en IOS. Ook zijn er steeds meer ontwikkelaars van (opensource) bibliotheken en applicaties die OpenCL gebruiken of van plan zijn dat te doen.

De OpenCL-runtimeomgeving kan de volgorde van taken zoals geheugenbeheer en rekenkernels aanpassen om de hardware zo efficiënt mogelijk te benutten. De programmeur moet hiervoor wel de afhankelijkheden aangeven.

Het zal geen verrassing zijn dat de early adopters te vinden zijn in de segmenten waar veel gerekend moet worden: simulatie, video- en beeldverwerking en visualisatie. Vooral voor dat laatste gebied is OpenCL aantrekkelijk. Datastructuren van graphics-Api‘s zoals DirectX of OpenGL zijn direct af te beelden op OpenCL-geheugen. Resultaten van berekeningen kunnen zo snel worden gevisualiseerd op een GPU zonder tussenkomst van de CPU.

Voor de ontwikkeling van ons 3D-simulatie- en -visualisatiepakket Crius hebben we ook voor deze OpenCL/OpenGL-combinatie gekozen: OpenCL voor de simulatie en generatie van 3D-content, OpenGL voor de rendering. We maken hier ook dankbaar gebruik van Supershaper, een programmaatje dat complexe vormen genereert uit wiskundige formules. De applicatie evalueert deze zogenaamde ’superformule‘ in OpenCL, waarna het resultaat wordt doorgeven aan OpenGL om te renderen. Door deze aanpak zijn we vrij in de keuze van hardware en platforms.

Supercomputers

Al vanaf de eerste aankondiging van OpenCL wordt de vergelijking gemaakt met NVidia‘s Cuda-Api. De verschillen zijn echter legio: Cuda wordt gecontroleerd door NVidia, werkt enkel op GPU‘s van deze fabrikant en biedt geen oplossingen voor CPU‘s of andere hardware. Het dient echter gezegd te worden dat het erg goed is in wat het wel doet: de GPU toegankelijk maken voor niet-grafische toepassingen. NVidia mikt hierbij op het high-performance computing-segment (HPC) van grote rekenclusters en supercomputers en is daarin erg succesvol. Dit komt ook doordat het bedrijf zwaar investeert in de marketing en ontwikkeling van tools, bibliotheken en cursussen voor zijn platform.

In het verleden waren vendor-specifieke Api‘s vaak geen lang leven beschoren in markten met veel concurrentie. Toch is het niet waarschijnlijk dat Cuda op korte termijn door OpenCL zal worden overvleugeld in het HPC-segment. Op de wat langere termijn en in andere markten, liggen de zaken natuurlijk anders en NVidia is wel zo slim geweest om OpenCL-drivers voor zijn hardware te ontwikkelen.

De keuze om OpenCL toe te passen in het ontwikkeltraject zal grotendeels afhangen van een gedegen kosten-batenanalyse, die de beschikbaarheid van tooling en robuuste bibliotheken en de verwachte ontwikkelingen op de langere termijn meeneemt. Vanwege zijn jonge leeftijd is het OpenCL-ecosysteem nog relatief klein, maar nu steeds meer partijen de standaard onderschrijven en actief projecten steunen, ligt een explosieve groei in de lijn der verwachting.

Qua tooling zijn er al compilers, debuggers en IDE‘s verschenen. AMD volgt NVidia‘s Cuda-aanpak en begint nu actief bibliotheken te ontwikkelen met daarin de bouwstenen voor applicatieontwikkelaars. De opzet van OpenCL biedt ook genoeg aanknopingspunten voor een geleidelijke transitie naar schaalbare applicaties. De standaard heeft dan ook de potentie om dé oplossing te worden voor het schrijven van schaalbare heterogene parallelle applicaties.