4. NINCS KÉSZ Szuperskalár architektúrák Flashcards
NINCS KÉSZ
Szuperskalár architektúra (mi is ez?)
A futószalag architektúráknál a dekódoló óraciklusonként egy utasítást tudott kibocsátani, ami
korlátozta a teljes CPU sebességét. Amennyiben óraciklusonként több utasítást tudna kibocsátani a
dekódoló, a teljesítmény is nőne. Erre jelentett megoldást a szuperskalár architektúra, ami párhuzamos
kibocsátást alkalmazott. 1990 környéként jelent meg és három generációra osztható. A harmadik
generációban már multimédiás (utasításon belüli párhuzamosság) képességek is megjelentek.
- és 2. generációs szuperskalár architektúrák közös jellemzői
- A dekódoló egységből képes óraciklusonként több utasítást kibocsátani -> ennek mérőszáma a kibocsátási ráta
- Első generáció 2-3 utasítás / ciklus
- Második generációnál 4-6 utasítás / ciklus
- Időbeli és térbeli párhuzamosság: több futószalag párhuzamosan
(KÉP JEGYZETBEN) - Maguk küzdenek meg a függőségekkel: dinamikusan, extra hardverek segítségével
- Például: adattípusonként külön regisztertár
- Kompatibilitás: evolúció a futószalagokhoz képest, tehát kompatibilis volt velük, így régi
programok is futtathatóak maradtak.
Harvard architektúra
Harvard amerikai mérnök 1944-ben dolgozta ki az elvet, melynek lényege, hogy az adat és a programkód
fizikailag elkülönített útvonalakon mozog.
Következménye, hogy párhuzamos adatutakat jönnek létre, az adat párhuzamosan tud mozogni, így
növekszik a teljesítmény. A szuperskalár architektúráknál az L1 cache-nél használtak Harvard
architektúrát, ahol az utasítás és az adat külön tárolódik. Manapság egy módosított Harvard
architektúrát használnak, ami azt jelenti, hogy ezen felül képes programot adatként is betölteni. Mivel
az L2 és L3 gyorsítótárban közösen tárolódnak az utasítások és adatok, látható, hogy a mai processzorok
tervezésénél mind a Harvard, mind a Neumann elveket felhasználják.
Harvard architektúra vezérlési vázlat
A vezérlőegység (CONTROLL) hívja le az utasítást az instruction cache-ből (INSTR adatút), majd ez
alapján jelet küld a data cache-nek, hogy az ALU-ba milyen címen lévő adat kerüljön (CONTROLL &
ADDR). Ezzel egyidőben az instruction cache felé is küld jelet, tehát a következő órajelre az adat és a
következő utasítás egyszerre hívódik le. A vezérlőegység felel az ALU irányításért is. Az ALU az IN és
OUT adatutakon kommunikálhat a perifériákkal, a STATUS adatúton pedig visszacsatolást biztosít a
vezérlőegység számra. Az egész működés órajelre szinkronizált.
(KÉP JEGYZETBEN)
Előnyei:
* Képes párhuzamosan adatot és utasítást olvasni vagy írni cache nélkül is
* Az adat és utasítás tárolók különálló címtartománnyal rendelkeznek, amikben a címek különböző hosszúak is lehetnek (például utasítás címek 32 bit, adat címek 64 bit)
- generációs szuperskalárok
Másnéven keskeny szuperskalárok
A kibocsátási ráta:
* RISC architektúráknál 3 utasítás/ciklus
* CISC-nél 2 utasítás/ciklus
Ez 2-3x-os sebességnövekedés a futószalag elvű processzorokhoz képest.
- generációs szuperskalárok jellemzői
- Közvetlen, vagyis nem pufferelt kibocsátás: a CPU a dekódolt utasítást közvetlenül küldi a végrehajtó egységhez
- Statikus elágazásbecslés, amit a Fetch alrendszer végzett. Kétféleképpen valósult meg:
- Fix elágazás: elágazásnál mindig ugrik
- A programkód bizonyos tulajdonságai alapján hozott létre egy statikus elágazásbecslést
- Kétszintű gyorsítótár a memória lassúságának kiküszöbölésére: L1 cache a processzorlapkán, L2 különálló lapkán
- Különálló adat és utasítás az L1 gyorsítótárban -> Harvard architektúra, L1 elérése Harvard elvű működéssel
- Operatív tár és L2 cache közös az adatok és utasítások számára -> Neumann architektúra, elérésük Neumann elvű működéssel
(1. generációs szuperskalárok)
Közvetlen, nem pufferelt kibocsátás
A CPU a dekódolt utasítást küldi a végrehajtó egységhez. Ehhez új fogalmat vezettek be: utasításablak.
Ez egy olyan puffer, amely az óraciklusonként kibocsátott utasításokat tartalmazza. Az utasításablakaz
utasítás pufferből kerül feltöltésre és utasítás kibocsátáskor kiürül. Itt történik a dekódolás és a függőségellenőrzés. A végrehajtható utasítások kibocsátásra, vagyis egyből a végrehajtó egységbe kerülnek. A végrehajtható utasítás olyan utasítás, aminek nincs függősége. A függőséggel rendelkező utasítások addig maradnak az utasításablakban, amíg a függőség meg nem szűnik.
(KÉP JEGYZETBEN)
Utasításablak működése:
Utasítás pótlás lehetőségei:
- A kibocsátott utasításokat egyenként pótoljuk
- A kibocsátott utasításokat egyszerre pótoljuk (megvárjuk, hogy az összes utasítás kiürül)
Utasítás végrehajtás és kibocsátás lehetőségei:
- Sorrendben
- Sorrenden kívül
Kezdeti megoldás az utasításablak egyszerre történő feltöltése és sorrendi végrehajtás volt. A sorrendi
kibocsátás hátránya, hogy egy függő utasítás a függőség megszűnéséig blokkolja a kibocsátást, így a
végrehajtóegységek kihasználatlanul álltak. Ez volt a legnagyobb probléma az első generációs
szuperskalárokkal.
(1. generációs szuperskalárok)
Végrehajtási modell
A teljes rendszer feldolgozási sebességét az alrendszerek átbocsátási képessége határozza meg. Az
alrendszerek jellege és száma az adott mikroarchitektúrától függ. A végrehajtási modell RISC
architketúra esetén:
- Első rész: feladata az utasítás lehívás és az utasításablak feltöltése
- Utasításablak
- Hátsó rész: feladata az utasításablak kiürítése (dekódolás, függőség ellenőrzése, kibocsátás),
végrehajtás és a visszaírás
(KÉP JEGYZETBEN)
RISC architektúra esetén az adat cache közvetlenül nem írható, csak regisztertárba lehet visszaírni. A
regisztertár és az adat cache közötti adatmozgatást LOAD/STORE utasítások segítségével érhetjük el.
Szélességnek nevezzük az alrendszerek átbocsátási képességét. A teljes rendszer szélességét a
legkeskenyebb alrendszer szélessége határozza meg.
(1. generációs szuperskalárok)
Szűk keresztmetszet
Az első generációs szuperskalároknál a következő szűk keresztmetszetek lépnek fel:
- Kibocsátás: oka a közvetlen kibocsátás, így kezelni nem lehetett, ezért következménye, hogy a
végrehajtás általános célú alkalmazások esetén korlátozódik. Ez maximum 2 utasítás/ciklust
jelentett CISC-nél, RISC-nél pedig 3 utasítás/ciklust. Gyakorlatban viszont körülbelül 1
utasítás/ciklust eredményezett.
- Memória: csökkentése cache bevezetésével
- Elágazásfeldolgozás: csökkentése statikus elágazásbecsléssel. Nem tudták viszont kezelni a
RAW függőségek és az adatfüggőségek által létrehozott szűk keresztmetszetet. Még az ál
függőségek is blokkolnak.
- generációs szuperskalárok jellemzői
Az első generációs szuperskalár CPU-k kibocsátási szűk keresztmetszete miatt az átbocsátóképesség
növeléséhez át kellett tervezni az architektúrát. Így születtek meg a második generációs szuperskalár
processzorok.
Kibocsátási rátájuk körülbelül 4 utasítás/ciklus RISC és 3 utasítás/ciklus CISC architektúrák esetén,
tehát az első generációhoz képest jelentős teljesítménynövekedés történt.
Ilyen processzorok voltak például:
- Intel Pentium Pro
- AMD K6
- PowerPC 604
(2. generációs szuperskalárok)
Feltételei
Egy CPU-t akkor tekinthetünk második generációs szuperskalárnak, ha jellemző rá:
- Dinamikus utasítás ütemezés (a)
- Regiszter átnevezés (b) -> (a-b) kiküszöbölték a közvetlen kibocsátási szűk keresztmetszetet
- Elágazások előrejelzése dinamikus előrejelzéssel (c) ugrástörténet figyelembevételével (ez
körülbelül 90-95%-os pontosságot biztosított)
- Kifinomult és kibővített gyorsítótár alrendszer
- Sorrenden kívüli kiküldés (d)
(2. generációs szuperskalárok feltételei)
Dinamikus elágazásbecslés
(c) Az leágazások történetét történet bitek formájában írja le. A dinamikus becslés lehet 1, 2 vagy 3
bites:
1 bites: a történet bit értéke lehet 0 vagy 1 attól függően, hogy előző elágazásnál ugrás vagy soros
folytatás történt. A következő elágazásnál a történet bit alapján döntötte el a CPU, hogy ugrás vagy
soros végrehajtás következik.
2 bites: a történet biteket 2 bittel ábrázoljuk.
- 11 – határozott elágazás: általában kezdeti állapot, ekkor mindenképpen ugrik
- 10 – gyenge elágazás
- 01 – gyenge soros folytatás
- 00 – határozott soros folytatás
Mivel legtöbbször az elágazásnál ugrás történik, ezért a történet bitek értéke kezdetben 11. Amennyiben
a következő elágazásnál mégis hibás volt az ugrás, a történeti bitek értéke 10-ra változott, tehát ezt
követi alkalommal megint meg fogja próbálni az ugrást. Ha harmadszorra is hibás volt az ugrás, átkerül
01 állapotba.
(2. generációs szuperskalárok feltételei)
Dinamikus utasítás ütemezés
(a) Másnéven várakoztatás vagy pufferelt utasításkibocsátás. Lényege, hogy az utasítások kibocsátása
pufferelt, sorrendi módon történik, a kiküldés viszont sorrenden kívüli. Ez jelentősen megnöveli a
mikroarchitektúra elejének átbocsátóképességét, valamint kiküszöböli a kibocsátási szűk
keresztmetszetet.
(2. generációs szuperskalárok feltételei)
Sorrenden kívüli kiküldés
(d) A második generációs szuperskalároknál kibocsátáskor nincs függőségvizsgálat, ezért a lehívás, a
dekódolás és a kibocsátás nominális rátával működhet, ami ebben az időben általában 3-4 utasítás/ciklus
volt. Az utasítások kibocsátáskor a kibocsátási pufferbe kerülnek, ez a várakoztató állomás. A kibocsátási
puffer lehet közös is, de előfordulhat, hogy különböző típusú utasításoknak (FX, FP stb.) külön pufferek
vannak fenntartva. A kibocsátási puffernek köszönhetően a vezérlő óraciklusonként akár több tucat
utasítás közül is választhat, hogy mit küldjön ki végrehajtásra. A döntés az állapot bitek alapján történik,
a vezérlő ezek segítségével dönti el az utasításokról, hogy azok függők vagy függetlenek. A CPU a
független utasításokat küldi ki végrehajtásra.
Ebben az esetben a várakoztató állomás mentén beszélhetünk első és hátsó részről.
(KÉP JEGYZETBEN)
(2. generációs szuperskalárok feltételei)
Regiszter átnevezés
A dinamikus utasítás ütemezés ugyan növeli az átbocsátóképességet, viszont a függő utasításokat nem
küszöböli ki, azok továbbra is lassítják a végrehajtást. Erre jelent megoldást a regiszter átnevezés, ami
kiküszöböli az ál adatfüggőségeket. A WAR és WAW függőségeket még a kibocsátás előtt megszünteti
(még mielőtt a várakoztató állomásba kerülnek).
A gyakorlatban ennek eléréséhez a CPU minden regiszterhez allokál egy átnevezési (piszkozat) regisztert.
Ilyenkor az átnevezési logika követi az aktuális regiszter allokációkat, átnevezik a forrás regisztereket is,
így az architektúrális regisztereket elég csak visszaíráskor figyelembe venni. Az allokációt a CPU az
utasításokhoz, és nem az architektúrális regiszterekhez köti. A forrás operandus megfelelő helyről való
beolvasását a forrás regiszter átnevezés biztosítja. Ha megszűnik a függőség, az utasítás végrehajtásra
kerül és az eredmény visszaíródik az architektúrális regiszterben, majd az átnevezési regiszterek
felszabadítása következik. Ez a megoldás dinamikus elágazásbecslés számára is előnyös, mivel, ha kiderül,
hogy a program mégsem azon az ágon folytatódik, amihez az adott utasítást végrehajtottuk, az eredmény
még csak a piszkozat regiszterben van jelen, ahonnan könnyen törölhető.