Les 9: Gepijplijnde micro-architecturen The maximum speedup that can be expected from parallel algorithms is limited by the proportion of parts that must be computed sequentially - Amdahl's Law
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Samenvatting controlesignalen Mar=0 MemR=1 IRW=1 S1=0 S2=1 Alu=plus PCSrc=1 Cond=0, PCW=1 IF S1=0 S2=2 Alu=add ID S1=2 S2=0 Alu=add S1=2 S2=2 Alu=add S1=2 S2=2 Alu=add PCSrc=0 PCW=1 Cond=0 S1=1 S2=0 Alu=cmpge PCSrc=0 PCW=1 Cond=1 EX Mar=1 MemW=1 Mar=1 MemR=1 MEM Dit is een overzicht van alle controlesignalen gegroepeerd per instructie en per cyclus. In vergelijking met de situatie bij de meer-cycli-per- instructiemachine hebben we hier nu de verwante toestanden per cyclus gegroepeerd. De eerste cyclus is gemeenschappelijk voor alle instructies, en haalt de instructie op (IF=instruction fetch) en verhoogt de programmateller. De tweede cyclus decodeert de instructie (ID = instruction decode), haalt de registerwaarden op en berekent speculatief het sprongadres De derde cyclus voert de eigenlijke semantiek van de instructie uit (EX = execute). Meestal is de ALU hierbij betrokken. De vierde cyclus wordt voorbehouden aan de interactie met het datageheugen (MEM = memory) De vijfde cyclus wordt gebruikt om de resultaten weg te schrijven in het registerbestand (WB = write back). Het voornaamste verschil met de situatie in de vorige les is dat de WB voor de ALU-instructies nu niet uitgevoerd wordt in de vierde cyclus, maar wel in de vijfde. Men zegt dat de instructie uitgevoerd worden in vijf trappen. C=1 RegW=1 C=0 RegW=1 WB
Meer-cycli-per-instructiemachine ra PC IR geheugen Register- bestand rb A R S1 rd decoder B LMDR Din 4 offset PCSrc Alu PCW S2 Mar MemW MemR RegW IRW C Indien we een instructie in meerdere cycli wensen uit te voeren, dan moeten we ervoor zorgen dat bij de overgang van 1 cyclus naar een volgende de waarden die een cyclusovergang moeten overleven tijdelijk opgeslagen worden in een register (IR, LMDR, A, B, R, PC). Indien we een implementatie willen realiseren bestaande uit vijf trappen, dan zullen we extra registers moeten toevoegen. cond Controle-eenheid
IF ID EX MEM WB 4 + ra rb rd decoder w2 Controle-eenheid w1 w3 w0 w4 PC 4 Cmp + geheugen Data instructie- geheugen ra Register- bestand rb S1 rd decoder Res Din PC In deze dia werd op het einde van elke trap een register geplaatst. Alle signalen die door dit register lopen worden in principe op het einde van de cyclus opgeslagen in dit register, en bij het begin van de volgende cyclus aangeboden aan de volgende trap. Deze architectuur laat ons toe om eender welke instructie in 5 cycli uit te voeren. Alle informatie die een trap nodig heeft om te kunnen werken zal door het register dat aan de trap voorafgaat aangeboden worden. Aangezien de bestemming van een sprong pas bekend is na de EX trap, of zelfs na de MEM trap indien het een geheugenindirecte sprong zou zijn, wordt de berekening van de nieuwe PC volledig verhuisd naar de WB trap. De PC functioneert hierbij dan eigenlijk als register dat de WB-trap afsluit. Deze opstelling wordt een pijplijn genoemd. De instructies gaan aan de linkerzijde in de pijplijn, en verplaatsen zich naar rechts aan een vast tempo. De registers tussen twee pijplijntrappen worden de pijplijnregisters genoemd. De pijplijnregisters worden aangestuurd door extra controlesignalen w0..w4. Deze controlesignalen bepalen wanneer een pijplijnregister waarden zal opnemen en doorgeven aan de volgende trap. offset MemW MemR S2 Alu RegW w2 Controle-eenheid w1 w3 w0 w4
Controle van de pijplijnregisters w0 w1 w2 w3 w4 IF 0 1 0 0 0 ID 0 0 1 0 0 EX 0 0 0 1 0 MEM 0 0 0 0 1 WB 1 0 0 0 0 Voor de uitvoering van een instructie in 5 cycli zijn dit de controlesignalen die naar de pijplijnregisters moeten gestuurd worden. Links staat de toestand waarin de pijplijn aan het uitvoeren is. Per toestand wordt aangegeven welke pijplijnregisters er geactiveerd worden.
Controletabel MEM WB EX S1 S2 Alu Cmp MemW MemR Res PC RegW add 1 0 001 xxx 0 0 1 0 1 addi 1 1 001 xxx 0 0 1 0 1 load 1 1 001 xxx 0 1 0 0 1 store 1 1 001 xxx 1 0 x 0 0 jump 0 1 001 111 0 0 1 1 0 De controletabel blijft dezelfde, maar het is nu niet meer nodig om de signalen gedurende de volledige uitvoering actief te houden. Tijdens de uitvoering van een instructie is er maar 1 pijplijntrap per keer actief, en enkel de controlesignalen die met de actieve trap geassocieerd zijn, moeten geactiveerd worden. Merk op dat het RegW signaal, ofschoon het een blok in de ID trap aanstuurt, pas aangestuurd wordt in de WB trap. Dit komt omdat het registerbestand tweemaal gebruikt worden, éénmaal in ID en éénmaal in WB. Op de figuur wordt dit ook schematisch gesuggereerd. Ook het PC controlesignaal wordt in de WB fase aangestuurd, net op tijd voor de volgende IF trap. In de IF en ID trap zijn er dus geen controlesignalen in dit model. Dit hoeft ons niet te verbazen omdat deze twee trappen onafhankelijk zijn van de uit te voeren instructie en de controle kan dus vast zijn. Het is pas vanaf de EX trap dat er verschillen optreden die moeten aangestuurd worden door de controle- eenheid. brge 0 1 001 110 0 0 1 1 0
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid PC geheugen PC PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De sturing van de controlesignalen kan aanzienlijk vereenvoudigd worden indien we de signalen allemaal laten genereren in de ID trap, en we deze signalen dan – net zoals alle andere signalen – via de pijplijnregisters doorgeven. Op die manier zullen de signalen op het gepaste ogenblik aangelegd worden. Let in het bijzonder op het RegW signaal dat artificieel vertraagd wordt tot in de WB-trap alvorens aangelegd te worden aan het registerbestand. Omdat we streven naar een situatie waarbij er per cyclus maar één trap actief is, zullen we het rd signaal ook vertragen zodat het pas in de WB-trap aan het registerbestand aangelegd wordt. Op die manier wordt verhinderd dat de controle-eenheid het rd signaal moet bewaren tot in de WB-trap. RegW S2 Cmp Controle- eenheid
Soorten instructies ALU-instructies add r1, r2, r3 addi r1,19, r3 load/store load r1, 0x100(r2) store r1,0x100(r2) controletransfer jump 0x10(pc) brge r1, 0x10(pc) We gaan de verschillende soorten instructies nu eens door de net opgestelde pijplijn sturen.
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid add r1,r2,r3 PC PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De add-instructie vereist nu 5 cycli om uit te voeren. In de MEM-trap gebeurt er niets. Deze zal enkel maar gebruikt worden bij de uitvoering van geheugentransferinstructies. RegW S2 Cmp Controle- eenheid add r1,r2,r3
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid addi r1,19,r3 PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De addi-instructie is nauwelijks verschillend. RegW S2 Cmp Controle- eenheid addi r1,19,r3
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid PC geheugen PC PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De load-instructie gebruikt de EX-trap om de adresseermode uit te rekenen, de MEM-trap om de waarde uit het geheugen te halen, en de WB-trap om het resultaat in het registerbestand te schrijven. RegW S2 Cmp Controle- eenheid load r1, 0x100(r2)
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid PC geheugen PC PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De store-instructie vertoont veel gelijkenis met de load-instructie. Ze produceert alleen geen resultaat in een register. RegW S2 Cmp Controle- eenheid store r1, 0x100(r2)
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid jump 0x10(pc) PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR De onvoorwaardelijke-spronginstructie gebruikt de EX-trap om de bestemming van de sprong uit te rekenen. In de WB-trap wordt dit resultaat teruggestuurd naar de IF-trap. RegW S2 Cmp Controle- eenheid jump 0x10(pc)
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid PC geheugen PC PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR Bij de voorwaardelijke-spronginstructie bepaalt de sprongvoorwaarde of de sprong al dan niet genomen wordt (keuze tussen PC+4 en PC+4+offset). RegW S2 Cmp Controle- eenheid brge r1,0x10(pc)
Sequentiële pijplijncyclus F D E M W i1 i2 F D IF ID EX MEM WB i1 i2 i1 i2 Pijplijn: fetch Deze dia illustreert nogmaals de tot dusver beschouwde uitwerking van de instructies door de controle-eenheid: elke instructie doorloopt 5 pijplijntrappen (Fetch, Decode, Execute, Memory, Writeback), waarbij de langst durende trap zal bepalen hoe groot een klokperiode mimimaal moet zijn (hier is dit de execute trap). Een volgende instructie wordt pas aangevat wanneer de vorige instructie volledig is verwerkt. Indien we naar de individuele trappen van de pijplijn kijken, dan zien we dat een trap gemiddeld gezien maar om de 5 cycli eens gebruikt wordt, en ongebruikt blijft tijdens de overige cycli. i1 Pijplijn: decode Pijplijn: execute i1 Pijplijn: memory i1 Pijplijn: writeback
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Parallelle pijplijncyclus t i1 i2 i3 F D E M W F D E M W F D E M W IF ID EX MEM WB i1 i2 i3 i1 i2 i3 Dit kan vermeden worden door de pijplijn verschillende instructies na elkaar te laten verwerken. Tijdens de decodeerfase van de eerste instructie kan de tweede instructie reeds ingeladen worden, enz. Uiteraard werkt dit enkel maar dank zij het feit dat in het sequentiële pijplijnmodel er maar precies 1 trap actief is tijdens de uitvoering van een instructie. Bovendien werkt het enkel maar voor instructies die geen controletransfer zijn aangezien de nieuwe PC dan pas in de EX trap bekend geraakt. Controletransferinstructies kunnen nog steeds correct uitgevoerd worden indien we na de controletransfer nog vier NOP-instructies plaatsen. Deze instructies vullen de pijplijn gedurende vier cycli totdat de bestemming van de sprong bekend geraakt. Verder zijn ze niet schadelijk. Dit aspect wordt verder uitvoerig behandeld. i1 i2 i3 i1 i2 i3 i1 i2 i3
IF ID EX MEM WB 4 + ra rb decoder rd Controle- eenheid CPI: 5 → 1 PC 4 + geheugen Data PC instructie- geheugen ra Register- bestand rb S1 decoder rd Res Din offset Alu MemW MemR Vergewis U van het feit dat het dankzij de pijplijnregisters is dat de verschillend trappen volledig ontkoppeld kunnen worden, en dat er 5 verschillende instructies simultaan in uitvoering kunnen zijn. Merk op dat PC+4 nu rechtstreeks doorgestuurd wordt naar de WB trap zodat in een volgende cyclus de volgende instructie kan opgehaald worden. Dit werkt voor alle instructies behalve voor de controletransferinstructies (zie verder). Dit is een model met 5 trappen. Moderne processors kunnen heel wat meer trappen bevatten. De Pentium 4 heeft 20 of 31 pijplijntrappen. Door de trappen die hier getekend zijn verder op te splitsen in deeltrappen, met daartussen pijplijnregisters kan men de maximale uitvoeringstijd per trap verder reduceren. Dit laat toe de klokfrequentie verder op te drijven. Merk trouwens op dat de instructies bij een gepijplijnde uitvoering niet noodzakelijk sneller uitvoeren. Per instructie is en blijft de uitvoeringstijd voor niet-controletransferinstructies 5 cycli. Doordat er 5 instructies simultaan verwerkt worden, zal men in dezelfde tijd wel 5 keer meer instructies kunnen uitvoeren, waardoor de gemiddelde uitvoeringstijd 1 cyclus is, en dit terwijl de uitvoeringstijd voor 1 instructie wel degelijk 5 cycli blijft. Men spreekt in dit verband van CPI (clocks per instruction) en IPC (instruction per clock cycle). RegW S2 Cmp CPI: 5 → 1 IPC: 0,2 → 1 Controle- eenheid
EX MEM WB 4 + ID ra rb rd decoder IF Controle- eenheid PC Cmp PC EX PC MEM WB 4 + Cmp PC geheugen Data ID instructie- geheugen ra Register- bestand rb S1 rd decoder Res Din IF In de vorige dia is af te lezen dat de berekening van de nieuwe PC enkel maar gebruik maakt van informatie die in de EX-trap geproduceerd wordt (tenzij er een geheugenindirecte sprong zou gemaakt worden). In de tabel met controlesignalen stond inderdaad te lezen dat een sprong slechts drie cycli in beslag nam. Door de invoering van de pijplijnregisters was dit artificieel verhoogd tot 5. We kunnen dit ongedaan maken door de selectie van de nieuwe PC te laten doorgaan in de EX-fase, en meteen op te slaan in het PC-register. Dit is nodig om te vermijden dat we bij een controletransfer 5 cycli moeten wachten om de nieuwe PC te kennen. Door deze transformatie kan het wachten in dit geval tot drie cycli herleid worden. Er zijn in dit geval dus maar 2 NOP-instructies meer nodig om deze tijd te overbruggen. Later zal blijken dat het zo snel mogelijk te weten komen van het sprongadres een belangrijk element is in de prestatie van een microprocessor. In de praktijk probeert men deze berekening dan ook zo vroeg mogelijk te doen. offset Alu MemW MemR RegW S2 Controle- eenheid
Gepijplijnde architectuur Fetch Decode Execute Memory Write back data cond 4 smdr Data in + pc pc1 mar Adres lmdr Reg. file A res1 res2 B alu In de praktijk kan men onderdelen van de pijplijnregisters gaan benoemen. Hier komen een paar reeds gekende registernamen terug aan de oppervlakte. Op deze dia staat het model van de escape simulator. Het model is licht verschillend van het model van de voorgaande dia’s, maar het doet functioneel hetzelfde. In de fetch-trap wordt de instructie opgehaald, en wordt de volgende PC berekend (PC+4). In de decodeertrap worden de registerargumenten opgehaald. In de uitvoeringstrap worden hetzij het sprongadres, de adresseermode of het resultaat van de ALU-operatie berekend. De sprongadressen worden na drie cycli reeds teruggevoerd naar de fetchtrap. In de mem-trap wordt het datageheugen gebruikt, en in de writeback-trap wordt het resultaat terug naar het registerbestand geschreven. Merk op dat bij het terugschrijven het resultaat tegelijk in het registerbestand en in de registers A en B kan geschreven worden. Dit is om aan te geven dat moderne registerbestanden in dezelfde processorcyclus een waarde kunnen opnemen, en die waarde meteen ook beschikbaar kunnen stellen aan het einde van die cyclus. Conceptueel is dit mogelijk door de klok van het registerbestand wat te vervroegen zodat de op te slane waarde (die reeds vroeg in de cyclus beschikbaar is in de WB-trap) opgeslagen wordt, en reeds zichtbaar wordt aan de uitgang, net op tijd voor het invullen van A en B. Hier wordt het expliciet zichtbaar gemaakt door de extra multiplexer. inst. IR IR1 IR2 IR3 ST1 ST2 ST3
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Pijplijnhazards Hazards zijn afwijkingen van de standaard sequentiële interpretatie van de programmatekst Ze worden veroorzaakt door de overlappende uitvoering van instructies die na elkaar komen Als gevolg van het introduceren van een pijplijn in de implementatie van de controle-eenheid, en het datapad, zijn er een aantal risico’s aanwezig: pijplijnhazards. Een hazard is een (mogelijkheid tot) afwijking van de standaard sequentiële interpretatie en uitvoering van de programmacode. Ze worden veroorzaakt door de overlappende uitvoering van instructies, die normaal na elkaar uitgevoerd worden.
Pijplijnhazards structurele hazards: soms wensen twee instructies in verschillende trappen dezelfde hardware te gebruiken. controlehazards: instructies worden blind opgehaald en partieel uitgevoerd: soms is nog niet gekend welke instructie moet opgehaald worden. datahazards: een object wordt gebruikt door overlappende instructies. Soms is de gewenste waarde nog niet beschikbaar. Pijplijnhazards bestaan in 3 soorten: de structurele hazards, de controlehazards en de datahazards. Structurele hazards hebben meestal te maken met te schaarse hardware. Gesteld dat het registerbestand niet simultaan zou kunnen lezen en schrijven, dan zou er een structurele hazard kunnen optreden tussen de WB en de ID trappen. Indien een dergelijk conflict zich zou voordoen, zou er een volgorde moeten afgesproken worden (vb. eerst WB en dan ID). Controlehazards hebben vooral te maken met de vertraging waarmee bekend wordt of een sprong al dan niet mag genomen worden. Zolang de bestemming van de sprong niet bekend is, kan de processor eigenlijk niet verder. Datahazards hebben te maken met het feit dat resultaten van instructies pas in de vijfde cyclus bewaard worden, maar er ondertussen instructies kunnen zijn die van deze waarde gebruik willen maken. Deze hazards zullen nu één voor één besproken worden.
Structurele hazard t ldw brge add addi stw F D E M W F D E M W F D E M Opl: ontdubbelen hardware, extra poorten F D E M W F D E M W F D E M W Deze dia illustreert een structurele hazard voor de pijplijn met 5 trappen. Gesteld dat er slechts 1 geheugen zou zijn, en dat dit geheugen maar 1 aanvraag per keer kan bedienen. Dan zal er in het bovenstaande voorbeeld een conflict zijn tussen de MEM-trap van de ldw instructie, en de IF-trap van de addi. Structurele hazards kunnen vermeden worden door onderdelen van de processor te ontdubbelen waardoor de twee simultane aanvragen wel gewoon door kunnen gaan. Structurele hazards zijn voornamelijk een probleem in microarchitecturen waar niet alle EX-trappen even lang duren (1, 2, of meer cycli, afhankelijk van de instructie) en parallel kunnen uitvoeren. Dan is niet statisch te voorspellen op welk ogenblik een bepaalde pijplijntrap een bepaald onderdeel van de processor zal nodig hebben. F D E M W F D E M W Pijplijnhazards: structureel
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Controlehazard t ldw brge add addi stw F D E M W Controle hazard F D E in vlucht F D E M W Deze dia illustreert een controlehazard voor de pijplijn met 5 trappen. Na de spronginstructie brge zullen de volgende 2 ingeladen instructies steeds komen uit de sequentiële programmacode. Pas op het einde van de execute- fase van de spronginstructie, blijkt (desgevallend) dat de sprong genomen moet worden en wordt de PC blindelings aangepast. De 2 instructies die ingeladen werden tussen het inladen van de spronginstructie en het bekend worden van de bestemming van de sprong, zouden volgens een strikt niet- gepijplijnde uitvoering (de zgn. sequentiële semantiek van het programma) nooit ingeladen en uitgevoerd worden. Instructies die aan hun uitvoering begonnen zijn, noemen we “in vlucht”. F D E M W F D E M W Pijplijnhazards: controle
Controlehazards: oplossingen Instructies in uitvoering vervangen door NOPs “pijplijnbellen” indien de sprong blijkt genomen te moeten worden Instructies gewoon verder laten uitvoeren (vertraagde controletransfer) Sprongen ‘voorspellen’ Er bestaan een aantal verschillende oplossingen om controlehazards te behandelen, en zoveel mogelijk te vermijden. Men kan de instructies die onterecht in uitvoering zijn, annuleren door ze tijdens hun uitvoering te vervangen door NOPs. M.a.w. worden de instructies omgezet in pijplijnbellen. Dit is net op tijd voordat er een toestandsverandering in de processorregisters of het geheugen veroorzaakt wordt (zie verder). Een andere aanpak is deze instructies toch uit te voeren. Door in de architectuur te definiëren dat bv. 1 of 2 instructies na een spronginstructie steeds worden uitgevoerd, onafhankelijk van het feit of de sprong genomen wordt, hoeft men zich in de processor zelf geen zorgen te maken over de controlehazards: men heeft het probleem verschoven naar de programmeur (of compiler). Men noemt dit een “vertraagde controletransfer”. Men kan in de fetch trap ook een poging doen om sprongen te voorspellen: men kan dan de verdere instructies afhalen vanaf de voorspelde locatie. Enkel indien later blijkt dat de voorspelling fout was, moeten de verkeerdelijk in vlucht zijnde instructies geannuleerd worden.
Controlehazards: stopzetten uitvoering pijplijnbellen ldw brge add addi stw F D E M W Controle hazard F D E M W F D E M W in vlucht F D E M W Deze dia illustreert de aanpak van controlehazards door ze om te zetten in pijplijnbellen. Omdat er in de fetch en decode trap geen permanente wijzigingen worden aangebracht in de processortoestand, zijn er geen blijvende gevolgen van het inladen en decoderen van de instructies. F D E M W F D E M W
EX MEM WB 4 + ID ra rb rd decoder IF Controle- eenheid PC Cmp PC EX PC MEM WB 4 + Cmp PC geheugen Data ID instructie- geheugen ra Register- bestand rb S1 rd decoder Res Din IF Het creëren van pijplijnbellen is eenvoudig. Het volstaat dat het signaal dat aangeeft dat er moet gesprongen worden de ingeladen en gedecodeerde versie van de instructie in de pijplijnregisters annuleert door ze b.v. op nul te zetten. Hierdoor zullen alle effecten van deze reeds ingelezen en gedecodeerde instructies verhinderd worden (ze worden a.h.w. omgezet in nop-instructies). Deze NOP-instructies kunnen verder ongehinderd door de pijplijn reizen. offset RegW Alu MemW MemR S2 Controle- eenheid
Controlehazard: vertraagde controletransfer ldw brge add addi stw F D E M W Controle hazard F D E M W F D E M W in vlucht F D E M W Bij een vertraagde controletransfer worden de 2 instructies (kan ook 1 of 3 zijn) na elke controletransfer steeds uitgevoerd, ongeacht het feit of de controletransfer genomen wordt of niet. Men moet deze 2 instructieslots dus opvullen met bewerkingen die sowieso mogen uitgevoerd worden. Vindt men geen geschikte instructies, dan kan men nog steeds NOP-instructies invoegen. Afhankelijk van het aantal pijplijntrappen kan het aantal instructies na de controletransfer variëren. Eén tot drie instructies komen courant voor. Uiteraard verkiest men een zo klein mogelijk aantal instructieslots. Vandaar dat men vaak poogt om de selectie van de volgende PC reeds in de ID-trap te laten gebeuren. Dit is soms mogelijk (zie volgende dia). F D E M W F D E M W
Controlehazards addi r0,10,r1 br 100 addi r1,1,r1 muli r1,3,r1 …. 100: stw r1,0x0100(r0) Zonder vertraagde sprong (klassiek) addi r0,10,r1 br 100 nop stw r1,0x0100(r0) Met vertraagde sprong addi r0,10,r1 br 100 addi r1,1,r1 muli r1,3,r1 stw r1,0x0100(r0) Het verschil tussen de klassieke sprong en de vertraagde sprong wordt hier nogmaals aangetoond op basis van de trace (de sequentie van uitgevoerde instructies). Terwijl bij een klassieke uitvoering de 2 instructies na de sprong worden geannuleerd (hier werden ze vervangen door NOP-instructies), worden die bij een vertraagde sprong wel uitgevoerd. Het eindresultaat is duidelijk verschillend - en het moet voor de programmeur en compilerbouwer duidelijk zijn hoe de processor hiermee omgaat. TRACE
+ EX MEM WB 4 + ID ra rb rd decoder IF Controle- eenheid Cmp PC EX MEM WB 4 + Cmp geheugen Data ID instructie- geheugen ra Register- bestand rb rd decoder Res Din IF Indien men de twee ALU’s die betrokken zijn bij de selectie van de nieuwe PC zou verplaatsen/dupliceren in de ID trap, dan zou men de controletransferinstructie zelfs nog een cyclus korter kunnen maken. Dit is uiteraard enkel zinvol indien de cyclustijd hierdoor niet zou toenemen. Het is weinig waarschijnlijk dat de berekening van de bestemming van de controletransfer een probleem zou stellen aangezien de PC bij het begin van de cyclus reeds beschikbaar is, en de offset zeer kort na het begin van de cyclus. Bovendien is een optelling niet de meest tijdrovende ALU-operatie. De comparator is iets moeilijker omdat deze moet wachten op een input uit het registerbestand. Indien de vergelijking eenvoudig is (controle van het tekenbit, of controle of een bitpatroon 0 is) kan het voldoende snel gemaakt worden om nog binnen dezelfde cyclus de multiplexer aan te sturen en de nieuwe PC te produceren. Op deze manier veroorzaakt de controlehazard maar 1 probleeminstructie, waardoor er minder cycli verloren gaan, of er minder instructies dienen gezocht te worden voor in de instructieslots. Heel wat processors voor algemeen gebruik hebben dan ook maar 1 delayslot. Indien het niet lukt om de comparator naar de ID-trap te verhuizen dan kan men de uitkomst van de comparator proberen te voorspellen (sprongvoorspelling, zie verder). offset RegW Alu MemW MemR PC S2 Controle- eenheid
Vertraagde sprong add r1,r1,1 jump next nop … next: or r2, r1, r0 Het komt er dus op aan de slot(s) volgend op een vertraagde sprong op te vullen met nuttige instructies. Bij een onvoorwaardelijke sprongen kunnen deze instructies van vóór de spronginstructie komen, of van op de bestemming van de sprong. Hier wordt een voorbeeld getoond waarbij de instructie van net vóór de sprong komt. Uiteraard mag het geen instructie zijn waarvan de sprong kan afhangen (b.v. in het geval van een berekende sprong).
Vertraagde sprong add r1,r1,1 jump next nop … next: or r2, r1, r0 Het andere alternatief gaat zoeken op de plaats van de bestemming van de sprong. In dit geval mag de instructie die men in het instructieslot plaatst niet weggelaten worden indien er ook nog andere controletransfers kunnen voorkomen die naar label ‘next’ springen.
Vertraagde Sprong / Sparc cmp r1, 1 breq next nop … next: mov 2, r1 cmp r1, 1 breq,a next2 mov 2, r1 … next: mov 2, r1 next2: Bij een voorwaardelijke sprong is het allemaal wat moeilijker. Die instructies die aan de sprong voorafgaan zijn vaak instructies die mee helpen om de sprongconditie vast te leggen. Deze komen dus niet in aanmerking om in het instructieslot te plaatsen. Mochten er wel onafhankelijke instructie voorkomen, dan kunnen deze uiteraard wel gebruikt worden. De instructies op de bestemming van de sprong zijn ook geen alternatief omdat deze maar uitgevoerd dienen te worden indien de sprong ook effectief uitgevoerd wordt. De SPARC architectuur biedt een middel aan om in deze gevallen toch nog in de helft van de gevallen van de vertraagde sprong te kunnen profiteren: annulatie. Men mag een instructie van de bestemming schrijven in het instructieslot, maar deze zal geannuleerd worden indien de sprong niet genomen wordt. Indien de sprong wel genomen wordt, dan wint men een cyclus. Een andere mogelijkheid bestaat erin om een instructie op te nemen die enkel nuttig is voor het then of het else pad, maar in het andere pad geen schade aanricht, zoals geïllustreerd in de volgende dia.
Procedure-oproep int vijfvoud(int n) { if (n > 0) return n * 5; else return 0; } int g; main() g = vijfvoud(6); vijfvoud: jmpf lr2,positief sll gr96,lr2,2 jmpi lr0 const gr96,0 positief: jmpi lr0 add gr96,gr96,lr2 call lr0,vijfvoud const lr2,6 const gr97,g consth gr97,g store gr96,gr97 Deze dia illustreert het belang van de vertraagde sprong. Het is de implementatie van de functie vijfvoud + oproep uit een eerdere les voor de AMD 29000 processor. In het hoofdprogramma wordt de functie vijfvoud opgeroepen. Het terugkeeradres komt in register lr0, terwijl het argument doorgegeven wordt in register lr2. Het initialiseren van lr2 gebeurt in het delay slot voor de call instructie. In de functie zelf wordt er gesprongen naar het label positief indien lr2 een positief getal bevat. De instructie jmpf test de tekenbit. Voor een positief getal wordt de sprong genomen. In het delayslot van de voorwaardelijke sprong wordt lr2 reeds met 4 vermenigvuldigd (verschuiving over 2 bits naar links). Op het label positief staat een jmpi instructie naar register lr0 wat de implementatie is van een return. In het delayslot van de return wordt lr2 nog eens opgeteld bij het viervoud dat zich reeds in register gr96 bevindt. In het negatieve geval staat er ook een return (jumpi lr0) waarbij in het delayslot het resultaat geproduceerd worden (0). In het hoofdprogramma wordt het resultaat weggeschreven op adres g. Het 32- bit adres wordt eerst in 2 stukken geladen in gr97, dat dan gebruikt wordt om registerindirect het resultaat in gr96 weg te schrijven. Hieruit blijkt dat de impact op de prestatie van een programma niet te verwaarlozen is. Merk ook op dat het delay slot van de voorwaardelijk sprong maar in 1 geval nuttig gebruikt kan worden. In het andere geval is het echter niet schadelijk.
Sprongvoorspelling BP + EX MEM WB 4 + ID ra rb rd decoder IF Controle- PC + EX MEM WB 4 Cmp + geheugen Data ID instructie- geheugen ra Register- bestand rb rd decoder Res Din IF Een sprongvoorspeller probeert, uitgaande van het voorbije gedrag van het programma te voorspellen wat de volgende in te laden instructie zal zijn. Sprongvoorspellers bestaan in heel wat variëteiten en kunnen een nauwkeurigheid halen van meer dan 95% op realistische programma’s. offset RegW Alu MemW MemR PC S2 Controle- eenheid
Sprongvoorspellers Branch Target Buffer Statische voorspellers Niet-genomen Backward taken/forward not taken Dynamische voorspellers 1-bit voorspeller 2-bit voorspeller Lokaal Globaal Een sprongvoorspeller voorspelt in de IF fase of een sprong al dan niet genomen zal worden. De generatie van het adres waarnaar moet gesprongen worden gebeurt in de ID-trap. Bij een vijftrapspijplijn levert ons dit geen winst op omdat deze in sommige gevallen de uitkomst kan berekenen in 2 cycli. Dan heeft een voorspelling uiteraard geen zin. Indien de uitkomst van een complexe vergelijking in een diepe pijplijn echter pas in de 5e trap bekend wordt, dan levert het een winst op omdat de sprong dan wel reeds in de ID- trap kan voorspeld worden. De overblijvende cyclus kan eventueel met een vertraagde sprong opgevangen worden. Het sprongadres kan ook in de IF-trap voorspeld worden, maar daarvoor moeten we in de sprongtabellen ook de adressen bijhouden (in een zgn. Branch Target Buffer). Er bestaan verschillende soorten sprongvoorspellers: statische en dynamische. Ze worden hierna uitgelegd.
Branch Target Buffer PC adres sprong bestemming + RAS voorspelling Indien we een voorspelling willen maken in de IF-trap, dan moeten we naast de informatie over het al dan niet nemen van een sprong, ook informatie bijhouden over de bestemming van de sprong (ook voor niet-conditionele sprongen). Dit vereist een tabel waar zowel het adres van de spronginstructie in voorkomt (deze informatie wordt gebruikt om de tabel associatief te doorzoeken), als de voorspelde bestemming van de sprong. Sprongen die niet-genomen voorspeld worden, hoeven niet in deze tabel opgenomen te worden. Indien een bepaald adres niet gevonden wordt, wordt automatisch het doorvalpad gekozen. Het voorspellen van de bestemming van een returninstructie vergt echter speciale aandacht. Aangezien het bestemmingsadres van een returninstructie afhangt van de oproeper, werkt een klassieke BTB niet zo goed omdat deze steeds de laatste bestemming weergeeft. Daarom wordt voor terugkeerinstructies een zgn return address stack (RAS) gebruikt. Dit is gewoon een cache van terugkeeradressen die steeds het meest recente terugkeeradres teruggeeft. + RAS voorspelling
Voorspel niet-genomen loop: cmp r1,r2 jne einde … lus … jump loop einde: In de normale werking van de pijplijn wordt na een sprong de instructie die volgt op de sprong ingeladen. Dit staat in feite gelijk met het voorspellen dat de sprong niet genomen wordt. Men kan dit gedrag exploiteren door bij een lus de voorwaardelijke spong in het begin van de lus te plaatsen, zodat in het meest voorkomende geval de voorspelling inderdaad juist is. Een onvoorwaardelijke sprong wordt uiteraard steeds als genomen voorspeld.
Branch backward taken/ forward not taken cmp r1,0 jle einde loop: … lus … cmp r1,r2 jne loop einde: De voorspelling kan ook afhankelijk gemaakt worden van de richting waarin de sprong gaat. In dit geval is het beter om de voorwaardelijke sprong achteraan de lus te plaatsen omdat hij in deze gevallen correct voorspeld zal worden. Indien de microarchitectuur het voorspellingsgedrag van voorwaardelijke spronginstructies vastlegt, moet de compiler zich hiernaar schikken. Deze strategie is duidelijk ingegeven door het gedrag van lussen met een test op het einde.
Eenvoudige dynamische voorspeller sprongtabel 1 laagste bits PC voorspel genomen Een dynamische voorspeller maakt een voorspelling op basis van de inhoud van een sprongtabel. Zo kan in de tabel bijvoorbeeld bijgehouden worden of de sprong op een gegeven adres de vorige keer al dan niet genomen werd. Dit werkt vrij goed voor lussen op voorwaarde dat een lus een voldoende aantal keer na elkaar uitgevoerd wordt. Bij elke foute voorspelling wordt de waarde in de sprongtabel aangepast aan de nieuwe situatie. Problemen bij deze eenvoudige dynamische voorspeller zijn: Bij het verlaten van de lus zal er verkeerd voorspeld worden dat de lus moet hernomen worden. Bij het voor de eerste keer heruitvoeren van de lus zal er opnieuw een verkeerde voorspelling gemaakt worden. Indien de lus 10 keer moet uitgevoerd worden, dan zal ze 2 x (=20%) verkeerd voorspeld worden. De sprongtabel is veel kleiner dan het aantal adressen (b.v. 2 Kib) in het programma. Dit wil zeggen dat sommige sprongen hun informatie op dezelfde plaats zullen achterlaten waardoor er informatie van andere sprongen zal vernietigd worden. Dit fenomeen wordt aliasing of verwarring genoemd. Deze kan destructief maar ook constructief zijn. sprongtabel aanpassen als uitkomst gekend 1=genomen 0=niet genomen
2-bit dynamische voorspeller sprongtabel 11 01 00 10 voorspel genomen 11 10 laagste bits PC 01 00 niet-genomen voorspel Het probleem van het einde van de sprong kan adequaat opgelost worden door i.p.v. 1 bit meerdere bits bij te houden in de sprongtabel (2 blijkt in de praktijk voldoende te zijn). Rechts staat de toestandsautomaat die aangeeft op welke manier de bits in de tabel aangepast worden. Deze toestandsautomaat kan geïnterpreteerd worden als saturerende 2-bit teller waarbij de waarden 3 en 2 (toestand 11 en 10) aanleiding geven tot de voorspelling ‘sprong genomen’ en waarden 0 en 1 (toestand 00 en 01) aanleiding geven tot de voorspelling ‘sprong niet- genomen’. Na een genomen sprong wordt de teller verhoogd tenzij deze reeds op de maximale waarde 3 staat. Analoog wordt de teller verminderd na een niet-genomen sprong tenzij deze reeds op de minimale waarde 0 staat. Kan je aantonen dat met deze tweebits voorspeller het aantal foute voorspellingen in een lus van b.v. 10 iteraties inderdaad van 2 naar 1 herleid wordt? Een tweebits voorspeller zoals hier voorgesteld kan gemakkelijk 90% voorspellingsnauwkeurigheid halen. 1=genomen 0=niet-genomen genomen niet-genomen
Lokale dynamische voorspeller geschiedenistabel sprongtabel 11010101 01111111 00000000 10101010 10001000 11111111 00 01 10 .. 11 laagste bits PC In plaats van een voorspelling te baseren op de laatste uitkomst van de voorwaardelijke sprong, is het ook mogelijk om deze te baseren op de geschiedenis van uitkomsten (b.v. de laatste 8). Per uitgevoerde sprong wordt in het schuifregister van de eerste tabel een bit bijgeschoven. In deze tabel ontstaat dus een geschiedenis van spronguitkomsten (allemaal 1’tjes betekent dat de sprong de laatste 8 keer genomen werd, 8 nulletjes betekent dat de sprong de laatste 8 keer niet genomen werd). Op basis van dit patroon wordt dan gekeken in een tweede tabel om te zien wat er bij een dergelijk patroon moet voorspeld worden. Dit kan eveneens gebeuren met de toestandsautomaat gebruikt in de 2-bit dynamische voorspeller. Allemaal 1’tjes in de geschiedenis zal wellicht een voorspelling van 1 teruggeven, evenals sommige patronen waarin herhaling herkenbaar is. Een patroon van allemaal nulletjes geeft een voorspelling 0 terug. Op die manier kan informatie over het gedrag van sommige sprongen uitgewisseld worden met een vergelijkbaar gedrag van andere sprongen (in de tweede tabel). voorspel genomen 1=genomen 0=niet genomen
Globale dynamische voorspeller 1 sprongtabel Globale- geschiedenis- register 1 00 01 10 11 1 1011111111 1 + voorspel genomen Op precies dezelfde manier kan er ook vertrokken worden van een globale geschiedenis. Dit is een geschiedenis zoals de processor ze zich ziet voltrekken. Per sprong die ontmoet wordt, wordt een bit toegevoegd aan het globale-geschiedenisregister, en deze geschiedenis wordt dan gebruikt om een sprongtabel te indexeren. Op die manier kan de correlatie tussen bepaalde sprongen (in geneste if-testen b.v.) uitgebuit worden. Om te vermijden dat twee globale geschiedenissen – afkomstig van twee verschillende plaatsen in het programma – noodzakelijk ook dezelfde voorspelling moeten opleveren, zal men vaak het geschiedenisregister XOR- en met een aantal bits van de PC. Op die manier maakt men beter gebruik van de sprongtabel omdat de XOR met de PC er zal voor zorgen dat de indices in de sprongtabel meer verstrooid geraken. Deze techniek kan ook toegepast worden bij een lokale dynamische voorspeller. PC 1=genomen 0=niet genomen
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Datahazard t ldw r1, ldw r2, addi r0,10,r3 add r3,5,r4 addi sub F D E M W data hazard F D E M W F D E M W F D E M W Deze dia illustreert een datahazard. De vierde instructie maakt gebruik van r3, welke door de derde instructie wordt berekend. Echter de vierde instructie leest de waarde r3 tijdens zijn ID-trap, terwijl de derde instructie r3 schrijft tijdens zijn WB-trap. Het komt er dus op neer dat r3 wordt uitgelezen door de vierde instructie nog voor r3 correct is bijgewerkt door de derde instructie. De vierde instructie riskeert dus een totaal verkeerd resultaat af te leveren omdat ze gebruikt maakt van de oude waarde van r3. F D E M W F D E M W Pijplijnhazards: data
Datahazards oplossingen Instructies ver genoeg uit elkaar zetten Blokkeren pijplijn Forwarding De foute gevolgen van echte afhankelijkheden wegwerken kan op 3 manieren (die in volgende dia’s worden geïllustreerd): Men kan die instructies die van elkaar afhankelijk zijn, ver genoeg uit elkaar zetten. Wat precies ver genoeg is, hangt af van de architectuur (i.h.b. van de pijplijn). Dit is een statische methode: de wijziging gebeurt in de programmacode, en dus buiten de processor. Dit maakt de code zeer specifiek voor de machine, en voorts weinig efficiënt indien er om voldoende afstand tussen instructies te bereiken NOP-instructies moeten bijgevoegd worden. Voorts kan men de pijplijn blokkeren tijdens de uitvoering, telkens zich een datahazard voordoet. Men stelt dan de uitvoering van de tweede instructie uit tot de eerste instructie afgelopen is, of althans ver genoeg gevorderd. Dit laat toe dat de programmacode niet bijzonder moet ingesteld zijn voor de pijplijn (correctie wordt dynamisch gewaarborgd), maar verhelpt niets aan het gebrek aan efficiëntie. Tot slot kan men de forwarding-techniek introduceren in het datapad: dit betekent dat van zodra dat het resultaat bestaat op de processor, het beschikbaar is voor volgende instructies die dit resultaat gebruiken, zelfs al is het resultaat nog niet ingeschreven in het registerbestand.
Oplossing datahazards: herschikken instructies+nops ldw r1, ldw r2, addi r0,10,r3 nop add r3,5,r4 F D E M W F D E M W F D E M W F D E M W Deze dia illustreert hoe datahazards vermeden worden als afhankelijke instructies ver genoeg uiteen zijn geplaatst. In eerste instantie zal men proberen om door het verplaatsen van instructies zoveel mogelijk nuttige instructies tussen de afhankelijke instructies te plaatsen. Indien dit niet mogelijk is, moet men zijn toevlucht zoeken tot NOP-instructies. In dit geval zijn twee NOP-instructies voldoende omdat we er kunnen van uitgaan dat de waarden die in het registerbestand beschreven worden tijdens de WB-trap, nog tijdens dezelfde cyclus aan de uitgang van het registerbestand zullen verschijnen (dit hindert niet omdat de waarden tot niet verder zullen gepropageerd worden dan de pijplijnregisters). De geschreven waarde kunnen dus in een volgende cyclus al in de EX-trap gebruikt worden. F D E M W F D E M W
Oplossing datahazards: pijplijnblokkeringen (stalls) ldw r1, ldw r2, addi r0,10,r3 addi r3,5,r4 addi sub F D E M W F D E M W F D E M W F D D D E M W Men kan datahazards behandelen door de tweede instructie lang genoeg op te houden (blokkeren, stall) terwijl de eerste instructie verder wordt afgewerkt. In de eenvoudige pijplijn die we hebben gezien, betekent dit dat ook alle instructies die volgen op de tweede instructie, worden geblokkeerd in hun trap. Op deze manier wordt de afhankelijkheid gegarandeerd, maar de kost is hoog: de uitvoering van het programma wordt gedurende een tweetal cycli gewoon stilgezet. Een blokkering betekent dat de controlesignalen voor de voorliggende trappen gewoon aangehouden worden, en dat de bijhorende pijplijnregisters geen signaal krijgen om nieuwe waarden op te nemen. Men zou kunnen zeggen dat de voorliggende trappen de berekeningen gewoon nogmaals uitvoeren, ofwel dat de pijplijnregisters nog even wachten om de resultaten op te nemen. F D D D E M F D E
Oplossing datahazards: forwarding ldw r1, ldw r2, addi r0,10,r3 addi r3,5,r4 addi sub F D E M W F D E M W F D E M W F D E M W De snelste oplossing voor datahazards is de forwarding-techniek. Het is niet omdat een waarde nog niet in het registerbestand bewaard werd, dat deze waarde nog niet zou bestaan. Twee cycli eerder werd deze waarde reeds door de ALU berekend. Mocht de ALU kunnen gaan spieken bij de waarden die verder door de pijplijn aan het propageren zijn, dan zou hij deze waarden kunnen gebruiken en zou het niet nodig zijn om de pijplijn gedurende twee cycli te blokkeren. Het vervroegd gebruiken van deze waarden wordt forwarding genoemd. Forwarding kan gebeuren vanuit de output van de EX- trap, of vanuit de output van de MEM-rap. F D E M W F D E M W
Forwarding EX MEM WB 4 + ID ra rb rd decoder IF Controle- eenheid PC EX PC MEM WB 4 + Cmp PC geheugen Data ID instructie- geheugen ra Register- bestand rb S1 rd decoder Res Din IF Om forwarding te realiseren, is het nodig dat er een aantal extra verbindingen worden gemaakt in het datapad: zo wordt uitgang van de ALU- trap aangeboden aan de ALU (terugkoppeling over afstand 1: MEM-trap naar EX-trap) en wordt de uitgang van de MEM-trap aangeboden aan de ALU (terugkoppeling over afstand 2: van WB-trap naar EX-trap). De terugkoppeling over afstand 3, WB-trap naar ID-trap kan als forwarding gezien worden, of als normale werking van het datapad of registerbestand. Het betekent alvast dat in eenzelfde klokcyclus de waarde die in het registerbestand wordt ingeschreven (door een WB-trap) er ook kan worden uitgelezen door een ID-trap. offset MemW MemR RegW Alu S2 Controle- eenheid
Pijplijnen In principe per klokperiode een nieuwe instructie Elke instructie vraagt 5 klokperioden voor uitvoering Vijf instructies tegelijkertijd in verschillende stadia van uitvoering Klokfrequentie hangt af van trapvertraging De klokfrequentie kan verhogen door het aantal trappen sterk te verhogen Aantal instructies/cyclus: <1 Tot slot worden enkele principes van een in-order gepijplijnde processor samengebracht. In principe begint en eindigt er per klokcyclus één instructie, dit in de veronderstelling dat elke instructie gedurende 1 klokcyclus in 1 trap verblijft, en dat de traagste trap dus de klokperiode bepaalt. Dan vraagt elke instructie dus 5 klokperioden om te worden uitgevoerd, en zijn er ten allen tijde dus 5 instructies in uitvoering. Verder kan men de klokfrequentie verhogen door de traagste trappen op te splitsen in twee trappen, en dus meer, maar snellere trappen te construeren. Met een enkelvoudige pijplijn zal het aantal instructies per cyclus (IPC) nooit boven 1 stijgen. In de praktijk zal men ten gevolge van data- en vooral controle-hazards zelfs een stuk onder 1 IPC blijven. Indien men een IPC van meer dan 1 wenst, dan zal men moeten toelaten dan (i) de instructies in een andere volgorde uitgevoerd worden dan deze van het programma, en (ii) dat er per cyclus meer dan één instructie opgehaald en uitgevoerd wordt.
Prestatiematen IPC: instructies per cyclus CPI: cycli per instructie MIPS: miljoen instructies per seconde MFLOPS: miljoen floating point operaties per seconde (ook GFLOPS, TFLOPS) Uitvoeringstijd T=(CPI x instructies)/Freq Als je de prestatie van een processor op een abstractie manier wil beschrijven, zijn er een aantal mogelijkheden. Je kan de prestatie op cyclusniveau beschrijven (gemiddeld aantal instructies per cyclus of gemiddeld aantal cycli per instructie). Je kan de prestatie ook per tijdseenheid (1s) beschrijven: MIPS (voor de berekening op gehele getallen) en FLOPS (voor de berekening op vlottende komma getallen). Verder is er uiteraard ook de uitvoeringstijd van een programma. Belangrijk is wel dat al deze maten afhangen van het gebruikte programma. Het is duidelijk dat de MIPS-waarde voor een programma dat uitsluitend uit NOP-operaties bestaat hoger zal liggen dan de MIPS-waarde voor programma’s met veel controletransfers, delingen, enz. In de praktijk zal men gebruik maken van publiek beschikbare benchmarkprogramma’s om de prestatie vast te stellen.
Inhoud Sequentiële gepijplijnde machine Parallelle gepijplijnde machine Hazards Structurele hazards Controlehazards Datahazards Andere microarchitecturen
Superscalaire architectuur F D E M W F D E M W F D E M W F D E M W Indien er per cyclus maar 1 instructie ingeladen wordt, zal de IPC steeds kleiner dan 1 blijven. Om gemiddeld meer dan 1 instructie per cyclus te kunnen uitvoeren, moeten er ook meer instructies per cyclus ingeladen kunnen worden, en moet er ook meer dan 1 instructie per cyclus door de vervolgtrappen kunnen verwerkt worden. Een eerste stap is om per cyclus meer dan 1 instructie in te laden. Concreet betekent dit voor het geval van de dia dat niet 32 bit maar 64 bit per keer moet ingelezen en verwerkt worden. Soms kunnen er randvoorwaarden opgelegd worden aan het soort van instructies dat gecombineerd kan worden (b.v. een integer en een floating point operatie). Bij moderne superscalaire architecturen komen deze beperkingen niet meer voor. Vervolgens zullen ook de andere trappen van de processen meer dan één instructie per cyclus moeten uitvoeren. Hierbij moet men er uiteraard op toezien dat de sequentiële semantiek van het programma niet verloren gaat. De processor zal met andere woorden steeds rekening moeten houden met echte afhankelijkheden. Anti-afhankelijkheden (zie volgende dia) kunnen weggewerkt worden door het resultaat van instructies tijdelijk op een andere plaats bij te houden en het pas weg te schrijven in het registerbestand nadat alle voorgaande instructies afgewerkt zijn. F D E M W F D E M W
Soorten Afhankelijkheden RAW: read after write: afhankelijkheid WAR: write after read: anti-afhankelijkheid WAW: write after write: anti-afhankelijkheid RAR: read after read: geen afhankelijkheid Wanneer 2 opeenvolgende of nabije instructies hetzelfde object lezen of schrijven, ontstaat er een afhankelijkheid. Deze bestaat in 4 soorten, afhankelijk van de normale uitwerking: RAW (read after write): het object wordt normaal eerst geschreven, dan gelezen. Dit is een echte afhankelijkheid. De leesoperatie moet wachten op de schrijfoperatie. WAR (write after read): het object wordt normaal eerst gelezen, dan geschreven. Dit is een anti-afhankelijkheid. De schrijfoperatie moet wachten tot na de leesoperatie, maar zou zijn resultaat ook elders kunnen wegschrijven en op deze manier het wachten kunnen vermijden. WAW (write after write): het object wordt 2 maal geschreven. Dit is een anti-afhankelijkheid. De tweede schrijfoperatie mag niet gebeuren vóór de eerste schrijfoperatie, maar zou zijn resultaat ook elders kunnen wegschrijven en op deze manier het wachten kunnen vermijden. RAR (read after read): het object wordt 2 maal gelezen. In dit geval is er eigenlijk geen afhankelijkheid. De leesoperaties mogen in een willekeurige volgorde uitgevoerd worden zonder het resultaat van het programma te wijzigen.
Superscalaire uitvoering Instructie-venster Fetch & Decode Commit Commitbreedte Fetchbreedte Issuebreedte E E E E Bij een superscalaire architectuur worden er asynchroon instructies ingeladen, gedecodeerd en opgeslagen in een instructievenster. Daar wachten de instructies totdat al hun argumenten beschikbaar worden om dan uitgevoerd te worden op één van de functionele eenheden. Deze uitvoering hoeft niet in de volgorde van voorkomen in de instructiestroom te zijn – maar houdt enkel rekening met de beschikbaarheid van de argumenten. Na uitvoering verhuizen de instructies dan naar de commit trap waar ze terug in volgorde de processor verlaten na hun waarden geproduceerd te hebben in de registers en de caches. Op die manier kan men ervoor zorgen dat onafhankelijke instructies parallel uitgevoerd kunnen worden, terwijl de neveneffecten van de instructies toch in de goede volgorde tot stand komen.
VLIW: Very Long Instruction Word processors Elke instructie bevat een aantal operaties die gegarandeerd parallel kunnen uitgevoerd worden (evtl. nop). F D E WB F D E WB Een andere manier om de functionele eenheden beter te benutten is om de hulp van de compiler in te roepen, en de complete hardware-machinerie achterwege te laten. Een instructie bestaat in dit geval uit een aantal (b.v. 3-5) operaties die allemaal simultaan moeten kunnen uitgevoerd worden. De processor leest een instructie in en stuurt de operaties direct naar de betrokken functionele eenheden (in order). Vaak zal processor er zelfs van uitgaan dat de compiler nagegaan heeft op welk ogenblik de resultaten van vorige instructie beschikbaar zullen komen in de registers, en neemt hij gewoon de waarde die zich op dat ogenblik in de registers bevindt. In dit geval wordt er dus een grote verantwoordelijkheid bij de compiler gelegd. Verder is het ook zo dat VLIW code vaak niet overdraagbaar is tussen twee modellen van dezelfde processor. Kleine verschillen in de latentie van instructies kan ervoor zorgen het programma niet langer correct uitvoert. De Philips Trimedia heeft 5 operaties per instructies (die vaak nop-operaties zijn), en een delay slot van 3 instructies.
EPIC: Explicitly Parallel Instruction Computing Instruction bundle Operatie 1 Operatie 2 Operatie 3 Temp 41 bits 41 bits 41 bits 5 bits Template bepaalt welke instructies er parallel kunnen uitgevoerd worden. De Itanium-processor van Intel is ook een VLIW-achtige. Intel spreekt echter liever van EPIC (Explicitly Parallel Instruction Computing). Een EPIC instructie staat uit drie operaties waarvan het onderlinge parallellisme aangegeven wordt in een zgn template. Dit zorgt ervoor dat er nu heel wat minder NOP-operaties nodig zijn om de instructie te vervolledigen. In de template kan men aangeven welke instructies er parallel mogen uitgevoerd worden, en dewelke niet. Daarnaast bevat de EPIC ook nog heel wat andere concepten om de uitvoering te versnellen (b.v. predikaten die toelaten om operaties conditioneel uit te voeren en op die manier sprongen te vermijden, en een zeer groot aantal registers).
Pauze