Prestazioni di un Calcolatore

Quando parliamo di prestazioni, quello che ci interessa è il tempo di esecuzione.Se voglio confrontare due calcolatori conta anche il compilatore, perchè chiaramente un compilatore ottimizzato fa la differenza anche in termini di prestazioni.

Volendo confrontare due calcolatori non devo farlo con lo stesso programma, perchè programmi diversi, con caratteristiche diverse potrebbero avere risultati diversi su calcolatori diversi.

Normalmente si usano dei benchmark, cioè un insieme di programmi riconosciuti, come standard da parte della comunità scientifica e industriale per fare queste valutazioni.Non si guarda il singolo programma ma il comportamento su un insieme di programmi.

Sono divisi in due macroclassi: programmi che lavorano con numeri interi e quelli con i numeri reali e spaziano tra programmi che hanno calcoli più complessi e programmi che sono invece più interattivi, ci sono anche programmi usati per le simulazioni elettriche(esempio SPICE).

Se voglio confrontare due calcolatori, che eseguono le stesse prove, devono essere calcolatori che hanno stesso ISA possibilmente ma con implementazioni diverse(è quello che idealmente si dovrebbe fare).

I benchmark sono visibili e si chiamano SPEC(Standard Performance Evaluation Corporation), che cambiano nel tempo perchè si cerca di ottimizzare i compilatori per fare queste prove ma poi non è detto che per il mondo “reale” queste ottimizzazioni siano anche utili.

Confrontare due calcolatori con ISA diverse, è evidente che le cose potrebbero essere molto diverse, cioè il confronto è abbastanza complicato.

PRESTAZIONI DI UN PROCESSORE GENERICO

Iniziamo con il dire che utilizzeremo un programma P per eseguire i test.NON verranno considerati i tempi per l’I/O e non si considera il SO, si considera solo quel programma P.

La relazione fondamentale tra i parametri del processore è la seguente:

T(P)=cicli(P)×CK=cicli(P)FREQT(P)=cicli(P)\times CK=\frac{cicli(P)}{FREQ}

esempio: se un certo P ha impiegato un T(P) pari a 10 secondi, su un processore che gira a 2GHz…

T(P)=10s,FREQ=2GHz=>cicli(P)=10s×2×109=20 mlrd di cicliT(P)=10s ,FREQ=2 GHz=>cicli(P)=10s\times2\times 10^{9}=20\space mlrd \space di \space cicli

Ma, se non ho il tempo di esecuzione, come si procede a calcolare cicli(P)?

Questo dipende dal numero di istruzioni che eseguo e da quanto ci metto ad eseguire ogni singola istruzione(quanti cicli di clock per istruzione).

Viene definito un parametro, detto CPI(Clock Cicle Per Instruction) che è il valore medio quindi del numero di cicli speso per ogni istruzione.

CPI=cicli totalinumero istruzioniCPI=\frac{cicli\space totali}{numero \space istruzioni}

Quindi posso riscrivere il T(P) come:

T(P)=CPI(P)×NI(P)FREQT(P)=\frac{CPI(P)\times NI(P) }{FREQ}

dove NI(P) è il numero totale delle istruzioni del programma.

esempio:

Supponiamo di voler confrontare due implementazioni di un processore, che hanno la stessa ISA,con lo stesso compilatore.

Devo confrontare i tempi di esecuzione; sia N il numero di istruzioni complessive del programma, allora il numero di cicli di clock sarà:

cicliA=N×2cicli_{A}=N\times 2
cicliB=N×1.2cicli_B=N\times1.2
TA(P)=cicliA×250psT_A(P)=cicli_A \times 250ps
TB(P)=cicliB×500psT_B(P)=cicli_B\times500ps

se notiamo bene però senza vedere il numero di istruzioni, già possiamo capire quale sarà la CPU più veloce, sostituendo con l’espressione del numero di cicli:

TA(P)=N×2×250ns=500×NT_A(P)=N\times 2 \times 250ns=500\times N
TB(P)=1.2×250×N=600×NT_B(P)=1.2\times250 \times N=600\times N

Quindi indipendentemente da N, T_B sarà sempre maggiore.

Attenzione però al fatto che un programma diverso potrebbe avere un CPI diverso, infatti il CPI è legato al programma.Un programma diverso potrebbe avere un CPI diverso, non è una caratteristica della macchina, ma più una caratteristica del programma eseguito su quella macchina.

Come confronto le prestazioni? faccio il rapporto del tempo di b su quello di a.Ottengo:

T(P)=600×N500×N=1.2T(P)=\frac{600\times N}{500 \times N}=1.2

cioè a è 1.2 volte più veloce di b.

Prestazioni(A)=TB(P)TA(P)Prestazioni(A)=\frac{T_B(P)}{T_A(P)}

In una pipeline ideale, perfetta, senza stalli quindi, terminiamo una istruzione ad ogni ciclo di clock, quindi CPI=1 (tolto il tempo di riempimento e svuotamento della pipeline),non prendo tutti e 5 i cicli di clock impiegati, perchè ho comunque che ogni ciclo di clock una istruzione termina(sempre nell’ipotesi in cui non ci siano stalli).

Se ci sono dei conflitti di dato ci sono poi degli stalli, che devo considerare.Li conteggio vedendo quanti cicli di clock perdo nell’esecuzione di quel programma.

Se la pipeline presenta degli stalli, si ha che il CPI non è più 1, e dobbiamo considerare:

4 è il tempo di riempimento della pipeline.

CPI(P)=cicli(P)NI(P)=NI(P)+stalli(P)NI(P)CPI(P)=\frac{cicli(P)}{NI(P)}=\frac{NI(P)+stalli(P)}{NI(P)}
T(P)=NI(P)×CPI(P)FREQT(P)=\frac{NI(P)\times CPI(P)}{FREQ}

esempio:

Ipotesi comuni:

Caso A: nessuna anticipazione (3 stalli) per ogni branch

fattore di rallentamento pari a 1,51 rispetto al caso ideale

Caso B:

Caso C come B, ma con predizione branch untaken,

con probabilità di predizione giusta = 50 %:

fattore di rallentamento pari a 0,085 rispetto al caso ideale

Quindi con il branch untaken salto il 50% del 17% di tutti i branch.

Prestazioni e memoria cache

In tutto ciò però manca una parte: la memoria.

Se la cache è ideale,

cioè che al 100% trovo i dati li, allora non devo considerare nessun rallentamento dovuto a miss.

Altrimenti, in caso di cache reale, dobbiamo calcolare gli stalli dovuti ai miss della cache, e quindi il fatto che quando non trovo il dato in cache lo devo andare a cercare in memoria centrale.

Se la memoria cache è reale e quindi presenta dei MISS, allora la pipeline va stallata per un numero di cicli di clock pari al tempo per gestire il MISS.

T(P)=cicli(P)+stalliM(P)FREQT(P)=\frac{cicli(P)+stalliM(P)}{FREQ}

Come faccio a definire il numero di stalli dovuti alla memoria cache?

Prendo h=HIT RATE (nb. è la frequenza di HIT), se necessario lo divido per hI e hD, per distinguere tra istruzioni e dati(quindi ci sarà un h della memoria istruzioni e una h della memoria dati).

Poi si prende l’ HIT TIME(cioè il tempo di accesso a una parola in memoria cache)

m = MISS rate = 1 - h (frequenza di eventi di MISS), cioè 1 meno il tasso di fallimento.

M= MISS PENALTY è il tempo di caricamento del blocco dalla memoria centrale alla memoria cache.Ricordiamo che quando c’è un miss, si mette in stallo la pipeline, si porta in cache il dato dalla memoria centrale e si riesegue l’istruzione.

Tempo di accesso medio alla memoria: HIT TIME+(m*M)

stalliM (P) = numero stalli causati da cache = stalli in lettura + stalli in scrittura

Questo perchè ovviamente posso avere dei miss sia facendo il fetch dell’istruzione sia una load o una store.

Supponiamo che il MISS Penalty è uguale sia in lettura che in scrittura e si assume la politica Write Through, cioè quando scrivo scrivo sia in cache che in memoria centrale.Ovviamente se uso un’altra politica, come la Write Back , il problema sarebbe che qualunque miss potrebbe risultare con un miss penalty doppio, perchè devo fare un doppio accesso(scrivo sia in cache che in mem centrale).

Il numero di cicli di clock di stallo per la memoria dipende da quanto tempo ci metto ad andare in memoria.Stiamo inoltre trascurando il tempo di scrittura in memoria RAM perchè ci sono dei meccanismi che lo gestiscono separatamente.

Il numero di stalli dovuti ai miss della memoria sono quindi dovuti da:

stalliM(P)=n×m×MstalliM(P)=n\times m \times M

Il miss penalty è il tempo necessario per caricare un blocco ed è quindi linearmente proporzionale al numero di parole che ho nel blocco.Ecco come calcolare il MISS PENALTY:

M=dimensione  blocco(in parole)×tempo accesso parola in mem.centraleM=dimensione\space \space blocco(in \space parole)\times tempo \space accesso \space parola \space in\space mem.centrale

Per dimensione del blocco si intende quello che riesce a portare il BUS in cache.

miss rate della memoria istruzioni(mI),miss rate della memoria dati(mD).

Esempio di pipeline con memoria cache

Parametri di cache e processore noti:

Determiniamo il CPI con cache reale (ossia con eventi di MISS):

Confronto tra CPI con cache reale e ideale (ossia senza MISS):

Se si accelera la pipeline riducendone il CPI (via forwarding elimina i conflitti di dati):

Il 2% di tutte le istruzioni richiede 100 cicli di clock per andare in memoria(M, miss penalty).

Ovviamente poi si moltiplica il 2%(o 4% per la mD) per il numero di istruzioni totali per il miss penalty per ottenere il numero di cicli per miss in cache istruzioni(dati).

TEMPO DI ACCESSO MEDIO ALLA MEMORIA(AMAT)

🔑
PAROLE CHIAVE
  • throughput: indica il numero di task eseguiti nell’unità di tempo
  • tempo di risposta:tempo passato dall’inizio al completamento di un task
  • tempo di CPU:tempo speso dal processore ad eseguire il task.Non comprende I/O, tempi di accesso in memoria RAM
  • tempo di CPU utente:tempo speso dalla CPU ad eseguire effettivamente il programma lanciato dall’utente
  • tempo di CPU di sistema: tempo speso dalla CPU ad eseguire le funzioni del sistema operativo richieste dal programma

diminuire il tempo di esecuzione di un task significa quasi sempre aumentare il throughput. Se aggiungo processori per svolgere contemporaneamente dei task, non modifico il tempo di esecuzione, ma il throughput, che aumenta.

Il tempo di esecuzione o tempo assoluto è il tempo totale richiesto per completare un task, comprendendo anche il tempo di accesso in memoria(centrale e disco) e I/O, in sostanza quanto ci vuole a completare il task considerando tutto.