Memoria cache a procesorului
Cache- ul CPU este memoria cache utilizată de CPU -ul unui computer pentru a reduce timpul mediu de acces la memorie [1] . Este un tip de memorie mic, dar foarte rapid, care păstrează copii ale datelor care sunt accesate cel mai frecvent în memoria principală . Acesta face parte din procesor și este situat foarte aproape de acesta. Nu este vizibil de software , dar este controlat și gestionat de hardware . Acesta este inclus în telefoane inteligente și tablete și poate fi văzut direct din software.
Caracteristici
Diagrama din stânga arată două memorii, principala și memoria cache. Fiecare locație de memorie cache conține date (o linie cache ), care între diferitele tipuri de cache variază între 512 octeți și dimensiunea de 8 MB a locației memoriei cache este în mod normal mai mică decât cea a memoriei normale, care variază de obicei între 1 și 16 GB . Fiecare locație de memorie are un index, care este un identificator unic folosit pentru a face referire la acea locație specifică. Indexul unei locații din memoria principală se numește adresă de memorie. Fiecare locație cache are, de asemenea, o etichetă care conține indexul memoriei principale al datelor încărcate acolo. În cache-urile de date, aceste valori sunt numite blocuri cache sau linii cache. Atâta timp cât majoritatea acceselor la memorie sunt pentru date stocate în cache, latența medie de acces la memorie va fi mai apropiată de latența cache decât memoria principală, astfel încât performanța va fi mai bună.
Când procesorul trebuie să citească sau să scrie într-o anumită locație din memoria principală, inițial verifică dacă conținutul acestei locații este încărcat în cache. Acest lucru se face prin compararea adresei locației de memorie cu orice etichete din cache care ar putea conține date la adresa respectivă. Dacă procesorul constată că locația memoriei este în cache, se numește o lovitură de cache, altfel o pierdere de cache. În cazul unei lovituri de cache, procesorul citește sau scrie imediat datele în linia cache. Raportul dintre accesările cache și numărul total de accesări se mai numește și rata de accesare și este o măsură indirectă a eficacității algoritmului de cache.
În cazul unei erori de cache, urmează (pentru majoritatea cache-urilor) crearea unei noi entități, care include eticheta tocmai solicitată de procesor și o copie a datelor din memoria principală. O astfel de defecțiune este relativ lentă, deoarece necesită transferul datelor din memoria principală, în unele cazuri după ce s-au șters datele care nu mai sunt valabile.
Acesta este motivul pentru care un cache foarte mare, chiar dacă este gestionat cu un algoritm eficient, poate fi contraproductiv din punct de vedere al performanței în anumite circumstanțe. De fapt, procesul de ștergere a datelor expirate și invalide din cache și de încărcare a datelor corecte în cache durează de obicei mai mult decât atunci când CPU citește datele direct din memoria principală fără a utiliza memoria cache. Cu alte cuvinte, un cache mare poate duce, în situații de calcul specifice, de exemplu cele non-iterative, la un număr mai mare de erori de cache decât hit-uri cache, cu o degradare semnificativă a performanței.
Câteva detalii operaționale
Pentru a face loc pentru date noi în cazul unei pierderi de memorie cache , memoria cache trebuie, în general, să ștergă conținutul uneia dintre linii. Euristica pe care o folosește pentru a alege datele de șters se numește politică de înlocuire. Problema fundamentală cu orice politică de înlocuire este necesitatea de a prezice datele din cache care vor fi mai puțin probabil să fie solicitate în viitor.
Prezicerea viitorului este dificilă, mai ales pentru cache-urile hardware care trebuie să exploateze reguli care pot fi ușor implementate în circuite, așa că există o serie de politici de înlocuire și niciuna dintre ele nu poate fi considerată perfectă. Unul dintre cele mai populare, LRU (din engleza Least Recently Used , care este folosit mai puțin recent ), înlocuiește, de fapt, datele accesate mai puțin recent.
Când datele sunt scrise în cache, acestea trebuie încă scrise în memoria principală după ceva timp . Decizia când ar trebui să aibă loc această scriere este controlată de politica de scriere. Într -un cache de scriere , fiecare scriere în cache are ca rezultat o scriere simultană în memoria principală. Alternativ, un cache de scriere înapoi nu efectuează imediat această acțiune: dimpotrivă, memoria cache ține evidența liniilor care conțin date care trebuie actualizate prin setarea adecvată a ceea ce se numește bitul murdar . Datele sunt de fapt scrise în memorie doar atunci când trebuie să fie șterse din cache pentru a face loc pentru noi informații. Din acest motiv, o căutare eșuată într-un cache de scriere înapoi generează adesea două accesări la memorie: una pentru a citi noile date, cealaltă pentru a scrie informațiile vechi (dacă este indicată de bitul murdar). Atât write-back, cât și write-through servesc la menținerea coerenței între nivelurile de memorie.
Există și câteva politici intermediare. De exemplu, memoria cache ar putea fi scrisă, dar scrierile ar putea fi puse temporar în coadă, astfel încât să proceseze mai multe scrieri împreună, optimizând accesul la magistrală .
Datele din memoria principală, a căror copie există în cache, ar putea fi modificate din alte cauze (eveniment deloc puțin probabil, de exemplu, într-un sistem multiprocesor ), prin urmare datele din cache ar putea deveni învechite. Protocoalele de comunicare între sistemele de management al memoriei cache care mențin consistența datelor sunt numite protocoale de consistență.
Timpul necesar citirii datelor din memorie (latența de citire) este important, deoarece de multe ori un CPU își poate finaliza coada de operații în timp ce așteaptă sosirea datelor solicitate. Când un microprocesor ajunge în această stare, se numește o oprire a procesorului. Pe măsură ce microprocesoarele accelerează, blocarea pentru cache miss irosește multă putere de calcul; CPU-urile moderne, de fapt, pot executa sute de instrucțiuni în același timp necesar pentru a încărca o singură bucată de date din memorie. Prin urmare, au fost studiate diverse tehnici pentru a „ține CPU-ul ocupat” în această fază. Unele microprocesoare, precum Pentium Pro , încearcă să efectueze operațiunile care urmează pe cea care așteaptă datele, dacă sunt independente de aceasta (din acest motiv sunt numite out-of-order în engleză ). Pentium 4 folosește simultan multithreading (numit HyperThreading în terminologia Intel ), care permite unui alt program să folosească procesorul în timp ce un prim program așteaptă sosirea datelor din memoria principală.
Asociativitate
Politica de înlocuire decide unde se poate afla în cache o copie a unei anumite locații de memorie. Dacă politica de înlocuire este liberă să aleagă în ce linie de cache să încarce datele, memoria cache este numită complet asociativă (sau chiar complet asociativă). Pe de altă parte, dacă orice date din memorie pot fi plasate doar într-o anumită linie de cache, se numește mapare directă (sau chiar mapare directă). Cu toate acestea, majoritatea cache-urilor implementează un compromis numit set asociativ (sau chiar parțial asociativ). De exemplu, memoria cache de date AMD Athlon de nivel 1 este asociată în două căi , adică o anumită locație de memorie poate fi stocată în cache în două locații distincte din memoria cache de date de nivel 1.
Dacă fiecare locație din memoria principală poate fi încărcată în două locații diferite, se pune întrebarea: care? Schema folosită cel mai frecvent este prezentată în diagrama din lateral: biții mai puțin semnificativi ai indexului locației de memorie sunt utilizați ca indici pentru cache și două linii de cache sunt asociate fiecăruia dintre acești indici. O proprietate bună a acestei scheme este că etichetele datelor încărcate în cache nu trebuie să includă acea parte a indexului deja codificată de linia de cache aleasă. Deoarece etichetele sunt exprimate pe mai puțini biți, ele ocupă mai puțină memorie și timpul de procesare a acestora este mai mic.
Au fost sugerate și alte scheme, cum ar fi cache-ul skewed , unde indexul modului 0 este direct, ca mai sus, în timp ce indicele modului 1 este calculat printr-o funcție hash. O funcție hash bună are proprietatea care abordează conflictul cu maparea directă nu se ciocnește atunci când este mapată la funcția hash, astfel încât un program este mai puțin probabil să sufere de un număr imprevizibil de mare de coliziuni din cauza unei funcții hash. acces. Dezavantajul este întârzierea suplimentară necesară pentru a calcula rezultatul funcției hash. În plus, atunci când devine necesar să încărcați o linie nouă și să ștergeți una veche, poate fi dificil să determinați care dintre liniile existente a fost folosită cel mai puțin recent, deoarece linia nouă intră în conflict cu diferite „seturi” de linii pentru fiecare „ cale"; de fapt, trasarea LRU este calculată în mod normal pentru fiecare set de linii.
Asociativitatea este un compromis. Dacă există zece poziții, politica de înlocuire poate umple o nouă linie, dar atunci când căutați date trebuie verificate toate cele 10 poziții. Controlul mai multor poziții necesită mai multă putere, zonă și timp. Pe de altă parte, cache-urile cu mai multă asociativitate suferă de mai puține erori de cache (vezi și mai jos). Regula generală este că dublarea asociativității are aproximativ același efect asupra ratei de accesare ca și dublarea dimensiunii cache-ului, de la 1-way ( direct mapping ) la 4-way. Creșterile asociativității dincolo de 4 direcții au un efect mult mai puțin asupra ratei de accesare și sunt utilizate în general din alte motive (vezi aliasarea virtuală, mai jos).
Unul dintre avantajele cache-ului mapat direct este că permite o execuție speculativă rapidă și ușoară . Odată ce adresa a fost calculată, se știe ce linie de cache ar putea conține datele. Acesta poate fi citit și procesorul poate continua să lucreze cu acele date înainte de a termina de verificat dacă eticheta se potrivește de fapt cu adresa solicitată.
Ideea că procesorul folosește datele din cache chiar înainte ca corespondența dintre etichetă și adresă să fie verificată poate fi aplicată și la cache-urile asociative. Un subset al etichetei, numit indiciu în engleză , poate fi folosit pentru a alege temporar una dintre liniile de cache asociate cu adresa solicitată. Aceste date pot fi folosite de CPU în paralel, în timp ce eticheta este complet verificată. Această tehnică funcționează cel mai bine atunci când este utilizată în contextul traducerii adreselor, așa cum se explică mai jos.
Cache miss
Cache miss se referă la o încercare eșuată de a citi sau scrie o bucată de date în cache, ceea ce are ca rezultat o latență mult mai mare în accesarea memoriei principale. Pentru o eroare de citire din memoria cache a instrucțiunilor, procesorul trebuie să aștepte (se blochează ) până când instrucțiunea este încărcată din memoria principală. O defecțiune a cache-ului cauzată de încărcarea datelor poate fi mai puțin dureroasă, deoarece alte instrucțiuni care nu au legătură cu aceasta pot fi încă executate, atâta timp cât operația care necesită încărcarea datelor poate fi efectuată. Cu toate acestea, datele sunt adesea folosite imediat după instrucțiunea de încărcare. Ultimul caz de pierdere a memoriei cache , adică un eșec de scriere, este cel mai puțin îngrijorător, deoarece scrierea este de obicei tamponată. Procesorul poate continua în siguranță până când tamponul este plin. (Nu există nicio eșec la scrierea în memoria cache a instrucțiunilor, deoarece acestea sunt doar pentru citire.)
Pentru a minimiza rata de pierdere a memoriei cache , a fost efectuată o mare analiză a comportamentului cache-ului pentru a găsi cea mai bună combinație de dimensiune, asociativitate, dimensiune bloc și așa mai departe. Secvențele de referință de memorie create de programele de referință sunt salvate ca urme de adrese . Analiza ulterioară simulează multe posibilități diferite de implementare a memoriei cache pe baza acestor urme lungi de adrese . Înțelegerea modului în care mai multe variabile modifică rata de accesare a memoriei cache poate fi destul de confuză. O contribuție semnificativă a fost făcută de Mark Hill, care a separat diferitele erori ale memoriei cache în trei categorii (cunoscute sub numele de „cei trei C” ):
- Eșecurile obligatorii sunt acele eșecuri cauzate de prima referire la un anumit. Mărimea memoriei cache și asociativitatea nu fac nicio diferență față de numărul de rateuri obligatorii . Preîncărcarea poate ajuta aici, la fel ca și dimensiunile mari ale blocurilor de cache (care este un tip de preluare preliminară).
- Eșecurile de capacitate sunt acele eșecuri pe care le va avea un cache de o anumită dimensiune, indiferent de asociativitate sau dimensiunea blocului. Curba frecvenței ratelor de capacitate față de dimensiunea memoriei cache oferă o anumită măsură a locației temporare a unui anumit flux de referință.
- Eșecurile de conflict sunt acele eșecuri care ar fi putut fi evitate dacă memoria cache nu ar fi șters datele anterior. Greșelile de conflict ar putea fi împărțite în continuare în rateuri de cartografiere , care sunt inevitabile având în vedere o anumită asociativitate, și rateuri de înlocuire , care sunt cauzate de alegerea specială a regulii de înlocuire.
Graficul din dreapta rezumă performanța cache-ului văzută de benchmark-urile porțiunii întregi a unui SPEC CPU2000, luate de Hill și Cantin [1] . Aceste valori de referință servesc pentru a reprezenta tipul de încărcare de lucru pe care o stație de lucru ar putea experimenta într-o zi dată. În acest grafic putem vedea diferitele efecte ale celor trei C.
În extrema dreaptă, când dimensiunea cache-ului ia o valoare „Inf” (care, cu alte cuvinte, tinde spre infinit), avem rate obligatorii . Dacă am dori să îmbunătățim caracteristicile SpecInt2000, creșterea dimensiunii cache-ului peste 1 MB ar fi practic inutilă.
Rata de eșec a memoriei cache complet asociative reprezintă pe deplin rata pierderilor de capacitate . În simulări, a fost aleasă o regulă de înlocuire a LRU: aceasta arată că ar fi necesară o regulă de înlocuire perfectă pentru a minimiza frecvența pierderilor de capacitate , ca și cum, de exemplu, un văzător ar căuta în viitor pentru a găsi o locație cache care nu va fi folosit.
Observați cum, în aproximarea frecvenței ratelor de capacitate , graficul are o scădere bruscă între 32KB și 64KB. Acest lucru indică faptul că benchmark-ul are un set de lucru de aproximativ 64KB. Un designer de cache care se uită la aceste valori de referință ar fi puternic tentat să seteze dimensiunea cache-ului chiar peste 64 KB, mai degrabă decât chiar sub această valoare. De asemenea, trebuie remarcat faptul că, pe această simulare, nici un fel de asociativitate nu poate rula un cache de 32KB, precum și un 4-way de 64KB, sau chiar un 128KB mapat direct.
În cele din urmă, rețineți că între 64KB și 1MB există o mare diferență între cache-ul mapat direct și cel complet asociativ. Această diferență este frecvența ratelor conflictelor . Conform datelor din 2004, cache-urile de nivel al doilea montate direct pe cipul procesorului tind să rămână în acest interval, deoarece cache-urile mici sunt suficient de rapide pentru a fi cache-uri de nivel întâi, în timp ce cele mai mari sunt prea scumpe pentru a fi montate ieftin pe cip în sine ( Itanium 2 are un cache de nivel al treilea de 9 MB, cel mai mare cache pe cip disponibil pe piață în 2004) . Din punctul de vedere al frecvenței ratelor de conflict , se pare că cache-ul de al doilea nivel aduce un mare beneficiu din asociativitatea ridicată.
Acest beneficiu a fost bine cunoscut la sfârșitul anilor 1980 și începutul anilor 1990 , când designerii de procesoare nu puteau încadra cache mari pe cipuri și nu aveau suficientă lățime de bandă pentru a implementa asociativitate ridicată pe cache-urile din afara cipului procesorului. Au fost încercate diverse soluții: MIPS R8000 a folosit SRAM -uri scumpe, dedicate off-chip , care includeau comparatoare de etichete și drivere mari, pentru a implementa un cache asociativ de 4MB în 4 căi. MIPS R10000 a folosit cipuri SRAM obișnuite pentru etichete. Accesarea etichetelor, în ambele direcții, a necesitat două cicluri: pentru a reduce latența, R10000, pentru fiecare acces, a încercat să prezică ce mod cache ar fi cel corect.
Lovitură în cache
Cache hit se referă în schimb la un succes al procesorului în găsirea adresei locației de memorie printre diferitele etichete de cache care o pot conține. Dacă are succes, procesorul poate citi ( Cache Read Hit ) sau scrie ( Cache Write Hit ) datele de pe linia cache.
În cazul unei lovituri de citire , procesorul citește cuvântul direct din cache fără a implica memoria principală. În ceea ce privește hit-ul de scriere , vă rugăm să consultați analiza aprofundată a politicii cache-ului de scriere
Traducerea adresei
Cele mai utilizate CPU-uri implementează un fel de memorie virtuală . În practică, fiecare program care rulează pe mașină își vede propriul spațiu de memorie, care conține cod și date pentru programul în sine, într-un mod simplificat. Fiecare program pune totul în propriul său spațiu de memorie fără a-și face griji cu privire la ceea ce fac celelalte programe în spațiile lor de memorie respective.
Memoria virtuală necesită procesorului să traducă adresele virtuale generate de program în adrese fizice din memoria principală. Porțiunea procesorului care face această translație este cunoscută sub numele de unitate de gestionare a memoriei (MMU). MMU poate accesa rapid tabelul de traducere prin Translation Lookaside Buffer (TLB), care este un cache de mapări pentru tabelul de pagini al sistemului de operare .
Traducerea adreselor are trei caracteristici importante:
- Latență: în general, MMU face adresa fizică disponibilă la câteva cicluri după ce adresa virtuală este calculată de generatorul de adrese.
- Alias: mai multe adrese virtuale se pot referi la aceeași adresă fizică. Majoritatea procesoarelor se asigură că toate actualizările la adresa fizică unică sunt făcute în ordine. Pentru a permite acest lucru, procesorul trebuie să se asigure că există o singură copie a fiecărei adrese fizice în cache la un moment dat.
- Granularitate: spațiul de adrese virtuale este împărțit în pagini. De exemplu, un spațiu de adrese virtuale de 4 GB ar putea fi împărțit în 1048576 pagini de 4 Kb, fiecare dintre acestea putând fi referită independent. Pentru suport pentru pagini de dimensiuni variabile, consultați intrarea de memorie virtuală .
O notă istorică: sistemele de memorie virtuale timpurii erau foarte lente, necesitând acces la tabelul de pagini (rezident în memorie) înainte de orice acces programat la memorie. Fără cache, aceasta reduce la jumătate viteza de accesare a memoriei mașinii. Din acest motiv, primul cache hardware folosit într-un computer nu a fost un cache de date sau instrucțiuni, ci un TLB.
Existența adreselor fizice și virtuale ridică întrebarea pe care dintre ele să se folosească pentru etichetele și indexurile cache. Motivația pentru utilizarea adreselor virtuale este viteza: un cache de date cu indici și etichete virtuale exclude MMU de la încărcare și utilizarea datelor din memorie. Întârzierea cauzată de încărcarea datelor din RAM ( load latency ) este crucială pentru performanța CPU: din acest motiv, majoritatea cache-urilor de nivel 1 sunt indexate cu adrese virtuale, permițând MMU să caute TLB în paralel cu preluarea datelor din memoria cache-ului RAM.
Adresarea virtuală nu este întotdeauna cea mai bună alegere: introduce, de exemplu, problema aliasurilor virtuale , adică cache-ul ar putea stoca valoarea aceleiași adrese fizice în mai multe locații. Costul gestionării aliasurilor virtuale crește odată cu dimensiunea memoriei cache și, ca rezultat, majoritatea cache-urilor de la nivelul 2 și mai sus sunt indexate cu adrese fizice.
Cu toate acestea, utilizarea adreselor virtuale pentru etichete ( etichetare virtuală ) nu este obișnuită. Dacă căutarea în TLB s-a încheiat înainte de căutarea în memoria cache RAM, atunci adresa fizică ar fi disponibilă la timp pentru compararea etichetelor și, prin urmare, etichetarea virtuală nu ar fi necesară. Cache-urile mari, prin urmare, tind să fie etichetate fizic și doar cache-urile mici cu latență scăzută sunt practic etichetate. În procesoarele mai noi, etichetarea virtuală a fost înlocuită cu vhints , așa cum este descris mai jos.
Indexare virtuală și aliasuri virtuale
Modul obișnuit prin care procesorul se asigură că aliasurile virtuale funcționează corect este de a le ordona astfel încât, în orice moment, un singur alias virtual să poată fi în cache.
De fiecare dată când o nouă valoare este adăugată în cache, procesorul caută alte aliasuri virtuale și le elimină. Acest lucru se face numai în cazul unei erori de cache. Nu este necesară nicio muncă specială în timpul unei accesări în cache, ceea ce ajută la menținerea căii rapide în cache cât mai rapid posibil.
Cel mai simplu mod de a găsi aliasuri este să le mapați pe toate în aceeași zonă de cache. Acest lucru se întâmplă, de exemplu, dacă TLB are pagini de 4 KB, iar memoria cache este mapată direct la 4 KB sau mai puțin.
Cache-urile moderne de nivel superior sunt mult mai mari decât 4KB, dar paginile de memorie virtuală au rămas la aceeași dimensiune. Dacă, de exemplu, memoria cache este de 16KB și virtual indexată, fiecare adresă fizică poate fi adresată din 4 locații diferite din cache, pentru tot atâtea adrese virtuale. Dacă memoria cache eșuează, toate cele patru locații ar trebui verificate pentru a vedea dacă adresele lor fizice corespunzătoare se potrivesc de fapt cu adresa fizică a autentificării eșuate.
Aceste controale sunt aceleași controale pe care le folosește un set cache asociativ pentru a selecta o anumită potrivire. Deci, dacă se folosește un cache indexat practic de 16KB, setul în 4 direcții asociativ, cu pagini de memorie virtuală de 4KB, nu este nevoie de muncă suplimentară pentru a elimina aliasurile virtuale în caz de pierdere a cache-ului, deoarece verificările au fost deja făcute. .
Să folosim din nou un AMD Athlon ca exemplu: are un cache de date de nivel superior de 64KB, cu pagini de 4KB, set asociativ bidirecțional. Când memoria cache de date de nivel superior eșuează, 2 dintre cele 16 (= 64 KB / 4 KB) aliasuri virtuale posibile au fost deja verificate și sunt necesare șapte cicluri suplimentare ale buclei de verificare a etichetei pentru a finaliza eliminarea alias-urilor virtuale suplimentare.
Etichete virtuale și vhints
Etichetarea virtuală este, de asemenea, posibilă. Marele avantaj al etichetei virtuale este că, pentru cache-urile asociative, acestea permit potrivirea etichetelor înainte ca traducerea virtuală-fizică să fie efectuată. Oricum,
- Verificările de consistență și de eliminare prezintă o adresă fizică pentru fiecare acțiune. Hardware-ul trebuie să aibă o metodă de conversie a adresei fizice într-o adresă cache, în general prin stocarea etichetelor fizice, precum și a etichetelor virtuale. Pentru comparație, un cache etichetat fizic nu trebuie să păstreze etichete virtuale, ceea ce este mai simplu.
- Când o referință virtuală-fizică este ștearsă din TLB, informațiile din cache cu acele adrese virtuale vor trebui golite într-un fel. Dacă informațiile din cache sunt permise pe paginile care nu sunt mapate de TLB, atunci aceste informații vor trebui șterse când drepturile de acces la aceste pagini se schimbă în tabelul de pagini.
Este posibil ca sistemul de operare să se asigure că mai multe aliasuri virtuale sunt rezidente simultan în cache. Sistemul de operare asigură acest lucru prin încordarea colorării paginii care este descrisă mai jos. Unele procesoare RISC recente (SPARC, RS / 6000) au adoptat această abordare. Nu a fost folosit recent, deoarece costul hardware-ului pentru descoperirea și eliminarea aliasurilor virtuale a scăzut, în timp ce complexitatea și prețul performanței software-ului de colorat pagini perfecte a crescut.
Ar putea fi util să distingem cele două funcții de etichetare într-un cache asociativ: ele sunt utilizate pentru a determina ce mod al setului de informații să fie selectat și sunt folosite pentru a determina dacă memoria cache eșuează sau nu. A doua funcție trebuie să fie întotdeauna corectă, dar primei funcție i se permite să ghicească și să obțină răspunsul greșit ocazional.
Unele procesoare (cum ar fi SPARC recent) au cache-uri atât cu etichete virtuale, cât și fizice. Etichetele virtuale sunt folosite pentru selectarea modului, iar etichetele fizice sunt folosite pentru a determina centrul sau eșecul. Acest tip de cache favorizează avantajul de latență al unui cache de etichete virtuale și interfața software simplă a unui cache de etichete fizice. Totuși, suportă costul suplimentar al etichetelor duplicate. Chiar și în timpul proceselor de eșec, modurile alternative ale liniei cache trebuie verificate pentru aliasuri virtuale și pentru eventualele potriviri eliminate.
Zona suplimentară (și o anumită latență) poate fi atenuată prin păstrarea indicii virtuale cu orice informații din cache în loc de etichete virtuale. Aceste indicii sunt un subset sau hash al unei etichete virtuale și sunt folosite pentru a selecta modul cache prin care să preia datele și o etichetă fizică. Cu un cache etichetat virtual, poate exista o potrivire de indiciu virtual, dar o nepotrivire fizică a etichetei, în acest caz, informațiile din cache cu potrivirea indicii trebuie eliminate, astfel încât să acceseze memoria cache după completarea memoriei cache la această adresă, ei vor au un singur indiciu potrivire. Deoarece indicii au mai puțini biți decât etichetele virtuale pentru a le distinge unele de altele, un cache cu indicii virtuale suferă de mai multe deficiențe de conflict decât un cache de etichete virtuale.
Poate că reducerea finală a indicii virtuale poate fi găsită în Pentium 4 (nuclee Willamette și Northwood). În aceste procesoare, indicația virtuală este de fapt de doar 2 biți, iar memoria cache este asociativă în 4 căi. De fapt, hardware-ul menține o permutare simplă de la adresele virtuale la adresele cache, astfel încât să nu fie nevoie de CAM pentru a selecta unul corect dintre cele patru moduri de recuperare.
Colorarea paginii
Cache-urile indexate fizic mari (de obicei cache-urile secundare) întâmpină o problemă: sistemul de operare, mai degrabă decât aplicațiile, controlează ce pagini se ciocnesc între ele în cache. Diferențele în alocarea paginilor dintr-un program duc la următorul nivel de diferențe în căile de coliziune în cache, ceea ce poate duce la diferențe foarte mari în performanța programului. Aceste diferențe pot face foarte dificilă obținerea unui timp de referință consecvent și repetabil pentru rularea programelor, determinând inginerii plătiți și deconsolați să solicite autorilor sistemelor de operare să rezolve problema.
Pentru a înțelege problema, luați în considerare un procesor cu 1 MB de cache de nivel 2 cu mapare directă indexată fizic și 4KB de pagini de memorie virtuală. Paginile fizice secvențiale se mapează la locații secvențiale din cache, până când, după 256 de pagini, calea revine la sine. Putem eticheta fiecare pagină fizică cu o culoare de la 0 la 255 pentru a indica locul în cache. Locațiile din paginile fizice cu culori diferite nu pot intra în conflict în cache.
Un programator care dorește să folosească la maximum memoria cache și-ar putea aranja accesele la program astfel încât doar 1 MB de date să fie stocate în cache la un moment dat, evitând în același timp defecțiunile de capacitate. Dar ar trebui să se asigure, de asemenea, că login-urile nu au erori de conflict. O modalitate de a gândi la această problemă este să subdivizați paginile virtuale pe care le folosește programul și să le atribuiți culori virtuale în același mod în care culorile fizice au fost atribuite paginilor fizice anterior. Programatorul poate aranja apoi accesele codului său astfel încât două pagini cu aceeași culoare virtuală să nu fie utilizate în același timp. Există o literatură extinsă despre aceste optimizări (de exemplu , Loop nest optimization ), provenind în mare parte din comunitatea High Performance Computing (HPC).
Conceptul este că, în timp ce toate paginile utilizate la un moment dat pot avea culori virtuale diferite, unele pot avea aceeași culoare fizică. De fapt, dacă sistemul de operare atribuie pagini fizice paginilor virtuale într-un mod aleatoriu și uniform, este foarte probabil ca unele pagini să aibă aceeași culoare fizică și, prin urmare, pozițiile din aceste pagini coincid în cache (acesta este paradoxul zilei de naștere ).
Soluția este ca sistemul de operare să încerce să atribuie pagini fizice colorate diferit unor culori virtuale diferite, o tehnică numită colorare a paginii . Deși maparea reală a culorilor virtuale la fizice este irelevantă pentru performanța sistemului, mapările ciudate sunt dificil de urmărit și au mici beneficii, așa că majoritatea abordărilor de colorare a paginilor încearcă pur și simplu să păstreze paginile fizice și virtuale colorate în același mod.
Dacă sistemul de operare poate garanta că fiecare pagină fizică se referă la o singură culoare virtuală, atunci nu există aliasuri virtuale, iar procesorul poate folosi cache-urile indexate virtual fără a fi nevoie de verificări suplimentare ale aliasului virtual în timpul gestionării erorilor. Alternativ, sistemul de operare poate șterge o pagină din cache, chiar dacă se schimbă de la o culoare virtuală la alta. După cum am menționat mai devreme, această abordare a fost folosită de unele modele recente SPARC și RC / 6000.
Ierarhia cache într-un procesor modern
Procesoarele moderne au mai multe cache-uri pe cip cu care să interacționeze. Două motive în special au condus la dezvoltarea actualei ierarhii cache.
Cache-uri specializate
Primul motiv este că procesoarele pipeline accesează memoria din mai multe puncte din conductă: regăsirea instrucțiunilor, traducerea adreselor virtuale în fizice și regăsirea datelor. Pentru un exemplu simplu: Classic RISC Pipeline . Implementarea naturală este de a folosi cache fizice diferite pentru fiecare dintre aceste puncte, astfel încât să nu fie necesară programarea resurselor fizice pentru a servi două puncte în conductă. Deși conducta se termină în mod natural cu cel puțin trei cache-uri separate (instrucțiuni, TLB și date), fiecare este specializat într-un anumit rol.
Cache pentru victime
Un cache pentru victimă este un cache folosit pentru a menține blocurile eliminate din memoria cache a CPU din cauza unui conflict sau a pierderii capacității. Cache-ul victimei este situat între memoria cache primară și memoria de bază și păstrează numai blocurile eliminate după o pierdere. Această tehnică este utilizată pentru a reduce penalizarea pentru o eroare a memoriei cache, deoarece se poate întâmpla ca datele care se află în memoria cache a victimei să fie solicitate ceva timp mai târziu, iar apoi, în loc să declare o pierdere și să intre în memorie pentru a prelua aceste date, memoria cache a victimei este verificată și datele care sunt încă în el sunt utilizate.
Cache-ul original al victimei de pe un HP PA7200 era un cache mic, complet asociativ. Procesoarele ulterioare, cum ar fi AMD Athlon , Athlon XP și Athlon 64 , folosesc memoria cache secundară foarte mare ca cache pentru victimă, pentru a evita repetarea stocurilor de context în memoria cache primară.
Cache de urmărire
Unul dintre cele mai extreme exemple de specializare cache este cel al trace cache-ului utilizat în microprocesoarele Pentium 4 . Un cache de urmărire este un mecanism pentru creșterea lățimii de bandă de preluare a instrucțiunilor prin stocarea urmelor de instrucțiuni care au fost deja stocate. Mecanismul a fost propus pentru prima dată de Eric Rotenberg , Steve Bennett și Jim Smith în lucrarea lor din 1996: „ Trace Cache: a Low Latency Approach to High Bandwidth Instruction Fetching ” .
Un cache de urmărire stochează instrucțiuni chiar și după ce au fost executate sau pe măsură ce sunt retrase. În general, instrucțiunile sunt adăugate în cache-urile de urmărire în grupuri care reprezintă atât blocuri individuale de bază, cât și urme de instrucțiuni dinamice. Un bloc de bază constă dintr-un grup de instrucțiuni fără ramură (Nedivizate) care se termină într-o ramură. O urmă dinamică („trace path” sau „trace of the path”) constă numai din instrucțiunile a căror rezultat este efectiv folosit și elimină următoarele instrucțiuni care iau ramuri (din moment ce nu sunt executate); o pistă dinamică poate fi concatenarea multiplilor de blocuri de bază. Acest lucru permite unității de recuperare a instrucțiunilor să recupereze mai multe blocuri de bază, fără grija de a se ramifica în fluxul de execuții.
Liniile de urmărire sunt stocate în memoria cache de urmărire pe baza contorului de program al primei instrucțiuni din urmă și a unui set de predicții de ramuri. Acest lucru permite stocarea diferitelor urme de căi începând cu aceeași adresă, fiecare reprezentând rezultate diferite de ramificare. În etapa de stocare a instrucțiunilor a unei conducte de instrucțiuni , contorul programului curent împreună cu un set de predicții de ramificație este verificat în memoria cache de urmărire pentru o atingere. Dacă apare o lovitură, este furnizată o linie de urmărire pentru a găsi care dintre acestea nu trebuie să meargă într-o memorie cache obișnuită pentru aceste instrucțiuni. memoria cache de urmărire continuă să alimenteze unitatea de preluare până când linia de urmărire se termină sau până când există o predicție greșită în conductă. Dacă există o eroare, începe să fie creată o nouă pistă. Avantajul față de cache-urile de cod obișnuite este că toate instrucțiunile care urmează unei ramuri care sunt necondiționate sau prezise ca nu sunt urmate nu sunt stocate în cache: rezultatul este că nu se formează „bule” de cod neutilizat care să risipească spațiu.memorie cache.
Cache-urile de urmărire sunt folosite și în procesoare precum Intel Pentium 4 pentru a stoca micro operațiuni deja decodate sau traduceri ale instrucțiunilor x86 complexe, astfel încât data viitoare când se solicită aceeași instrucțiune, aceasta nu trebuie să fie decodificată.
Ideea din spatele trace cache-ului este că în procesoarele CISC care folosesc instrucțiuni RISC intern , cum ar fi Pentium 4, decodarea instrucțiunilor este o operațiune extrem de costisitoare, iar rezultatul acesteia ar trebui exploatat la maximum. Folosirea unui cache de urmărire în loc de un cache normal are doar acest avantaj: nu trebuie să decodați o instrucțiune deja întâlnită în timpul execuției unui program.
Cacheul de urme nu a primit prea multă favoare în ultima vreme din cauza unor defecte. Primul este că multe instrucțiuni RISC sunt traduse într-o singură instrucțiune CISC într-un singur ciclu de ceas, iar instrucțiunile care necesită mai multe cicluri de ceas pentru a se traduce în mai multe instrucțiuni RISC sunt relativ puține și rare, astfel încât beneficiul real al cache-ului de urmărire este limitat. . La aceasta se adaugă și faptul că, în cazul arhitecturii Intel, instrucțiunile CISC au în general o lungime variabilă între 1 și 6 octeți (între 8 și 48 de biți), în timp ce toate instrucțiunile RISC utilizate intern au o lungime fixă de 118 biți. . Prin urmare, cu aceeași dimensiune, un cache de urme conține mult mai puține instrucțiuni decât un cache normal. Aceste dezavantaje au determinat Intel să nu folosească trace cache în cele mai recente arhitecturi: Intel Core și Intel Core 2 .
Vezi textul lucrării Smith, Rotenberg și Bennett . Preluat la 30 noiembrie 2019 (arhivat din original pe 3 aprilie 2008) . în Citeseer .
Cache pe mai multe niveluri
Al doilea motiv este compromisul fundamental dintre latența cache-ului și rata de accesare. Cache-urile mai mari sunt mai lente și au rate de accesare mai bune. Pentru a îmbunătăți acest compromis , multe sisteme folosesc mai multe niveluri de cache, cu cache-uri mici și rapide bazându-se pe cache-uri mai mari și mai lente. Pe măsură ce diferența de latență dintre memoria principală și memoria cache mai rapidă a devenit mai mare, unele procesoare au început să folosească și trei niveluri de cache pe cip. De exemplu, în 2003, Itanium II a început să fie livrat cu un cache unificat pe cip de 6MB de nivel 3. Seria IBM Power 4 are 256 MB de memorie cache de nivel 3 off-chip, partajată între mai multe procesoare.
Cache-urile pe mai multe niveluri funcționează în general prin verificarea mai întâi a cache-urilor de nivel 1; dacă apare o lovitură, procesorul rulează la viteză mare. Dacă memoria cache mai mică „eșuează”, atunci cea mai mare este verificată și așa mai departe, până când memoria principală trebuie accesată.
Cache-urile pe mai multe niveluri introduc un nou model decizional. De exemplu, la unele procesoare (cum ar fi Intel Pentium 2 , 3 și 4 , precum și multe RISC ), datele din memoria cache L1 pot fi, de asemenea, în memoria cache L2. Aceste cache-uri sunt denumite inclusiv. Alte procesoare (cum ar fi AMD Athlon ) au cache-uri exclusive în care datele sunt garantate a fi cel mult într-una dintre cache-urile L1 sau L2.
Avantajul cache-urilor exclusive este că stochează mai multe date. Acest avantaj crește cu cache-uri mai mari (implementările Intel x86 nu sunt). Un avantaj al cache-urilor inclusive este că, atunci când dispozitivele externe sau alte procesoare dintr-un sistem multiprocesor doresc să elimine o linie de cache din procesor, trebuie ca procesorul să verifice doar memoria cache L2. În ierarhiile cache care nu folosesc includerea, trebuie verificate și cache-urile L1. Există o corelație între asociativitatea cache-urilor L1 și L2: dacă cache-urile L2 nu au cel puțin la fel de multe moduri ca toate cache-urile L1 împreună, asociativitatea reală a cache-urilor L1 este limitată.
Un alt avantaj al cache-urilor inclusive este că cache-urile mai mari pot folosi linii de cache mai mari, ceea ce reduce dimensiunea etichetelor cache secundare. Dacă memoria cache secundară este cu un ordin de mărime mai mare decât cea primară, iar datele din cache sunt cu un ordin de mărime mai mari decât etichetele cache, aceste etichete de date salvate pot fi comparate cu zona incrementală necesară pentru stocarea datelor. Cache L1 și L2.
După cum am menționat mai devreme, computerele mari au uneori un alt cache între L2 și memoria principală numită cache L3. Acest cache este în general implementat pe un cip separat de CPU și, ca în 2004 , are o capacitate de la 2MB până la 256MB. Aceste cache-uri vor costa cu mult peste 1000 USD pentru a construi, iar beneficiile lor vor depinde de căile de acces ale aplicațiilor. Stațiile de lucru și serverele x86 de vârf sunt acum disponibile cu o opțiune pentru cache L3.
În cele din urmă, de cealaltă parte a ierarhiei memoriei, fișierul CPU Register poate fi considerat cel mai mic și mai rapid cache din sistem, caracteristica specială fiind apelată de software - de obicei de un compilator, deoarece alocă registre care trebuie să dețină valori. preluat din memoria principală.
Exemplu: arhitectura AMD K8
Pentru a ilustra atât specializarea, cât și multinivelul de cache, iată ierarhia cache a unui AMD Athlon 64 , a cărui implementare de bază este cunoscută sub numele de arhitectura K8 .
K8 are 4 cache specializate: un cache de instrucțiuni, un cache de instrucțiuni TLB , un cache de date și un cache de date TLB. Fiecare dintre aceste cache-uri este specializată:
- Cache-ul de instrucțiuni menține copii de linie de 64 de octeți de memorie și preia 16 octeți pe ciclu. Fiecare octet din acest cache este stocat pe 10 biți în loc de 8, biții suplimentari marcând limitele instrucțiunilor (Acesta este un exemplu de precodificare). Cache-ul are doar protecție la paritate , mai degrabă decât ECC , deoarece paritatea este mai mică și orice date corupte pot fi înlocuite cu date proaspete din memorie (care are întotdeauna o copie actualizată a instrucțiunilor).
- Instrucțiunea TLB păstrează o copie a informațiilor din tabelul de pagini (PTE). Fiecare ciclu de preluare a instrucțiunii are adresa sa virtuală tradusă prin acest TLB într-una fizică. Fiecare informație are atât 4 cât și 8 octeți în memorie. Fiecare TLB este împărțit în două secțiuni, una pentru a păstra maparea PTE la 4KB și una pentru a păstra maparea PTE la 4MB sau 2MB. Subdiviziunea permite un circuit simplu pentru o comparație complet asociativă în fiecare secțiune. Sistemul de operare mapează diferite secțiuni ale spațiului de adrese virtuale cu diferite dimensiuni PTE.
- TLB de date are două copii diferite care dețin aceleași informații. Cele două copii permit două accesări la date pentru fiecare ciclu pentru a traduce adrese virtuale în adrese fizice. La fel ca instrucțiunea TLB, acest TLB este împărțit în două tipuri de informații.
- Cache-ul de date păstrează copii de memorie ale liniilor de 64 de octeți. Este împărțit în 8 bănci (fiecare stochează 8 KB de date) și poate prelua două date de 8 octeți pe ciclu, atâta timp cât aceste date sunt în bănci diferite. Există două copii ale etichetelor, deoarece fiecare linie de 64 de octeți este răspândită pe toate cele 8 bănci. Fiecare copie a etichetei gestionează una dintre cele două accesări pe ciclu.
K8 are, de asemenea, caching pe mai multe niveluri. Există instrucțiuni de nivel al doilea și TLB de date, care stochează doar mapări PTE de 4KB. Atât cache-urile de instrucțiuni și de date, cât și diferitele TLB-uri, pot fi umplute de cache-ul mare unificat de nivel 2. Acest cache este exclusiv atât pentru cache-urile de date L1, cât și pentru instrucțiuni, ceea ce înseamnă că orice linie de 8 octeți poate locui într-una dintre cache-urile de instrucțiuni L1, memoria cache de date L1 sau cache-ul L2. Cu toate acestea, este posibil ca o linie din memoria cache de date să aibă un PTE care se află și într-unul dintre cache-urile TLB - sistemul de operare este responsabil pentru menținerea consecvenței TLB-urilor prin descărcarea unor părți din ele atunci când tabelul de pagini din memorie este reîmprospătat.
K8 stochează informații care nu sunt niciodată stocate în memorie - informații de predicție. Aceste cache nu sunt afișate în diagrama anterioară. Așa cum este de obicei pentru această clasă de procesoare, K8 are o predicție a ramurilor destul de complexă , cu tabele care ajută la prezicerea căilor parcurse și alte tabele care prezic ținte de traseu și salt. Unele dintre aceste informații sunt asociate cu instrucțiuni, atât în memoria cache a instrucțiunilor L1, cât și a L2 unificat.
K8 folosește un mecanism interesant pentru a stoca informații de predicție cu instrucțiuni în memoria cache secundară. Liniile din memoria cache secundară sunt protejate de coruperea accidentală a datelor (de exemplu , particulele alfa lovite prin ECC sau paritate , în funcție de dacă aceste linii au fost eliminate din memoria cache de date sau de instrucțiuni. de paritate ocupă mai puțini biți decât ECC, liniile din memoria cache de instrucțiuni). au câțiva biți rămași. Acești biți sunt utilizați pentru a calcula predicțiile de cale asociate cu instrucțiunile. Rezultatul final este că predictorul de cale are un istoric mare de tabel, deci are o precizie mai bună.
Alte ierarhii
Alte procesoare au alte tipuri de predictori. (de exemplu, predictorul de ocolire de la stocare la încărcare în DEC Alpha 21264) și diferiți alți predictori specializați sunt ușor de imaginat pentru a fi integrati în procesoarele viitoare.
Acești predictori sunt cache-uri în sensul că stochează informații care sunt costisitoare de calculat. Unele dintre terminologiile folosite în discutarea predictorilor sunt aceleași cu cele pentru cache (numite rezultate în predictorul de cale), dar predictorii nu sunt, în general, ponderați ca parte a ierarhiei cache.
K8 păstrează consecvența instrucțiunilor și a datelor din cache în hardware, ceea ce înseamnă că o stocare într-o instrucțiune imediat după ce instrucțiunea este stocată va schimba instrucțiunea următoare. Alte procesoare, cum ar fi cele din familia Alpha și MPS, sunt bazate pe software pentru a menține cache-urile de instrucțiuni consistente. Nu se garantează că stocările vor fi văzute în fluxul de instrucțiuni decât dacă un program apelează o opțiune de sistem de operare pentru a asigura coerența. Ideea este de a scuti complexitatea hardware, presupunând că codul care se modifică automat este rar.
Ierarhia cache-ului se extinde dacă luăm în considerare atât software-ul, cât și hardware-ul. Fișierul de registru din nucleul unui procesor poate fi considerat un cache foarte mic și rapid, care atinge, eșuează și umplerile sunt prezise de compilator din timp. (Vezi în special Optimizarea cuibului buclei .) Fișierele de înregistrare au uneori și o ierarhie: Cray-1 (circa 1976) avea 8 registre scalare și 8 registre de adrese care erau în general utilizabile, avea și 64 de registre scalare și 64 de adrese de tip „B”. registre. Registrele de tip „B” puteau fi încărcate mai repede decât cele din memoria principală, deoarece Cray-1 nu avea cache de date.
Implementare
Deoarece citirile din memoria cache sunt operațiuni destul de obișnuite care durează mai mult de un singur ciclu, recurența de la o încărcare a unei instrucțiuni la instrucțiunea în sine tinde să fie calea cea mai critică în designul bun al procesorului, astfel încât datele din această cale se pierd cât mai puțin timp. pe cat posibil. Ca rezultat, memoria cache L1 este componenta cea mai sensibilă la latență de pe cip.
Cel mai simplu cache este un cache cu hartă directă indexată virtual. Adresa virtuală este calculată cu un sumator, cea mai semnificativă parte a adresei este extrasă și utilizată pentru a indexa o SRAM, care returnează datele stocate. Datele sunt aliniate cu octeți într-un decalator de octeți și de acolo sunt trecute la următoarea operație. Nu este nevoie de nicio verificare a etichetelor în bucla internă - de fapt, etichetele nici nu trebuie să fie citite. Mai târziu, dar înainte ca instrucțiunea să fie încărcată efectiv, eticheta pentru datele încărcate trebuie citită și verificată cu adresa virtuală pentru a vă asigura că a existat o accesare în cache. Dacă aceasta eșuează, memoria cache este actualizată cu linia solicitată și conducta este repornită.
O memorie cache asociativă este mult mai complicată, deoarece unele elemente de date trebuie citite pentru a determina ce punct de cache să selecteze, un cache de nivel 1 cu N-way-set-asociativ citește de obicei toate N etichete posibile și N date în paralel, după care alege datele asociate cu eticheta corespunzătoare. Cache-urile de nivel 2 economisesc uneori energie citind mai întâi eticheta, astfel încât doar o singură bucată de date este citită din SRAM.
Diagrama din dreapta servește la clarificarea modului în care sunt utilizate diferitele câmpuri de adresă. Diagrama arată SRAM-ul, indexarea și multiplexarea pentru o memorie cache asociată cu set de 4 KB etichetat și indexat virtual, cu 64B linii, o citire largă de 32b și o adresă virtuală de 32b.
Deoarece memoria cache este de 4KB și are 64B de linii, există doar 64 de linii în cache și citim câte două dintr-o etichetă SRAM care are 32 de linii, fiecare cu câteva etichete de 21 de biți. Deși orice funcție de adresă virtuală de la 31 la 6 poate fi utilizată pentru a indexa etichete și date SRAM, este mai ușor să folosiți biții mai puțin semnificativi.
În mod similar, deoarece memoria cache este de 4KB și are o cale de citire de 4B și citește două moduri pentru fiecare adresă, datele SRAM au o lățime de 512 linii de 8 octeți.
O memorie cache mai modernă ar putea fi de 16 KB, 4-way set-associative, virtual indexată, virtual sugerată și etichetată fizic, cu 32B linii, 32b citiri și adrese fizice pe 36 de biți. Apariția căilor de citire pentru aceste tipuri de cache seamănă foarte mult cu calea de mai sus. În loc de etichete, se citesc indicii și se compară cu un subset de adrese virtuale. Mai târziu, adresa virtuală este tradusă într-o adresă fizică de către TLB, iar eticheta fizică este citită (doar una, deoarece vhint-ul oferă ce direcție a cache-ului să citească). În cele din urmă, adresa fizică este comparată cu adresa etichetei pentru a determina dacă a avut loc o lovitură.
Unele implementări SPARC și-au îmbunătățit viteza cache-urilor L1 cu câteva întârzieri prin prăbușirea agregatorului de adrese virtuale în decodoarele SRAM.
Note
- ^ How The Cache Memory Works , despre Hardware Secrets , 12 septembrie 2007. Consultat la 29 martie 2022 .
Articole înrudite
Alte proiecte
Wikimedia Commons conține imagini sau alte fișiere în memoria cache a CPU
Link- uri externe
- ( EN ) Evaluarea asociativității în cache-urile CPU - Hill și Smith - 1989 - Introduce capacitatea, conflictul și clasificarea obligatorie.
- ( RO ) Performanța memoriei cache pentru benchmark-uri SPEC CPU2000 . - Hill and Cantin - 2003 - Această lucrare de referință a fost actualizată de mai multe ori. Are rezultate de simulare amănunțite și lucide prezentate pentru un set rezonabil de larg de benchmark-uri și organizații de cache.
- ( EN ) Memory Hierarchy in Cache-Based Systems ( PDF ) (arhivat din original pe 15 septembrie 2009) . , de Ruud van der Pas, 2002, Sun Microsystems, este un frumos articol introductiv la memorarea în cache a CPU.
- ( EN ) A Cache Primer ( PDF ) (arhivat din original la 25 iulie 2008) . de Paul Genua, PE, 2004, Freescale Semiconductor, un alt articol introductiv.


