Università degli Studi di Napoli Federico II Sistemi ad Elevate Prestazioni Prof.re Nicola Mazzocca Lezione 1 0. Introduzione al corso (prestazioni e affidabilità) Per capire le finalità del corso e il filo logico che lega le lezioni, strutturiamo schematicamente le unità didattiche in modo da capire i diversi argomenti affrontati. Il corso di Sistemi ad elevate prestazioni è basato su due moduli fondamentali: - Sistemi ad elevate prestazioni; - Sistemi affidabili; 0.1 Sistemi ad elevate prestazioni La prima grossa novità di questo modulo è che il modello di Von Neumann, che fino ad ora ci ha condotto nella trattazione, risulta essere accantonato per lasciare spazio ad architetture reali che non risultano seguire tale modello. Il modello di Von Neumann assume, quindi, una valenza più logicoastratta che architetturale. Le architetture studiate nei diversi corsi universitari a parte l’MC68000, non risultano essere architetture reali, almeno per quanto riguarda i processori moderni. Quindi ci occuperemo di architetture reali, caratterizzate da precisi accorgimenti sul parallelismo interno e/o sul clock, tali da permettere il miglioramento delle prestazioni. Da un punto di vista pratico nell’ambito dello studio di sistemi ad elevate prestazioni possiamo delineare due diverse soluzioni: - Parallelismo interno: Le architetture che puntano su tale aspetto per incrementare le prestazioni sono: le architetture SuperScalari, i VLIW (Very Long Instruction Word), e i DSP; - Architetture Parallele: caratterizzate dall’aumento del numero di processori presenti nel sistema, in modo da aumentare le prestazioni. Si passa, quindi, dalla soluzione monoprocessore (a parallelismo interno) a più processori. Naturalmente è possibile sfruttare tale soluzione secondo modalità diverse, è possibile avere due processori che collaborano attraverso memoria condivisa, in tal caso si parla di sistema multiprocessore (il problema relativo è quello della gestione della memoria condivisa). Altra soluzione è quella dei sistemi multicomputer, caratterizzata da una comunicazione tra i processori basata su messaggi. Ogni processore è dotato di un sistema di I/O con cui connettersi agli altri; in tal caso il problema sarà gestire la comunicazione attraverso link. Una delle problematiche importanti, che distingue le architetture parallele dalle soluzioni monoprocessore, è la gestione dello stato che può essere centralizzato o distribuito. Nel caso dei sistemi a più processori ho certamente uno stato distribuito e la gestione, quindi, risulta sicuramente più complessa rispetto al caso dei sistemi monoprocessore. In più possiamo allargare maggiormente il discorso andando a sottolineare che sicuramente la gestione dello stato nei sistemi multicomputer risulta più critica rispetto al caso dei sistemi multiprocessore. Per meglio capire quali sono le difficoltà nella gestione dello stato possiamo stilare una breve lista delle principali difficoltà nella gestione distribuita dello stato: - Perdita del riferimento temporale, quindi l’ordinamento temporale degli eventi; - Perdita della mutua esclusione, ogni sistema può elaborare indipendentemente dagli altri mentre in un sistema centralizzato c’è mutua esclusione; - Problema di stallo; - Problema di guasti: devo gestire situazioni in cui solo alcuni delle parti che formano il sistema risultano non funzionanti, mentre il resto continua a funzionare; - Problema di programmazione su sistemi distribuiti, con la possibilità di voler realizzare sistemi single-purpose e multi-purpose. Tutti questi problemi sono problemi che rientrano nel cosiddetto Software di Base. Parte esercitativa relativa al primo modulo del corso: - Tesine (analisi di un processore alla luce della teoria trattata al corso); Esercizi sul dimensionamento delle memorie (Tool Dinero); Programmazione su architetture parallele (Multicomputer). 0.2 Sistemi affidabili La seconda parte del corso cura il problema dell’affidabilità. Quando consideriamo un sistema basato su più oggetti replicati lo si fa o per aumentare le prestazioni o per raggiungere una maggiore affidabilità. In questo caso ci occuperemo di affidabilità nei sistemi ferroviari e nei sistemi avionici. 1. Sistemi ad elevate prestazioni 1.1 Sistemi Monoprocessore Il più importante parametro fra quelli che riguardano le prestazioni dei sistemi (ma non l’unico) è la velocità di elaborazione. Per incrementare la velocità di un sistema possiamo agire sia sull’hardware che sul software, e, per quest’ultimo punto, o sulla fase di programmazione, o su quella di compilazione. Ricordiamo che il ruolo del compilatore è quello di adattare il linguaggio di alto livello alle caratteristiche fisiche della macchina. Se ci limitiamo a considerare architetture a singolo processore, possiamo solo muoverci nella direzione di massimizzare le prestazioni dell’unico processore presente. Prima o poi però ci si trova ad avere a che fare con applicazioni e/o requisiti prestazionali che non possono essere in nessun caso soddisfatti mediante la struttura monoprocessore, e, quand’anche non esistesse questo limite, è solo naturale pensare di incrementare le prestazioni combinando strutture a nodo singolo per ottenere strutture più potenti. Quindi si passa a considerare le architetture parallele. 1.1.1 La tecnica del Pipelining Concentriamoci per ora solo sui sistemi monoprocessore, dove ci sono più unità che evolvono in parallelo. Per poter effettivamente parlare di unità che evolvono in parallelo bisogna accertarsi che il processo elaborativo possa essere sviluppato da unità che elaborano in modo disgiunto. Per fare questo bisogna riferirsi a modelli che possono essere più o meno complessi. Nell’ambito degli studi abbiamo visto due modelli principali, il modello CISC e quello RISC, che differiscono per: - Codici Operativi. Avere più (CISC) o meno (RISC) codici operativi corrisponde ad una maggiore o minore complessità della rete di controllo del processore; - Operandi ammessi dal processore. Per i processori RISC gli operandi per le operazioni aritmetiche sono solo di tipo registro, questo significa che per fare una qualsiasi operazione su di un valore contenuto in memoria bisogna far riferimento al modello load/store, cioè i dati devono essere caricati prima all’interno dei registri del processore per poi essere oggetto del calcolo effettivo. - Modi di indirizzamento. Per i processori RISC abbiamo solo indirizzamento immediato e indiretto, in quanto attraverso questi due modi riesco a coprire tutte le operazioni. Naturalmente su questo ha un grosso peso l’attività di compilazione. Tutto questo ci fa capire che nei processori RISC è meno problematica l’operazione aritmetica rispetto ad un’operazione di I/O, naturalmente si può dire questo con qualche riserva in quanto già se ci si pone di fare un’operazione in aritmetica floating point, queste considerazioni possono cambiare. Questi sono i presupposti da cui partiamo per costruire un sistema monoprocessore basato su pipe, cioè vogliamo costruire un sistema con pochi codici operativi, caratterizzato da codici di load e store, e con pochi modi di indirizzamento. Quindi vogliamo capire ponendoci questi vincoli come possiamo semplificare l’architettura del nostro sistema, poi passeremo a capire se l’architettura determinata possa andare bene anche per i processori CISC, quindi processori non caratterizzati dalle tre proprietà delineate. Un’architettura che può soddisfare i requisiti espressi rispetta delle fasi principali: 1. IF 2. ID 3. EX 4. MEM 5. WB (prelievo (Fetch), interpretazione (Decode), esecuzione (Execution), Memorizzazione ed eventuale Scrittura dei risultati in memoria (Write Back)1) c’è da sottolineare che rispetto alla schematizzazione fatta nei corsi di Calcolatori I e II dove ci si poneva nell’ottica di poter fare operazioni coinvolgendo sia i registri del processore sia la memoria, per le ipotesi fatte, prima della fase di esecuzione non c’è la fase di preparazione degli operandi. Questa fase è mancante perchè gli operandi saranno disponibili nei registri del processore oppure affinché siano disponibili bisogna eseguire un’operazione di load. Le cose più importanti su cui su può agire per migliorare le prestazioni del sistema appena delineato sono: - Aumentare il clock; - Duplicare le risorse hardware (figura 1); - Implementare il parallelismo (all’interno) del nodo o microparallelismo. In realtà la frequenza del clock non può essere aumentata indefinitamente, a causa di un limite massimo dovuto alle proprietà reattive; la seconda soluzione può essere applicata solo per alcuni componenti del processore, per evidenti motivi economici e di spazio; si preferisce, dunque, la terza soluzione. PC TEMPi2 MAR’ MDR’ MAR MDR ID TEMPi3 ALU Registro Stato RC Figura 1 : Schema di un processore RISC LIKE. Come vedremo più avanti il microparallelismo può essere implementato via hardware e/o software e, in quest’ultimo caso, è possibile agire sulla fase di programmazione, o su quella di compilazione. Si può partire dall’idea che se le cinque fasi sono eseguite in modo strettamente sequenziale, ogni unità lavora per una quota parte del tempo di esecuzione della singola (1) (2) (3) (4) (5) istruzione; ad esempio, quando i-1 IF ID EX MEM WB l’istruzione è in fase di i IF ID EX MEM interpretazione, le unità associate alle i+1 IF ID EX altre fasi sono inattive; il processore i+2 IF ID non è, quindi, sfruttato al massimo. tempo 1 Alcune istruzioni non necessitano di alcune fasi, ad esempio, ADD R2, R1 non necessita della fase WB. Quindi per rendere il sistema più veloce è possibile prelevare una nuova istruzione, mentre la precedente è ancora in esecuzione (tecnica del prefetching). Più in generale, è possibile parallelizzare le tutte fasi, implementando la tecnica del pipelining. La tecnica del pipelining permette di diminuire il tempo di esecuzione di un programma, anche se il tempo di attraversamento della singola istruzione non varia. Tempo di attraversamento TA = TIF + TID + TEX + TMEM + TWB Tempo di risposta TR = max {TIF,TID,TEX,TMEM,TWB} In particolare se N sono le fasi, in condizioni ottimali, il tempo di esecuzione del programma diventa pari ad 1/N del tempo di esecuzione dello stesso programma, in caso di esecuzione sequenziale; ovvero il throughput (produttività), diventa N volte maggiore rispetto all’esecuzione sequenziale. 1.1.2. I limiti del pipeling 1° Limite. (Vincolo di tempo) Queste fasi dette ‘in PIPE’ funzionano bene se tutte le unità funzionali impiegano più o meno lo stesso tempo. Quindi la prima ipotesi da fare per garantire un buon funzionamento del pipeling è: ti cost Infatti, se il tempo necessario per una delle unità è significativamente maggiore di quello delle altre, l’intero processore risulterà condizionato dalle prestazioni di tale unità più lenta (come indicato nell’espressione precedente del tempo di risposta): la produttività è legata al tempo massimo. Ora, è naturale che ciò può avvenire solo se le istruzioni eseguibili sono relativamente semplici. Come si vede tale condizione tipica dei sistemi Risc è non, come siamo abituati a pensare, una premessa progettuale, ma una conseguenza architetturale. Un’istruzione singola processata da un sistema di questo genere impiegherebbe naturalmente lo stesso tempo che sarebbe necessario per eseguirla in un sistema tradizionale. La velocizzazione risiede nella possibilità di eseguire più istruzioni in parallelo nel modo che si è spiegato: migliora il throughput (produttività). Ad ogni colpo di clock, difatti, sarà sempre disponibile una istruzione nella fase di esecuzione. Se ad esempio il tempo di risposta (o di ‘fuoriuscita’ dal blocco elaborativo) di una istruzione in un sistema tradizionale è 5*ti, qui diventa ti. ti sarà il tempo impiegato da ciascuna unità funzionale, supposto costante; tale parametro evidentemente può essere migliorato per via elettronica. L’unico inconveniente è far andare a regime la pipe (problema dello startup), solo dopo una fase transitoria che dura 5*ti possiamo dire che il tempo di risposta diviene ti. Il parallelismo ottenuto è a livello di istruzione: fino a 5 istruzioni dello stesso programma, prelevate in tempi successivi, vengono eseguite in parallelo. Fino a questo momento il miglioramento è solo di tipo hardware: programmatore e compilatore sembrano non entrare in gioco. 2° Limite. (Vincolo tecnologico) Dobbiamo imporre che tra le diverse fasi ci debba essere uno stesso clock, quindi questo segnale dovrà viaggiare attraverso un filo, sorgono quindi problemi di natura elettronica, e principalmente il problema dello skew (allungamento) del clock. Quando la frequenza diviene molto elevata, il clock comincia a deformarsi, e la deformazione è tanto maggiore quanto più lunga è la linea di trasmissione. La linea di trasmissione è un circuito induttivo/capacitivo che tende a filtrare le alte frequenze, ovvero quelle che sono responsabili delle variazioni rapide (transizioni Figura 2: Circuito induttivo/capacitivo. Figura 3: Lo skew del segnale di clock. 01 e 10) del segnale. Per conseguenza il segnale di clock si ‘addolcisce’ in corrispondenza delle transizioni. Poiché l’impedenza vale C, maggiore è la frequenza, maggiore è l’impedenza di filtro e più evidente è la deformazione; al limite, il clock si deforma fino a divenire una linea, e gli ultimi elementi della catena delle 5 unità funzionali, che ricevono tutte lo stesso segnale di clock, finiscono col non percepire nulla. Il problema è acuito dalla presenza inevitabile del rumore induttivo. Nelle comunicazioni a grandi distanza si sovracampiona il segnale e si inseriscono bit di controllo per sapere se il segnale è corretto o meno. Per poter quantomeno limitare questo problema, si fa in modo da avere una linea di trasmissione su cui far viaggiare il clock che sia priva di fenomeni capacitivi (problema di tecnologia elettronica), in più è possibile aggiungere tra ogni coppia di unità dello schema uno stabilizzatore, in termini informatici un registro, che sia in grado di acquisire il dato e di mantenerlo stabile durante l’elaborazione. 3° Limite. (Problema di gestione delle istruzioni di salto) Le istruzioni di salto sono utilizzate per cambiare il flusso di esecuzione di un programma; quando si incontra una istruzione di salto bisogna eseguirla completamente (fine fase EX), prima di sapere se il salto deve essere effettuato o meno e, quindi, prima di conoscere l’indirizzo della prossima istruzione da prelevare. La pipe, intanto, continua a caricare le istruzioni in modo sequenziale. Tali istruzioni potrebbero essere esatte o meno; se non lo sono bisogna eliminarle dalla pipe (flush della pipe) e caricare le istruzioni esatte, si ha, quindi, un ritardo. Tale ritardo detto branch penality è molto rilevante se si pensa che in un programma si ha un salto ogni volta che si ha un ciclo o un costrutto condizionale (if-then-else/do-while…ecc); i salti costituiscono, quindi, il 25% circa delle istruzioni eseguite. Le soluzioni adottate per risolvere questo problema sono varie e saranno affrontate in seguito. Questo problema della gestione delle istruzioni di salto è presente sia nei processori CISC che nei processori RISC, però per i RISC il problema è meno rilevante perché i RISC hanno pochi modi di indirizzamento ed operandi quindi fa operazioni più semplici arrivando prima a capire cosa può accadere, mentre nei CISC c’è una maggiore complessità anche nei salti, arrivando dopo a capire il salto. 4° Limite. (Problema di conflitto sui dati) Spesso accade che due istruzioni consecutive cercano di leggere e scrivere contemporaneamente lo stesso registro; ciò potrebbe causare gravi errori. Nei processori CISC i conflitti sui dati sono più probabili, siccome quest’ultimi possono utilizzare come operandi per tutte le istruzioni sia registri del processore che le locazioni di memoria. Il conflitto sui dati è confinato alle ultime tre fasi: EX, MEM e WB. 5° Limite (Problema della gestione delle interruzioni) In un sistema parallelo sono in esecuzione più istruzioni contemporaneamente diventa, quindi, difficile gestire le interruzioni esterne e garantire che le interruzioni interne siano eseguite in ordine. 6° Limite (Problema di conflitti per l’accesso in memoria) ovvero più fasi possono tentare di accedere contemporaneamente alla memoria, per eseguire operazioni di lettura delle istruzioni o scrittura dei dati. La cosa fondamentale sarebbe risolvere ognuno dei problemi elencati nell’ambito della singola fase senza coinvolgere le altre fasi, quindi limitando gli effetti negativi alla singola fase isolandola dalle altre. Torniamo ai due modelli CISC e RISC. Possiamo dire che quanto spiegato fino ad ora è relativo al modello RISC, se cerchiamo di applicare gli stessi concetti al modello CISC ci rendiamo conto che nei CISC quanto descritto per funzionare deve subire delle aggiunte, sicuramente bisogna aggiungere la fase di operand assembly alle 5 già presenti, ma altro inconveniente che capita nei CISC è la variabilità dei tempi che occorre impiegare nelle diverse fasi, cosa che certamente non va a porre rimedio al primo limite evidenziato, quindi nei processori CISC avremo una suddivisione ulteriore di ogni singola fase più lunga, in fasi, in modo da ottenere una pipe più lunga ma con un tempo di esecuzione di ogni fase approssimativamente costante. Naturalmente allungare la pipe non risulta un vantaggio a causa dello startup che si allunga e a causa del maggior numero di informazioni da gestire in caso di errori. Anche da un punto di vista elettronico si ha, a parità di circuiti che realizzano un pezzo della pipe, una diversa occupazione nei processori RISC e CISC, questo porta alla possibilità di avere più registri nei processori RISC in quanto c’è da realizzare meno stadi rispetto ad un processore CISC. 1.1.3. Cache dati e cache istruzioni Il processore lavora ad una frequenza che è fino a 5 volte più elevata di quella di una macchina tradizionale. Le fasi critiche dal punto di vista del tempo di esecuzione sono evidentemente quelle che si interfacciano con la memoria, cioè quelle che abbiamo indicato con WB e IF. Le memorie, rigorosamente sincrone, devono essere dunque molto veloci. Le memorie più veloci che conosciamo sono le memorie cache. CACHE P Si comprende però come, nel momento in cui si esegue una fase di WB per un’istruzione e una IF per un’altra, si verifichi un conflitto (contemporaneità di una operazione di lettura e di una di scrittura in memoria). IF ID EX MEM IF ID EX IF ID IF WB MEM . . . EX . . . ID . . . IF . . . Se quindi utilizziamo una sola cache il modello non funziona perché c’è un conflitto sulla 5° fase. Osserviamo tuttavia che la fase WB riguarda la scrittura di dati, mentre la fase IF il prelievo di istruzioni. Possiamo pensare allora di impiegare due cache: una per le istruzioni e una per i dati. Tale limite quindi viene superato mediante una duplicazione architetturale. Delle due cache, quella dei dati è più critica; infatti le istruzioni sono statiche: possono essere solo lette. Invece i dati sono acceduti in lettura e scrittura, e quindi tutte le tecniche di write back, write through ecc. Processore considerate nel corso di Calcolatori 2 riguardano principalmente la cache dati. Si noti che la cosa si complica enormemente in presenza CACHEist CACHEdati di un processore CISC, le cui istruzioni consentono di operare direttamente su dati all’interno della memoria: ci sarà una ulteriore fase tra le fasi 2 e 3 la quale, consistendo di operazioni di lettura e scrittura in Figura 4 : Le memorie cache per i dati e memoria, provocherà ulteriori potenziali conflitti con le per le istruzioni. altre fasi che accedono alla memoria. A tutto quanto detto bisogna aggiungere che senza pipelining si accedeva alla memoria ogni 5*ti, con la pipe si accede in memoria ogni ti ,quindi le tecnologie su cui si basano le memorie risultano essere molto importanti nell’economia del sistema. 1.1.4. Le Memorie Cerchiamo di capire ora come sono strutturate le memorie e come interfacciamo le memorie ai processori. Lo schema generale da cui partiamo è: R A M Pbus Pbus Ci Cj mA M M U P mA Fra la cache primaria e l’eventuale cache secondaria, e fra quest’ultima e la RAM ci saranno opportuni protocolli di bus. La memoria virtuale con la sua unità di gestione (MMU) risiede nel processore. La MMU converte gli indirizzi logici, con i quali ha a che fare il processore, negli indirizzi fisici di memoria. MMU lavora come è noto secondo un criterio di memoria associativa, producendo un indirizzo fisico a partire da una etichetta. Apriamo una parentesi su di un argomento che vedremo in futuro: Virtual cache. È da notare che in molti casi anche le cache moderne lavorano con un criterio di associatività (virtual cache). Sfruttando il vantaggio di avere la cache primaria integrata sullo Processore stesso blocco del processore, in tale configurazione si fa in modo che la MMU indichi direttamente dove si trova il dato all’interno della cache (se vi è presente). Si Cachedati Primaria fondono cioè le due tabelle associative in una sola, mediante la quale la MMU determina la posizione del Buffer dato nella cache. Ovviamente nel caso in cui il dato non Figura si trovi in cache sarà necessario propagare normalmente Cachedati Secondaria 26(b): l’indirizzo fino alla cache secondaria, o, alla peggio, Esempio 1 fino alla memoria fisica. Tabella di I sistemi moderni, come rappresentato nello schema ad ibernazione Figura 5: Le cache dei dati di primo e inizio paragrafo, prevedono generalmente un doppio secondo livello. . livello di cache dati: la cache primaria (Cj), che risiede sullo stesso chip del processore, al fine di ridurre le distorsioni (skew) e migliorare la propagazione dei segnali, e la cache secondaria (Ci), più lontana dal processore e più capiente, ma meno veloce della primaria. Tra le due cache dati potrebbe nascere un problema di disallineamento dei dati; per evitarlo si utilizza un bus dedicato che, attraverso una politica di Write Through, garantisce sempre il perfetto allineamento tra le informazioni. Il bus dedicato non causa rallentamento del sistema, siccome il trasferimento dei dati tra le due cache è effettuato utilizzando un buffer: il dato, scritto su Cj, è prima bufferizzato e, successivamente, scritto in Ci. Riepilogando, i dati vengono scritti nella cache primaria Cj, che è quella più vicina al processore, dunque è più veloce e, fra l’altro, non presenta problemi di skew; la coerenza con la cache secondaria viene garantita dalla politica di write through, ma le due scritture possono essere differite grazie all’impiego di un buffer. In nessun caso si ha conflitto con il prelievo di istruzioni, che sono contenute in una cache distinta. La velocità di esecuzione di un sistema di calcolo dipende dalla velocità con cui si effettuano gli scambi tra la CPU e la Memoria Principale, in cui dati e programmi sono memorizzati durante l’esecuzione. Le memorie dovrebbero essere veloci, grandi e poco costose, ma ottenere queste tre caratteristiche contemporaneamente è impossibile, perciò i moderni sistemi di calcolo utilizzano più memorie ciascuna con caratteristiche e compiti diversi. Processore Cache Primaria Cacheist. Cache Secondaria Memoria Principale Memoria di massa Figura 6 : La gerarchia delle memorie. La memoria di massa (o Memoria Secondaria) è ad accesso sequenziale o parzialmente sequenziale, quindi, il tempo di accesso alla memoria dipende dalla locazione a cui si deve accedere. Le memorie cache e la Memoria Principale sono RAM (Random Access Memory); in particolare la Memoria Principale è una RAM dinamica (DRAM), capace di mantenere i dati solo per un breve intervallo di tempo, mentre le cache sono RAM statiche (SRAM), capaci di mantenere i dati finchè sono alimentate. Una memoria dinamica può essere immaginata come una matrice nella quale ciascun elemento è individuato dalla coppia di indici (i,j). Ogni riga costituisce una parola della memoria e tutte le celle di una riga sono collegate alla linea di parola , pilotata dal decodificatore di riga. Le celle di ogni colonna sono collegate ad un circuito Sense/Write, tramite 2 linee di bit. I circuiti Sense/Write sono collegati al decodificatore di colonna ed al bus dei dati. Durante un’operazione di lettura/scrittura l’indirizzo, proveniente dal processore, è diviso in 2 parti, la prima utilizzata per selezionare la riga, la seconda utilizzata per selezionare la colonna. linee di bit DECODIFICATORE DI RIGA linea di parola Sense/Write Sense/Write DECODIFICATORE DI COLONNA dati Figura 7 : Organizzazione delle celle di memoria. Prima è applicato l’indirizzo di riga, seguito dall’impulso del segnale RAS (Row Address Strobe), che seleziona la riga; poco dopo è caricato l’indirizzo di colonna, seguito dall’impulso del segnale CAS (Column Address Strobe), che seleziona il circuito Sense/Write interessato. Se l’operazione è di lettura, l’uscita del circuito selezionato è trasferita sul bus dei dati; se, invece, è di scrittura i dati presenti sul bus dati vengono trasferiti nel circuito selezionato. Quando si accede a locazioni di memoria successive, l’indirizzo di riga è caricato una sola volta, mentre gli indirizzi di colonna nei cicli di memoria successivi; la frequenza, quindi, aumenta rispetto agli accessi a locazioni casuali. Questo mi porta ad avere tempi di accesso più lunghi tipo 4 volte il tempo di secondo accesso ad un elemento della stessa riga, cioè il tempo per accedere al primo elemento di una riga risulta essere 4 volte il tempo di accesso per avere gli elementi successivi di una stessa riga. Si è detto che le DRAM sono capaci di mantenere i dati solo per un breve intervallo di tempo è, quindi, necessario riscrivere periodicamente (ogni 216 ms) il contenuto delle celle, prima che esso venga perso definitivamente; questa operazione è detta refresh. 1K 1K 1K 1K BUFFER (1K) BUFFER (1K) carica (a) Figura 8 : L’operazione di refresh. BUFFER (1K) (b) In realtà il refresh fatto sulla singola cella richiederebbe un tempo enorme, risulta perciò conveniente rinfrescare un’intera riga per volta. Supponiamo, ad esempio, di avere un indirizzo lungo 20 bit, diviso in due gruppi da 10 bit; ci saranno, quindi 220 celle, divise in 210 righe e 210 colonne (figura 8). Il refresh consiste nel copiare la riga in un buffer e ricopiarla nella posizione iniziale; il tempo di refresh sarà, quindi, proporzionale a 210, non più a 220. Il buffer può essere realizzato con la tecnologia statica, essendo relativamente piccolo. Una naturale evoluzione del modello consiste nel duplicare i buffer, in modo che mentre una riga caricata nel buffer (o scaricata dal buffer), l’altro buffer possa scaricare nella cache (o caricare dalla cache) il suo contenuto. Quando si applica un indirizzo di riga, sia durante un’operazione di lettura che di scrittura, l’intera riga è rinfrescata. Il circuito di refresh e la CPU sono in competizione per l’accesso in memoria; il circuito di refresh ha, però, priorità maggiore. L’esecuzione del programma subirà, quindi, un ritardo, che dipende dalla modalità di rinfresco: è possibile rinfrescare tutte le righe e poi far tornare la memoria allo stato di funzionamento normale, oppure rinfrescarle un gruppo per volta, in modo da avere tempi di rinfresco più brevi ma, più frequenti. Il rinfresco provoca degrado delle prestazioni della DRAM, che risultano più lente ( 10 volte in più) delle SRAM, che non necessitano dell’operazione di refresh. Alcuni chip incorporano al loro interno il circuito di refresh e perciò sono dette memorie pseudostatiche.