Warning: Undefined array key "bio" in /home/techwatch/domains/test.bits-chips.nl/public_html/wp-content/plugins/wpcodebox2/src/Runner/QueryRunner.php(126) : eval()'d code on line 13
Author:
Reading time: 7 minutes
Betekende multicore een paar jaar geleden nog dat de programmeur min of meer op de oude voet verder kon met twee of vier dezelfde cores, tegenwoordig moet hij ook rekening houden met DSP‘s, GPU‘s en zelfs FPGA‘s. Voorstellen zat hoe hij daarmee om moet gaan, maar dé oplossing is er nog niet bij.
OpenCL, OpenACC, OpenMP, OpenMPI, OpenHMPP, C++ AMP, PThreads, Renderscript, Threading Building Blocks, Array Building Blocks, ISPC, Go, Cilk (Plus), Cuda, Directcompute, Erlang, HSAIL, WebCL … Ziet u door de bomen het bos nog? Dit lijstje is een greep uit de vele aanpakken die een oplossing moeten leveren voor het programmeren van multicore processoren. Er zijn er nog veel meer.
Het illustreert mooi de worsteling die de industrie heeft met multicore. Of liever gezegd: met het efficiënt parallelliseren van code, iets wat in één adem wordt genoemd met multicore, maar feitelijk breder is. Dat vraagstuk is wellicht al zo oud als de informatica zelf en zeker ’aan de randen‘ van het vakgebied zoals in embedded systemen en supercomputers welbekend. Vanaf halverwege het vorige decennium is het echter een mainstream onderwerp geworden waar steeds meer programmeurs mee te maken krijgen. En de situatie wordt er alleen maar ingewikkelder op.

Destijds begonnen processormakers serieuze problemen te ondervinden om op de traditionele manier de wet van Moore uit te buiten voor het maken van steeds snellere CPU‘s. Zoals David Patterson van de universiteit van Californië in Berkeley het beschreef, liepen ze tegen maar liefst drie grenzen op. Traditioneel was kloksnelheid de belangrijkste – in ieder geval vanuit marketingoogpunt – methode om processoren sneller te maken. Kleinere structuren betekent dat elektronen kortere afstanden afleggen en de bewerkingen elkaar sneller kunnen opvolgen. Met de oplopende schakelfrequentie van een transistor nemen echter het stroomverbruik en de geproduceerde warmte toe. Dat was nooit echt een issue, want de voedingsspanning kon steeds een beetje worden teruggeschroefd en daarmee werd het probleem netjes gecompenseerd. Maar dit bereikte zijn fysieke limieten. Hoewel IBM de processoren in zijn allernieuwste mainframes tot 5,5 GHz heeft weten op te voeren, draaien de meeste CPU‘s vandaag de dag niet sneller – zeker niet op de twintig gigahertz die tien jaar geleden werd beoogd.
De tweede hindernis was dat processormakers niet heel veel méér konden met al die extra transistoren die dankzij kleinere procestechnieken beschikbaar kwamen. Tot dan toe werden ze ingezet voor steeds complexere logica om de instructiestroom efficiënter te verwerken, vooral door te kijken hoe instructies parallel verwerkt kunnen worden en door te speculeren wat de volgende stap zou zijn. Het maximale optimalisatieniveau was echter wel zo‘n beetje bereikt: het toevoegen van veel complexere circuits leverde steeds minder extra performance op. De laatste hindernis was dat de snelheid van het externe geheugen niet meegroeit met die van de processor. De processor moet bij geheugenoperaties dus steeds meer kloktikken staan niksen tot de relevante data binnengehengeld is.
Multicore biedt een manier om nog wel van Moore te profiteren. Door meerdere processoren – in welke vorm dan ook – tegelijk te laten rekenen op een ’matige‘ kloksnelheid worden toch alle transistoren nuttig gebruikt, blijft het stroomverbruik binnen de perken en wordt het snelheidsverschil met het geheugen niet groter. Dat betekende echter een aardverschuiving voor de software. De dominante basisgedachte is al decennia dat de processor stapje voor stapje verteld krijgt wat hij moet doen, en bij snellere processoren worden de stapjes sneller achter elkaar gezet. Maar nu moeten er ineens meerdere stapjes tegelijk gezet gaan worden, een compleet ander paradigma.
Allerminst irrelevant
Een paar jaar geleden ging het bij multicore vooral nog over twee of misschien vier dezelfde processorkernen naast elkaar geplaatst, met een overkoepelende pool cachegeheugen. Dat bleek voor de markt al lastig. Exotischere modellen bleven vooral academische spielerei, pogingen tot marktintroductie, zoals bij de Cell-processor van IBM, Sony en Toshiba, moesten hun eigenwijze programmeeraanpak bezuren met geweeklaag van ontwikkelaars en tegenvallende resultaten. Alleen de domeinen die traditioneel aan multicore gewend waren, gingen gewoon hun gang.
Terugkijkend, was het leven toen nog simpel. Met name toepassingen die allerlei min of meer onafhankelijke taken moeten uitvoeren, zijn heel aardig uit te smeren over een symmetrische multicore processor. Meestal kan het besturingssysteem dit voor zijn rekening nemen. Voor zware applicaties, die normaliter op een enkele processorkern draaien, kan de programmeur de verschillende deelprogramma‘s onderbrengen in meerdere threads.

Embedded toepassingen hebben die luxe meestal niet. Daar moeten de meerdere cores zich gezamenlijk door dezelfde hoeveelheid data heen eten. Bovendien schieten de coreaantallen omhoog, beginnen geheugenarchitecturen te veranderen en worden DSP‘s, GPU‘s en zelfs FPGA‘s steeds vaker meegenomen in het plaatje. Met name grafische processoren staan op dit moment volop in de belangstelling. Honderden identieke eenvoudige cores kunnen daar gezamenlijk een grote dataset aanvallen, mits op elk datapunt dezelfde databewerking moet worden uitgevoerd. Dit is een nieuwe aanpak van single instruction, mulitple data (SimD), dat eerder in DSP-versnellers of media-extensies zoals Intels SSE en Arms Neon naar voren kwam. Deze zijn allerminst irrelevant geworden. Intel, dat tot nog toe geen vuist wist te maken tegen het oprukken van GPU-rekenen, zoekt zijn antwoord juist in veel krachtigere SimD-instructies in een standaard CPU-core – waarvan er dan weer tientallen op een chip geplaatst zijn om de zaak nog een beetje te compliceren.
Jonge hippe internetbedijfjes
De hamvraag is hoe dit allemaal te programmeren. Het zijn voornamelijk de chipmakers die mogelijke oplossingen naar voren schuiven, sommigen van hen zelfs meer dan een, sommigen zelfs véél meer. In combinatie met de verschillende uitgangspunten en situaties levert dat een wirwar van aanpakken op. In het ideale geval heeft de programmeur natuurlijk slechts te maken met één raamwerk voor alle soorten hardware en doelgebieden – van embedded tot supercomputers en van SimD-extensies tot GPU‘s en FPGA‘s. De tooling zorgt dan voor de optimale mapping zonder overhead toe te voegen, voor zowel programmeur als systeem. En dat systeem zou onderdeel zijn van een goed ondersteund en open ecosysteem. Vooralsnog lijkt het aloude adagio echter op te gaan: pick any two.
Ook de aanpakken vertonen grote verschillen. Sommige proberen parallellisatie te retrofitten op good old C, C++, Fortran of Java. Dat kan via bibliotheken met bouwblokken of complete geparallelliseerde functionaliteit. Het kan ook gaan om aanwijzingen over wat er wel en niet veilig kan worden geparallelliseerd; voor compilers is dat erg lastig om te bepalen, maar met dergelijke aanwijzingen is het toch te doen. Ideaal voor bestaande code, zeggen de voorstanders: hier en daar versier je je software met een pragma en voilà: de boel draait efficiënt op je multicore processor. De praktijk is doorgaans weerbarstiger, maar het is natuurlijk altijd beter dan de software opnieuw implementeren.
Natuurlijk zijn er ook toolketens om bestaande code om te zetten naar parallelle code. En er gaan stemmen op om de oude talen nu echt een keertje te vervangen door iets wat meer toegesneden is op de hedendaagse situatie – zoals multicore. Ook academici hebben eindelijk weer een goede reden om hun geliefde functionele programmeermethodes naar voren te schuiven. Het mag geen verbazing wekken dat vooral de gevestigde bedrijven er niet heel happig op zijn om een jonge onbewezen methode te omarmen, maar jonge hippe internetbedrijfjes zijn er dol op.
Om begrijpelijke redenen spitsen de meeste aanpakken zich toe op een specifieke manier van multicore, zoals symmetrische multiprocessoren, SimD-extensies, DSP‘s of GPU‘s. Vaak kan de programmeur zijn software optimaliseren voor een specifieke hardwareconfiguratie en bijvoorbeeld aangeven over hoe veel compute units de taak moet worden verdeeld, of juist de tooling de beste verdeling laten uitvogelen – in dat laatste geval is de optimalisatie wellicht minder goed, maar is de software weer makkelijker over te zetten naar andere systemen.
Langzaam komen er echter ook geluiden op om één gezamenlijke aanpak voor alle situaties te ontwikkelen. OpenCL lijkt hierin de beste kaarten te hebben: het is een open standaard voor zowel homogene als heterogene multicore, wordt ondersteund vanuit een brede reeks traditionele talen en de belangrijkste halfgeleiderspelers hebben er al hun steun aan gegeven. Die ondersteuning is echter niet per se exclusief en voor bijvoorbeeld Intel en NVidia lijkt het meer een verplicht nummertje terwijl ze verder zoeken naar iets beters. Met OpenCL is het de programmeur die parallelliseert, met aardig wat overhead voor hemzelf. Hiermee vergeleken is een pragma-gebaseerde aanpak zoals OpenMP (Intel) of OpenACC (NVidia) een ware verademing.’
Het zou goed zijn als de industrie om de tafel zou gaan zitten en zich daadwerkelijk achter één aanpak schaart. Tot die tijd, of totdat de markt een groep ’winnaars‘ kiest, is het onderwerp een grote puzzel voor de programmeur, zoals u kunt lezen op de volgende pagina‘s. Maar als u goed kijkt, zal ook blijken dat multicore mogelijkheden biedt voor de software-engineer: eindelijk is hij verlost van vertragingen door context switching en circuits kunnen zonder extra kosten zuinig en robuust worden gemaakt. De generatie programmeurs die nu opgroeit en straks niet anders gewend is, zal zich wellicht afvragen hoe we ooit zonder hebben gekund.