Het programmeren van grote heterogene manycoresystemen is vaak een hoofdpijndossier. Maar met de juiste gereedschappen hoeft dat niet zo te zijn. Inès Nijman van Recore Systems legt aan de hand van een huishouden uit hoe haar bedrijf dit voor zich ziet.
Eindelijk, na jaren sparen, was het zover. Mijn oma had haar eerste, gloednieuwe wasmachine. Ze had het apparaat nog maar een paar maanden toen tante Margreet haar hoorde gillen. Margreet rende naar haar toe, en zag oma ontzet naar haar schone was wijzen. Nou ja, schoon? De hele was zat vol kleine grijze plukjes, pluisjes en haartjes, en boven op de berg lag een roze, kale muis. De kat stond met zwiepende staart klaar om er op te springen om haar – kennelijk ontsnapte – prooi terug te vorderen. ‘Ik wil mijn wastobbe terug!’, riep oma. ‘Die moderne fratsen zijn maar niks!’
Het huishouden is drastisch veranderd in de afgelopen eeuw. Het handwerk dat de huisvrouw taak voor taak uitvoerde, is grotendeels overgeheveld naar machines die aan het werk zijn terwijl we iets anders doen. Toch kan het in principe nog veel efficiënter, maar daar zijn ingrijpende veranderingen voor nodig.
Dat is een mooie metafoor voor de elektronica ín die apparaten, die evolueert van singlecore naar multicore en op den duur naar heterogene manycore. Bij Recore Systems hebben we een programmeermodel ontwikkeld voor dergelijke grote heterogene manycoresystemen, dat zich goed laat uitleggen aan de hand van de huishoudmetafoor.

Kleur en soort
Vóór de komst van machines in het huishouden was alles handwerk. Een huisvrouw als mijn oma voerde haar taken een voor een uit, net zolang tot ze klaar was. De snelheid waarmee het gebeurde, was de snelheid waarmee oma het deed. In Figuur 1 een overzicht van hoe ze het deed: bijtijds beginnen, zodat om 12 uur het middageten op tafel stond. Kwam er iets belangrijks tussen – een kind dat krijsend de keuken binnenrende met een gat in z’n hoofd nadat het van de schommel was gevallen bijvoorbeeld – dan was het eten later klaar.
In embedded systemen gaat het traditioneel ook zo: er is één processor, en die werkt sequentieel de taken af. Alleen met een snellere processor is het werk sneller klaar. En komt er een high-level interrupt binnen, dan pauzeert de uitvoering van de taken totdat het probleem is opgelost.
Tegenwoordig gaat het er iets anders aan toe in een gemiddeld huishouden. Laten we een voorbeeld nemen van zomaar een huishouden – het mijne. We hebben geen hulp in de huishouding, dus de taken wassen, was drogen, afwassen en koken worden verdeeld over mijn man en mij – een dualcore systeem dus. Gelukkig hebben we wel wat apparaten die ons kunnen helpen zodat we koffie kunnen drinken (idle time) terwijl het halve huis gevuld is met het geraas van machines (processing).

Het zal echter lastig worden om ons huishouden nog sneller af te handelen. Misschien kunnen we nog wel optimaliseren hier en daar, maar wasmachines, drogers, vaatwassers én wijzelf worden niet meer veel sneller. Wij houden bovendien van efficiëntie en halve trommels was zijn een doorn in het oog. Manlief stopt de maximale hoeveelheid was in de trommel, en met resultaat. ‘Ik háát roze sokken!’, stampvoet zoonlief dan door het huis.
Dit moet anders kunnen. Waarom schalen we het niet op naar een huishouden met het hele huizenblok of de hele wijk – een manycore-huishouden zogezegd? De buren worstelen immers met dezelfde problemen. We zullen hiervoor wel buiten de gevestigde kaders moeten gaan denken, maar het heeft voordelen: we kunnen iedere wasmachine en droger per kleur en soort was vullen, vaatwassers zetten we efficiënt in voor het soort vaat – de vuile pannen moeten heter en langer dan de bordjes, dus is het efficiënter om ze te verzamelen in aparte vaatwassers (en misschien kunnen we voor de borden wel een goedkopere machine kopen dan voor de pannen). Het wordt simpeler als één persoon de groenten, een ander de aardappels en een derde het vlees klaarmaakt.

De keerzijde is wel dat we heen en weer moeten rennen met vaat en hete pannen, en sokken sorteren wordt wat meer werk. Dat maakt het idee complex en onaantrekkelijk – nog even afgezien van de forse mentale barrière waar we over moeten voordat we ons vuile wasgoed aan de buren geven.
Hetzelfde zien we bij heterogene manycoresystemen. In principe kunnen ze meer efficiëntie en performance opleveren dan een single- of dualcore, maar vanwege de vermeende complexiteit is het ook een behoorlijk hoofdpijndossier en begint iedereen er niet zomaar even aan.
De uitdaging is dus om het te laten lijken alsof we nog steeds onze eigen huishouden regelen en plannen op de manier die we gewend zijn. Het rondrennen met sokken en glazen moet ongemerkt door kaboutertjes worden afgehandeld. Of in de manycore-analogie: we willen gewoon kunnen blijven programmeren in C zoals we gewend zijn, terwijl ergens achter de schermen een blackboxsysteem regelt dat de geprogrammeerde taken parallel kunnen worden uitgevoerd.
Tweede keus
Het blijkt dat dat goed kan, zolang we maar het een en ander vastleggen over de taken die moeten worden uitgevoerd. We weten welke taken tegelijkertijd klaar moeten zijn: in onze huishoudanalogie moet de tafel gedekt zijn en moeten de groenten, aardappels en het vlees gaar zijn voordat we kunnen eten. We weten ook van een aantal taken dat ze in een specifieke volgorde moeten gebeuren: eerst moet de vaat schoon, daarna kan deze pas worden gebruikt. Dit zijn sequentiële taken, en hoewel de tijd waarop we de vaatwasser aanzetten wellicht niet uitmaakt, heeft het beschikbaar zijn van de schone vaat wel een deadline. Dergelijke deadlines en afhankelijkheden voor taken kunnen ook in de Flexaware-softwareontwikkelomgeving worden aangegeven.

Verder weten we welke hardware het beste past bij welke taak, en we hebben eventueel ook wat back-up-opties. Om maar iets te noemen: wist je dat je ook eten kunt koken in de vaatwasser? (Google maar eens op ‘dishwasher cooking’.) Het is wat ongebruikelijk en de bereidingstijd zal erdoor veranderen, maar het resultaat is in beide gevallen een eetbare maaltijd.
Op een vergelijkbare manier kunnen we in onze omgeving een voorkeur afdwingen met core binding, óf we kunnen het systeem laten bepalen welk soort processor in de bijbehorende Flexaware-hardware de eerste, tweede en derde keus is voor de uitvoering van een taak. Voor een fft is onze eerste keus waarschijnlijk een specifiek type hardwareversneller. Als die allemaal al bezet zijn met taken die écht niet op een ander type processor kunnen, is onze tweede keus een digitale signaalprocessor. En als er echt niets anders op zit, is onze derde keus een generieke processor.

We weten ook welke uitwisseling van goederen er nodig is tussen de taken. Tussen de vaatwasser en de tafel is een uitwisseling van schone borden, glazen en bestek. Het kan ons niet zo veel schelen welke vaatwasser de borden en welke de pannen wast, zolang het maar op het borden- dan wel pannenprogramma gebeurt. Maar we willen wel onze eigen borden op tafel terugzien, in de juiste hoeveelheid. Op een soortgelijke manier kunnen we in de softwareontwikkelomgeving aangeven welke data-uitwisseling er tussen taken moet plaatsvinden, en hoeveel data er moeten worden uitgewisseld.
Hoe meer kennis we hebben, hoe meer kennis we kunnen meegeven en hoe meer grip we hebben op de situatie. Het model is er echter op gericht om te beginnen met normale C-code. De programmeur kan stapsgewijs extra informatie inbrengen over parallellisme en steeds betere prestaties halen.
Dat gaat als volgt: als programmeur voeg je in je programma taken toe via een bibliotheek met standaard en eigen taken. Daarna komt de Flexaware-tooling in actie. De graph extractor zet de C-code om in een task graph die expliciet de taken en communicatiekanalen laat zien. Deze is handmatig aan te passen.
Wanneer de code wordt uitgevoerd op de hardware, komt een runtime in actie die min of meer optreedt als coördinator van ons huizenblok. Deze zorgt er voortdurend voor dat alles precies op de juiste plek terechtkomt op precies de juiste tijd. De softwareontwikkelomgeving kent in samenspraak met deze runtime het geheugen toe en plant alle taken in.

Daarna kan er een optimalisatieslag worden uitgevoerd. De Flexaware-ontwikkelomgeving laat zien waar de bottlenecks zitten en suggereert hoe die zijn op te lossen. Zo komen we stap voor stap tot de optimale opbouw voor onze applicatie op het heterogene manycoresysteem.
Moderne fratsen
Mijn oma heeft na het debacle met de muis nog jarenlang haar was uitgeschud vóór ze hem in de trommel stopte – maar de wasmachine is nooit meer verdwenen. Na verloop van tijd deden ook de wasdroger en vaatwasser hun intrede, en oma was blij dat ze meer kon doen in dezelfde tijd. Ze wilde helemaal niet meer zonder die ‘moderne fratsen’.
Zo zal het ook gaan met manycoresystemen. Nu lijken het af en toe nog moderne fratsen, maar wij zijn ervan overtuigd dat we over tien jaar niets anders meer doen dan manycoresystemen in een handomdraai programmeren. Een kind kan de was doen!