Gyorsítótárak
Processzor megnevezése | AMD K7 | AMD K8 | AMD K10 | Intel Merom | Intel Penryn |
L1 cache | 64 kB adat 64 kB utasítás (2 utas, 64 byte line hossz) | 32 kB adat 32 kB utasítás (8 utas, 64 byte line hossz) | |||
L1I cache szélessége | 128 bit | 256 bit | ? bit | ||
L1D cache szélessége | 2 x 64 bit load 1 x 64 bit store | 2 x 128 bit load 2 x 64 bit store | 1 x 128 bit load 1 x 128 bit store | ||
L2 cache | 256–512 kB (16 utas; 128 bit; 64 byte line hossz) | 512–1024 kB (16 utas; 128 bit; 64 byte line hossz) | 512 kB (16 utas; 256 bit; 64 byte line hossz) | 4 MB megosztott (16 utas; 256 bit; 64 byte line hossz) | 6 MB megosztott (24 utas; 256 bit; 64 byte line hossz) |
L3 cache | nincs | 2 MB (32 utas; 128 bit) | nincs |
Tesztünk első fejezetében tehát a gyorsítótárrakkal foglalkozunk, vagyis az L1, azaz elsőszintű és L2, azaz másodszintű cache-ekkel. Az L1 cache-ről tudvalevő, hogy a regiszterek után a leggyorsabb átmeneti tároló, amivel a processzor dolgozhat. Napjainkban a processzor órajelén fut, mérete pedig igen pici, az AMD esetében 2 x 64 kB, a Core CPU-kban pedig 2 x 32 kB. Nem minden a méret, a gyorsítótárak feltérképezése során szót kell ejteni az asszociativitásról is. Az AMD 2 utas, míg az Intel 8 utas csoportasszociatív L1-es gyorsítótárakat alkalmaz. Mit is jelent ez?
Az n-utas csoportasszociatív gyorsítótárak esetében a cache set-ekre (nevezzük őket blokkokra) van osztva, ezek a blokkok pedig n darab cache-vonalat (nevezzük őket celláknak) tartalmaznak. Egy kis számolás után adott számú memóriablokkhoz hozzárendelődik egy cache-blokk, így az adott memóriablokkból n darab cím tárolható el a cache-blokkban.
Vegyük alapul az AMD processzorokat, 64 bájtos cache-szervezés esetén (az AMD és az Intel is 64 bájt méretű cache-cellákkal dolgozik) a 64 kB méretű L1 cache 1024 darab cache-cellára oszlik ([64 x 1024 bájt] / 64 bájt cellaméret). Maradva a példánknál, ha 2 GB rendszermemóriánk van, akkor azt az AMD processzorok 512 darab 4 MB-os blokkra osztják fel (2048(MB memória)/1024(db cella)x2 (utas)=4), majd minden egyes memóriablokkhoz hozzárendelődik egy cache-blokk, ami n-utas, esetünkben kétutas, tehát a 4 MB-os blokkok megcímzése a processzorcache-ben kétfelé oszlik. És most jön a lényeg. Amikor a processzornak szüksége van egy memóriában található adatra, a cache-vezérlés betölt egy sort (64 bájt) a memóriából a hozzárendelt cache-blokkba, azon belül az egyik cellába, így amikor a CPU-nak később is szüksége lesz erre vagy egy pár bájttal később megtalálható adatra (64 bájton belül maradva), már nem kell a memóriához nyúlnia, hiszen az megtalálható lesz a sokkal gyorsabb cache-ben, pontosabban AMD processzorok esetén a blokk egyik cellájában (Core processzoroknál nyolcutas a cache, tehát nyolc helyre lehet elhelyezni ezt az adatot). A tár minél több utas, annál magasabb a találati arány, viszont annál lassabb benne a keresés. Két eset lehetséges. Az egyik, amikor a rendszermemória adott blokkjából kiolvasunk egy adatot, az ehhez rendelt cache-blokk legutoljára feltöltött (LIFO) vagy legrégebben használt (FIFO) cellája átkerül a cache-hierarchia következő elemébe, helyére pedig az újonnan bejövő adatok kerülnek. A másik, amikor a cache a használatba vételek arányában szortírozza az adatokat (L[east] R[ecently] U[sed]). Ha kétutas a cache, akkor az adott blokkból minden második betöltés az egyik cache-cella felülírását eredményezi, márpedig ha sűrűn kell ugrándozni a memóriában mondjuk három egymáshoz közel, de 64 bájtnál távolabb elhelyezkedő memóriacím között (például ezerszer lefutó ciklus esetén), akkor ez nem igazán optimális. A Core processzorokban nyolcutas csoportasszociatív L1 cache található, ami egyrészt azt jelenti, hogy az adott blokkon belül csak minden nyolcadik memóriabetöltés igényli a 64 bájtos cella felülírását, ugyanakkor viszont a keresési idő a legrosszabb esetben akár négyszeresére is nőhet, ha a 2-utas megoldáshoz hasonlítjuk.
Kicsit elkalandoztunk a témától, ugyanis a n-utas csoportasszociativitással együtt járó különbségeket pont hogy nem mértük le, de azért érdemes felfrissíteni ismereteinket. Számunkra most először is az L1D cache sebessége fontos, amit a gyártók szépen fel is szoktak tüntetni a dokumentációkban. Lássuk, itt mi történt az elmúlt években. Az AMD Athlon processzorok (K7) órajelenként két 64 bites olvasásra és/vagy egy 64 bites írásra képesek. Talán hihetetlen, de ezt a konstrukciót az Athlon 64 is megörökölte, napjainkra már nem ez a leggyorsabb megoldás, korábbi Athlon 64-es tesztjeinkben nyilvánvalóvá is vált, hogy ez a keskeny útvonal olvasásnál és írásnál is visszafogja a processzort. Akkor vált láthatóvá, amikor az órajel emelésével együtt nőtt a memóriaolvasás/írás sebessége is (lásd például itt). A K10-ben az olvasás és az írás is duplájára gyorsult, de eltérő módon. Az olvasások szélessége megduplázódott, tehát a K10 órajelenként 2 x 128 bites olvasásra képes. Ezzel szemben az írás szélessége nem változott, viszont immár két port képes írni, igaz, ezek még mindig csak 64 bit szélesek, ezzel együtt jár, hogy a 128 bites utasításokat a K10 kétszer 64 bites formában tárolja el. Az Intel processzorok másképpen működnek, már a P6 óta két egymástól független olvasó és író port van, a Core processzorokban ezek 128 bit szélesek.
Az AMD a másodszintű gyorsítótár méretére a K8 megjelenése óta nem fektet túl nagy hangsúlyt. A K7 processzorokban 256–512 kB található (akkoriban még a magméret, azaz a gyártástechnológia korlátozta a gyártót), az Athlon 64-ben maximum 1 MB a mérete, a K10-ben pedig megelégedtek az 512 kB-tal. Ezzel szemben az Intel már a Pentiumok L2-es gyorsítótárát is szerette növelni, és ez még inkább igaz a Core processzorokra, a Merom 4 MB, a Penryn pedig 6 MB másodszintű gyorsítótárral rendelkezik, duplamagonként. Az AMD azért nem növeli meg jobban az L2 cache méretét, mert az integrált memóriavezérlő (amelyről később még szó esik) gyorsan hozzáfér a memóriához, így a cache által biztosított gyorsabb adatelérés (alacsonyabb késleltetés/várakoztatás) nem igazán mutatkozik meg a mindennapi használatban, ezt láthattuk is K8-as elemzéseinkben. Az Intel ezzel szemben szeret az L2 cache-re támaszkodni, mert a processzor csak a lassú rendszerbuszon keresztül éri el a rendszermemóriát, ezért a cache méretének növelése szignifikáns gyorsulással jár együtt.
Táblázatunkból kiolvasható, hogy az AMD a K10 esetében egy 2 MB méretű harmadszintű gyorsítótárat is alkalmazott. Mit érdemes erről tudni? Az L3 cache egészen mostanáig egyfajta luxust jelentett, gyakorlatilag csak szerverprocesszorok esetében láthattunk példát az alkalmazására. Miért? Azért, mert a cache kialakítása drága, fajlagosan sokkal drágább, mint az egyszerű alaplapba passzintható memóriamodulok. Az AMD a K10 esetében azért döntött az L3 cache használata mellett, mert a K10 úgynevezett natív négymagos processzor, egyetlen lapkán találunk négy központi egységet, ez a harmadszintű gyorsítótár pedig úgy készült, hogy mind a négy mag hozzáférhessen, gyakorlatilag összekösse őket. A megoldásnak vannak előnyei és hátrányai is. Az előnyök között lehet felsorolni, amikor több szálon futó (tehát több processzormagot megdolgoztató) alkalmazások arra kényszerítik az egyes központi egységeket, hogy ugyanazon adatokkal dolgozzanak, ilyenkor az adatokat elég egyszer eltárolni (az L3 cache-ben), az összes processzormag ugyanolyan sebességgel fér hozzájuk. Gondoljunk bele, az Intel négymagosa ezzel szemben két darab 4–6 MB méretű gyorsítótárat alkalmaz (kétmagonként egyet); ha az egyik processzorpár (egyik elemének) szüksége van a másik pár gyorsítótárában megtalálható adatra, akkor azt kénytelen a rendszerbuszon keresztül lekérni, ami rengeteg ciklusnyi időkiesést jelent. Kérdés viszont, hogy ez mennyire ütközik ki egy átlagos felhasználói környezetben? Valószínűleg nem túlságosan, hiszen még nagyon kevés az olyan program, mely egyszerre kettőnél több szálon képes dolgozni és sok memóriát is igényel.
Ugyanakkor vannak hátrányai is. Egyik hátránya, hogy az L3 cache relatíve lassú. Méretéből és kialakításából kifolyólag csak lassabb elérésű memóriacellákból épülhet fel, összehasonlításul a K10 L1 cache 3 ciklusnyi, az L2 cache 9 ciklusnyi, az L3 pedig legalább 20 ciklusnyi késleltetésű. A második probléma, hogy sokkal bonyolultabb cache-koherenciakezelő logikára van szükség az adatfüggőségek kezelésére, amikor már 3-4 mag dolgozik egyszerre. Összességében tehát az L3 alkalmazásának előnyei és hátrányai arányban állnak egymással, ami ez esetben nem túl pozitív kicsengésű, hiszen jobb lenne, ha az előnyök felé billenne a mérleg.
Lássuk, hogy az egyes generációk gyorsítótárai milyen sebességgel rendelkeznek. A tesztek 2 GHz-es órajelen születtek 10 x 200 MHz-es beállítás mellett.
Először az L1D cache sebességére voltunk kíváncsiak, az eredmények egyértelműek. A K7 és a K8 egy kis különbséget leszámítva ugyanúgy teljesített, 2 GHz-es órajelen az elérhető maximális olvasási sebesség 32 000 MB/s, ez stimmel is (ciklusonként 2 x 64 bit). Az írás csak 1 x 64 bit széles, így az elérhető maximum 16 000 MB/s, ez is stimmel (az Athlon 64-ünk 2003 MHz-en járt, itt pedig 16 024 MB/s). A másolás egy igencsak becsapós téma. Az Everest készítőivel konzultálva sikerült kideríteni, hogy minek köszönhető az olvasásnál alacsonyabb, de az írásnál magasabb érték. Az Everest Copy az L1D cache méretének felét olvassa ki és írja vissza, amiben pontosan az a jó, hogy így a teljes copy rutin az L1D cache adataival dolgozik, és kibukik, ha függetlenek a load/store portok. Mivel minden az L1D-n belül történik, ennek nincs köze se a prefetcherekhez, se a memory disambiguationhöz. Ha a portok függetlenek, akkor a portok olvasási és írási sebessége összeadódik. Ha nem függetlenek, akkor az kiütközik. A K7/K8-ak egyik portja képes a 64 bites olvasásra, míg a másik port egyidejűleg tud írni és olvasni is. A másolás során összeadódik az egyidejű olvasási és írási sebesség (64 bit + 64 bit), így a másolás sávszélessége nagyobb az olvasásnál, de nem duplája az írásnak egyfajta cache-megvalósításbeli jellemző miatt. A K10 eredményei egyértelműbbek, az új architektúra 2 x 128 bit olvasására és 2 x 64 bit írására képes órajelenként, ennek megfelelőek az adatok. A másolást korlátozza a 2 x 64 bites írás sebessége, ezért a K10 itt ugyanolyan gyors, mint írásban. A Core processzorokban két 128 bites port van, ezek egymástól teljesen függetlenül működnek. Ez jól is látszik, az olvasás és az írás ugyanolyan gyors, míg a másolás során összeadódik a két port sebessége.
A másodszintű gyorsítótár sebességének leméréséhez ugyanúgy 2 GHz-es órajelet alkalmaztunk. Itt már kicsit bonyolultabb a téma, mert eltérő késleltetéssel eltérő sebességűek a gyorsítótárak. Az L1 esetében ez nem volt probléma, mert az összes L1-es cache késleltetése ugyanolyan mértékű volt, de az L2-nél ez már többé nem igaz. Ami jól látható, az az, hogy a K7 és a K8 itt is közel ugyanolyan gyors, a K8 picit lassabb, mert a cache elérési ideje hosszabb (Brisbane-t teszteltünk). A K10 már egy teljesen felújított architektúra ebből a szempontból is, az L2 cache elérése 256 bitre szélesedett (bár hallottunk 128 bites pletykákat is), ráadásul késleltetési ideje is csökkent, így a K8-hoz képest a gyorsulás olvasásban 2,5-szeres, írásban 2-szeres, másolásban pedig szintén majdnem annyi, mint olvasásban. A Merom és a Penryn a K10-hez hasonlóan szerepelt, de a nagy, 4–6 MB méretű gyorsítótárak elérési ideje hosszabb, mint a K10-é, és valószínűleg az L2 feltöltését az L1 sebessége is meghatározza, így olvasásban lassabbak annál, írásban és másolásban viszont gyorsabbak.
A késleltetési időket ábrázoló grafikon beszédes, az L1-es cache-ek elérési ideje minden processzornál azonos, 1,5 ns volt. A gyártók minden esetben 3 ciklust specifikáltak, tehát az Everest jól mért. A K7-es másodszintű gyorsítótára fél nanoszekundummal gyorsabb a K8-énál, viszont a K10 nagyot lépett előre, esetében 35%-kal kisebb késleltetésről beszélhetünk. A Merom és Penryn viszonya is érdekes, bár a Penryn jóval nagyobb L2-es cache-sel rendelkezik, késleltetése is magasabb lett.
Bevetettük a közkedvelt Sciencemarkot is, amivel szintén figyelemreméltó eredményeket kaptunk. Nem tudjuk, hogy a program pontosan milyen módon teszteli a processzorokat (nem 100%-ig biztos információink vannak arra vonatkozólag, hogy másolást [is] mér), de ami biztos, hogy elavultabb technikákkal, mint az Everest, hiszen már két éve nem nyúlt hozzá programozó, így az SSE3-nál újabb utasításkészleteket nem is támogatja. A Sciencemark különbséget mért ki a K7 és a K8 L1-es gyorsítótára között is, a K10 nem gyorsult kétszeresére a K8-hoz képest, és szépen lemaradt a Core architektúrára épülő processzoroktól. Arra tudunk gondolni, hogy valóban közrejátszhat a másolási sebesség, és itt az L1I is szerepet játszhat (+prefetch), másképpen nem lehet gyorsabb a Merom és a Penryn. Az L2 cache méréseknél már nem volt különbség a K7 és a K8 között, viszont ebben a K10-en a K8 dupláját mértük, az Intel CPU-i pedig még gyorsabbak voltak, de azonos sebességűek, ami már csak az elérési idők miatt is kétséges. Összegezve inkább az Everestnek hiszünk, abban logikus eredményeket kaptunk.
Everest benchmarkok | Olvasás (MB/s) | Írás (MB/s) | Másolás (MB/s) | Késleltetés (ns) |
AMD K10 L2 cache (2 GHz) | 16 015 | 11 412 | 14 865 | 4,6 |
AMD K10 L3 cache (1,8 GHz) | 7478 | 7131 | 9168 | 9,1 |
AMD K10 L3 cache (2,2 GHz) | 7558 | 8303 | 10 854 | 8,2 |
AMD K10 memória (unganged mód - 2,2 GHz) | 7531 | 5382 | 8286 | 59,3 |
Utolsóként a K10-en található L3-as gyorsítótárat vetettük össze a K10 memóriaelérésével, a táblázatból jól látszik, hogy miért. Az L3 olvasása semmivel sem gyorsabb, mint a memória olvasása, írásban már van 32% különbség, viszont másolásban megint csak 10%-ot mértünk ki. Az egyetlen komoly differenciát a késleltetés mutatta, a cache-hez természetesen sokkal gyorsabban férünk hozzá, mint a memóriához. Ha tehát csak a sávszélességet vesszük figyelembe, az L3 nem muzsikál túl jól. De ne feledjük el, hogy az L3 praktikus okokból került a processzorba, ez egy olyan tárterület, amit a négy processzormag együttesen használ, és ha olyan adatokra van szükség, amit több mag is igényel, akkor jobban járunk a cache-sel, mint a memóriával.
A cikk még nem ért véget, kérlek, lapozz!