Le sfide tecnologiche
delle moderne CPU
| Premessa
|
Continua la serie di articoli tratti dai lavori realizzati
e pubblicati da Fantini Filippo e Stocchi Stefano
con la coordinazione del Prof. Gianni Conte dell'Università
degli Studi di Parma. Questa volta parliamo della continua
sfida tecnologica a cui sono sottoposti i progettisti di
CPU moderne. Nell'articolo si approfondiscono i punti critici
di una CPU superscalare (come PII,PIII,P4, Athlon,G4,etc...)
e le strategie utilizzate dai progettisti per superare le
problematiche e fornire prestazioni sempre più alte.
Il lavoro originale è disponibile on-line a questo
indirizzo:
http://www.ce.unipr.it/~stocchi/
dove potete trovare anche altri interessantissimi articoli.
Per contattare gli autori inviare una mail al seguente indirizzo:
conte@CE.UniPR.IT
Buona Lettura. |
L’obiettivo di questo articolo non è quello di spiegare
nel dettaglio il funzionamento di una specifica CPU,
bensì di mettere in evidenza i punti maggiormente critici dell'architettura
di un moderno processore.
La
generazione attuale dei microprocessori ha prestazioni, rispetto
ai predecessori, superiori di svariati ordini di grandezza.
Questi radicali aumenti di performance, velocità e numero di
transistor possono sembrare slegati ad un osservatore casuale.
In
realtà, sebbene il progetto attuale dei microprocessori vari
enormemente da caso a caso, possono essere individuate delle
linee guida comuni. Ogni processore infatti effettua una generazione
degli indirizzi, contiene unità logico-aritmetiche, possiede
dei file dei registri, e ha un’interfaccia di sistema.
Molti hanno una o più cache on-chip, un TLB
(translation lookaside buffer), e praticamente tutte le architetture
correnti possiedono unità floating point on-chip.
Per
effettuare queste funzioni di base sono state implementate differenti
tecniche di progetto, che però devono risolvere gli stessi problemi.
Pertanto in questa sede analizzeremo per primi i più
comuni problemi affrontati da tutti i progettisti di CPU, per
presentare poi le tecniche utilizzate per superare questi problemi.
Nella seconda parte dell'articolo daremo invece uno sguardo
alle linee guida per lo sviluppo dei processori futuri che si
prefiggono l'obbiettivo di superare le limitazioni che affliggono
gli attuali modelli computazionali, ed in primis i limiti delle
CPU x86.
I PROBLEMI DEI PROCESSORI MODERNI...
1.1 Le
latenze della memoria e della cache di secondo livello
I
primi microprocessori effettuavano il fetch delle istruzioni
direttamente dalla memoria; in questo modo, dopo aver inviato
una richiesta di dati, il processore doveva attendere un tempo
molto lungo prima che i dati arrivassero, impedendo così alla
CPU di operare in modo efficiente alla velocità per la quale
era stata progettata.
L’implementazione
della cache secondaria off-chip ha aiutato ad alleviare questo
problema. Una mamoria cache è solitamente di dimensioni limitate
(normalmente da 32 a 512 Kbyte), e contiene un blocco di indirizzi
di memoria comprendenti una piccola sezione della memoria principale.
La memoria cache fornisce un accesso più rapido, e può spedire
i dati al processore ad una frequenza maggiore della memoria
principale.
I
sistemi di memoria cache on-chip possono poi aumentare ancore
le prestazioni, poiché permettono il completamento di un accesso
in un singolo ciclo di clock. L’aumento di prestazioni fornito
dalla cache di primo livello ha indotto i progettisti ad aumentarne
sempre più le dimensioni causando in molte architetture
un notevole aumento dello spazio dedicato al progetto della
cache; in molte implementazioni attuali la cache occupa più
dell’80% della superficie del die.
Le
performance raggiungono il valore massimo quando l’applicazione
può essere eseguita totalmente dentro la cache. Tuttavia, quando
l’applicazione, come spesso avviene, è troppo grande per stare
nella cache, le performance diminuiscono in modo significativo.
La figura 1 mostra la relazione esistente fra le prestazioni
e la dimensione di un’applicazione.
Fig.
2
Se
la cache on-chip ha il vantaggio di aumentare le prestazioni,
la tecnologia attuale e il numero di transistori disponibili
ne limitano la dimensione massima. Attualmente 64 Kbyte (32
per i dati e 32 per le istruzioni) rappresentano il limite della
cache di primo livello, e la sua implementazione richiede molti
milioni di transistor.
Questi
fattori limitanti della cache on-chip aumentano l‘importanza
della cache di secondo livello, dove la dimensione della cache
è limitata solo dal mercato in cui il prodotto sarà collocato.
Il
tempo di accesso di molti dei dispositivi RAM attualmente disponibili
è piuttosto elevato rispetto al tempo di clock del processore,
e ciò forza i progettisti a trovare soluzioni alternative. L’interleaving
della cache è uno degli espedienti utilizzati, dato che permette
la sovrapposizione delle richieste in memoria da parte del processore.
Questa tecnica si può applicare sia alla memoria principale
che alla cache; il più comune è l’interleaving a due o a quattro
vie. Questo perché aumentando l’interleaving si riesce a nascondere
gran parte del tempo di accesso, ma aumenta considerevolmente
anche la complessità richiesta per supportarlo.
1.2 Le
dipendenze dei dati
In
un programma, le istruzioni vengono caricate dalla cache istruzioni,
decodificate ed eseguite. Il dato corrispondente è spesso caricato
da un registro, manipolato in un’ALU, e il risultato viene rimesso
nello stesso registro o in un altro.
Se
l’istruzione successiva della sequenza richiede il risultato
dell’istruzione precedente per poter essere eseguita, avviene
una dipendenza di dati. Per quelle istruzioni che richiedono
molti cicli per essere completate, ci può essere un impatto
notevole sulle prestazioni nel caso vi siano delle dipendenze.
Alcune di queste possono essere eliminate semplicemente riarrangiando
il programma in modo che il risultato di una data istruzione
non venga utilizzato dalle prime istruzioni seguenti.
Un
modo per alleviare il problema delle dipendenze dei dati è utilizzare
l’esecuzione fuori ordine con ridenominazione dei registri.
1.3 Diramazioni
(salti condizionali)
Tutti
i programmi di computer contengono diramazioni (branch). Alcune
sono non condizionali, cioè il flusso del programma viene interrotto
non appena l’istruzione di branch viene eseguita; altre sono
condizionali, cioè il branch viene eseguito solo se certe condizioni
vengono soddisfatte. Le interruzioni del flusso del programma
sono presenti in tutti i software, e l’hardware può solo cercare
di adeguarsi ai branch nel modo più efficiente possibile.
Quando
viene presa una diramazione, il nuovo indirizzo al quale il
programma deve riiniziare può essere nella cache secondaria
oppure no; a seconda di dove è situato il nuovo blocco di istruzioni
la latenza aumenta o diminuisce. Poiché il tempo di accesso
della memoria principale e della cache secondaria sono molto
maggiori del tempo di accesso della cache on chip, il branching
spesso degrada le prestazioni del processore.
Questo
problema è ancora più importante nelle macchine superscalari,
dove ad ogni ciclo vengono eseguite più istruzioni. In un certo
momento, infatti, a seconda della dimensione della pipeline,
numerose istruzioni possono essere in vari stadi di esecuzione;
quando viene presa una diramazione, non si conoscono il numero
di cicli che saranno necessari per la sua esecuzione.
L’implementazione
del branching è un importante problema architetturale. Per migliorare
le prestazioni molte architettura attuali incorporano una circuiteria
per la predizione delle diramazioni, la quale può essere implementata
in vari modi. La sezione 2.2 discute alcune fra le tecniche
di predizione più comuni.