Esercizio 1 (20%) Si assuma di avere una macchina con 10 registri

Transcript

Esercizio 1 (20%) Si assuma di avere una macchina con 10 registri
Esercizio 1 (20%)
Si assuma di avere una macchina con 10 registri ufficiali (da R0 a R9) e sufficienti registri segreti in
grado di avviare 2 istruzioni per ciclo di clock. Tale macchina richiede 2 cicli di clock per
completare somme e differenze e 4 cicli di clock per completare prodotti e divisioni. Si consideri la
seguente sequenza di istruzioni (dove X è la cifra meno significativa non nulla del proprio numero
di matricola):
(1) RX = R1 - R2
(2) R3 = RX / R5
(3) R4 = R5 + R2
(4) R4 = R7 * R7
Indicare le istruzioni avviate e ritirate in ogni ciclo di clock (dall’inizio al termine dell’esecuzione
del programma) secondo le seguenti strategie di esecuzione (l’uso dei registri segreti è consentito
solo nei casi (B) e (C)): (A) avvio e ritiro in ordine; (B) avvio fuori ordine e ritiro in ordine; (C)
avvio e ritiro fuori ordine. Fornire per ciascuno dei casi una breve spiegazione di ciò che succede in
ogni ciclo con riferimento agli eventuali vincoli tra le istruzioni.
Risposta Sia X=2 (per valori di X diversi la tabella risulta diversa)
Clk
1
2
Decodifica
(1) R2 = R1 - R2
(2) R3 = R2 / R5
(3) R4 = R5 + R2
(4) R4 = R7 * R7
3
4
Avv
(1)
-
(A) In-In
Rit
Commenti
(2) rinviata perché
in RAW con (1)
Avv
(1)
(4)
(1)
(2)
(3)
-
5
(B) Out-In
Rit
(2) rinviata perché
in RAW con (1)
(3) rinviata perché
in RAW con (1), (4)
avviata con uso di
registro segreto S4
(1)
(2)
(3)
(4) rinviata perché
in WAW con (3)
(3) e (4) ritirabili
ma attendono il
completamento di (2)
(2)
(3)
9
10
11
12
13
(C) Out-Out
Rit
(2) rinviata perché
in RAW con (1)
(3) rinviata perché
in RAW con (1), (4)
avviata con uso di
registro segreto S4
(1)
(2)
(3)
6
7
8
Avv
(1)
(4)
(2)
(3)
(4)
(3)
(4)
(2)
(4)
(4)
Esercizio 2 (20%)
Si vuole progettare una cache unificata a mappatura diretta per una CPU con indirizzi a 32 bit e
linee di cache di 32 byte. Supponendo di avere a disposizione una memoria di 4MB e 32 KB di
spazio disponibile massimo sul chip della CPU determinare:
A) la struttura di una possibile slot di cache che soddisfi questi requisiti e la relativa struttura
dell’indirizzo di memoria;
B) le dimensioni totali della cache progettata;
C) se e come sia possibile modificare la struttura determinata al punto A per ridurre le collisioni
sulle slot di cache;
D) cosa può succedere se la CPU vuole leggere il byte 325 della memoria principale.
Risposta
A) Procedendo per tentativi si trova che una slot in grado si soddisfare i requisiti è la seguente:
18 bit
TAG
1bit
V
32 byte
CACHE LINE
a cui corrisponde un indirizzo con la struttura seguente:
18 bit
TAG
9 bit
LINE
5 bit
BYTE
Possibili alternative valide (che però sfruttavano meno lo spazio disponibile) hanno un campo TAG
più grande e un campo LINE più piccolo.
B) Una slot ha dimensione (18+1+32×8)= 275 bit. La cache ha 29 slots e quindi: dimensione della
cache = 29×275 = 512×275 = 140.800 bit = 17.600 bytes ovvero circa 17KB < 32KB disponibili.
Si osservi che scegliendo una slot con TAG di 17 bit si ottiene un campo LINE di 10 bit da cui:
dimensione cache = 210×274 = 1024×274 = 280.576 bit = 35.072 bytes ovvero circa 34KB > 32KB
disponibili che NON soddisfa i requisiti. La stessa cosa vale per valori di TAG inferiori.
C) In generale per ridurre le collisioni o si aumenta il numero di slot (e conseguentemente si riduce
il campo TAG) o si aumentano le “vie” (2-way, 4-way ecc.). Con il vincolo di 32KB di spazio
disponibile però la prima soluzione non era praticabile (vedi punto B) e la seconda nemmeno
(perché richiede sostanzialmente, a parità di numero di slot, almeno il raddoppio delle dimensioni
della cache).
D) Il byte 325 ha indirizzo binario (su 32 bit): 000000000000000000|000001010|00101. Si accede
quindi alla undicesima slot (indirizzo 10) e, se il bit di validità è a 1, si verifica se il TAG della slot
sia 000000000000000000. Se è così si ha un cache hit, si preleva la cache line dalla slot e si accede
al sesto byte (indirizzo 5) che è quello cercato. Altrimenti si ha un cache miss, si preleva
l’undicesima cache line dalla memoria, la si mette in cache nell’undicesima slot e si pone il TAG
della slot a 000000000000000000 e il bit di validità a 1. Infine, si preleva il sesto byte (indirizzo 5)
della cache line che è quello cercato. Tutto questo è realizzato dall’hardware.
Esercizio 3 (20%)
Sia dato un file di testo Regioni.txt le cui righe sono costituite da due stringhe e un intero che
rappresentano rispettivamente una regione, una città (nella regione) e un numero di abitanti (della
città). Scrivere in ANSI C un programma in grado di: (1) creare a partire dal file dato una lista
costituita da record con un campo regione (stringa) e un campo abitanti (intero che specifica il
numero totale di abitanti di quella regione), (2) salvare su di un file Regioni.dat gli elementi di
questa lista, (3) dati in input una regione (stringa) e un numero (intero), sommare nel file
Regioni.dat il numero passato da input al numero di abitanti della regione passata da input.
Una possibile soluzione
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* definiamo i tipi di dato che servono per implementare la lista */
typedef struct {
char nome[20]; // il nome della regione
int n; // il numero di abitanti
} zona;
typedef struct elem* plist;
typedef struct elem {
zona info;
plist next;
} elist;
/* definiamo ora un metodo insert che data la lista e un elemento zona lo inserisce nella lista se
la regione non è presente altrimenti aggiorna il numero di abitanti della regione passata da input;
basta scorrere tutta lista fino a che non trovo una regione il cui nome è uguale a quella dell’input
passato; se arrivo alla fine della lista, dovrò aggiungere il nuovo elemento in fondo */
void insert (plist p, zona z) {
plist p1 = p;
int test = 0;
while ((p1->next != NULL) && (!test)) {
if (strcmp((p1->info).nome,z.nome)) {
test = 1; (p1->info).n += z.n;
}
else p1 = p1->next;
}
if (!test) {
if (strcmp((p1->info).nome,z.nome)) (p1->info).n += z.n;
else {
plist p2 = (plist)malloc(sizeof(elist));
p2->info = z; p2->next = NULL; p1->next = p2;
}
}
}
/* ora implementiamo il metodo crealista() che accede al file Regioni.txt in modo sequenziale e
costruisce la lista iterando il metodo insert */
plist crealista() {
FILE* f = fopen("Regioni.txt", "r");
plist p = NULL;
zona z;
char citta[20];
while (!feof) {
fprintf(f,"%s %s %d \n",z.nome,citta,&z.n); insert(p,z);
}
return p;
}
/* ora implementiamo il metodo che immagazzina nel file Regioni.dat gli elementi della lista così
creata utilizzando un accesso casuale */
void creafile(plist p) {
FILE* f = fopen("Regioni.dat", "wb");
plist p1=p;
while (p!=NULL) {
fwrite(&p1->info,sizeof(zona),1,f);
p1=p1->next;
}
}
/* ora implementiamo il metodo che data una regione
abitanti di quella regione presente in Regioni.dat;
sarebbe stato opportuno aggiungere in fondo al file
metodo) ma la dicitura del testo non lo specificava
versione in cui non aggiunge niente */
e un numero di abitanti aggiorna il numero di
nel caso in cui non esista questa regione
il nuovo elemento (e così sarà implementato il
esplicitamente e quindi è corretta anche la
void aggiorna(char nome[20], int n) {
long pos;
FILE* f = fopen("Regioni.dat", "rb+");
int test = 0;
zona z;
while ((!test) && (!feof)) {
pos = ftell(f);
fread(&z,sizeof(zona),1,f);
if (strcmp(z.nome,nome)) {
fseek(f,pos,SEEK_SET); z.n+=n; fwrite(&z,sizeof(zona),1,f);
test = 1;
}
}
if (!test) {
fclose(f);
f = fopen("Regioni.dat","ab");
strcpy(z.nome,nome);
z.n=n;
fwrite(&z,sizeof(zona),1,f);
}
}
Esercizio 4 (40%)
Indicare in fondo al foglio se le seguenti affermazioni sono vere o false.
A) Si consideri un file di 15.000 record di 320 byte ciascuno, con un campo chiave di 68 byte, sul
quale è stato costruito un indice ISAM. Supponendo di non frazionare mai un record su due blocchi
e di disporre di blocchi di 1K byte con indirizzi di 4 byte, indicare se le seguenti affermazioni sono
vere o false.
@NO In un blocco del file dati entrano 4 record.
@SI Sono necessari 5000 blocchi per memorizzare il file dati.
@NO Ogni record del file indice è lungo 70 byte.
@SI In un blocco del file indice entrano 14 record.
@NO Sono necessari 357 blocchi per memorizzare il file indice.
@SI In ogni blocco del file dati si sprecano 64 byte.
@SI Lo spazio inutilizzato nell’ultimo blocco del file indice è maggiore dello spazio inutilizzato
negli altri blocchi.
@SI L’accesso ad un record di chiave data richiede un solo accesso al file dati.
B) Con riferimento ai linguaggi macchina discussi a lezione:
@SI Il linguaggio macchina della UltraSPARC vede solo 32 registri general-purpose sebbene i
registri fisici siano di più.
@NO Il linguaggio macchina dei Pentium ha a disposizione 16 registri general purpose a 32 bit.
@NO Con il meccanismo di espansione dei codici, il numero di istruzioni a n operandi è
indipendente dal numero di istruzioni a n-1 operandi.
@SI Le istruzioni del linguaggio macchina IA-32 possono indirizzare direttamente una locazione di
memoria principale.
@SI Le uniche istruzioni del linguaggio macchina della UltraSPARC che indirizzano la memoria
sono le LOAD e le STORE.
@SI Nell’indirizzamento diretto si specifica nell’istruzione l’indirizzo di memoria dell’operando.
@NO L’indirizzamento indiretto a registro richiede in generale più bit dell’indirizzamento diretto.
@NO Una istruzione che adotta l’indirizzamento a stack contiene un solo indirizzo.
C) Con riferimento alla memoria fisica, cache e virtuale, indicare se le seguenti affermazioni sono
vere o false.
@NO Nella memoria fisica dati ed istruzioni hanno spazi di indirizzamento separati.
@NO La dimensione di una memoria cache di secondo livello (L2) è paragonabile a quella della
memoria fisica.
@SI La memoria cache di primo livello (L1) dei Pentium relativa alle istruzioni è accessibile in sola
lettura.
@NO Un blocco di memoria presente nella cache di primo livello (L1) è sempre allineato al
relativo blocco in memoria centrale.
@NO Nel Pentium ogni singolo processo vede uno spazio di indirizzamento virtuale pari a 4Gbyte.
@NO Il tempo di accesso ai dati in memoria principale (DRAM) è dell’ordine dei millisecondi.
@SI Utilizzando una politica write through i dati nella cache L1 sono sempre allineati con quelli
della memoria.
@NO Se un blocco è presente nella cache di secondo livello una copia del blocco è presente anche
nella cache di primo livello.
Con riferimento al seguente programma C e supponendo che vengano dati in input i dati “2 2.3
3.2”, indicare se le seguenti affermazioni sono vere o false:
#include<stdio.h>
#include<stdlib.h>
float* GEN(int n) {
float *b = (float*)calloc(n,sizeof(float*)); return b;
}
void main() {
float *b; int i,n; scanf("%d",&n); b = GEN(n);
for (i=0; i<n; i++) scanf("%f",&b[i]);
for (i=0; i<n-1; i++) b[i+1]=b[i+1]+b[i]; printf("%f",b[i]);
}
@SI Nel main la funzione GEN alloca dinamicamente un vettore di 2 elementi.
@NO Non è possibile utilizzare nel programma principale il vettore allocato nella funzione GEN.
@SI Il programma stampa 5.5.
@SI Se avessimo fornito in input la stringa “4 2.2 3.3” avremmo avuto lo stesso output.
@NO Il programma dà un errore durante la compilazione.
@SI L’istruzione (float*)calloc(n,sizeof(float*)); nella funzione GEN può essere
sostituita dall’istruzione (float*)malloc(n*sizeof(float*));
@SI L’allocazione dinamica del vettore b consente di utilizzare solo la memoria strettamente
sufficiente alla memorizzazione dei dati che deve contenere.
@SI Non è possibile allocare staticamente un array la cui dimensione non è nota a priori.
D) Con riferimento alle tecniche adottate nelle architetture con pipeline, indicare se le seguenti
affermazioni sono vere o false.
@SI La tavola di predizione dei salti contiene una linea per ogni istruzione di salto.
@SI Nella micro architettura dei Pentium esiste un’unità dedicata al ritiro delle istruzioni.
@SI Nel Pentium le istruzioni macchina vanno facilmente in conflitto a causa dei pochi registri
ufficiali a disposizione.
@NO Le predizioni di salto statiche non possono essere a carico del compilatore.
@NO La ridenominazione dei registri si adotta per rimediare ai vincoli WAW e RAW tra istruzioni
macchina.
@SI Il ritiro in ordine delle istruzioni macchina garantisce interruzioni precise.
@NO L’unità Dispatch/Execute del Pentium consente di eseguire fino a 10 microistruzioni in
parallelo.
@SI La decomposizione di istruzioni in microistruzioni nelle macchine Pentium è a carico
dell’unità Fetch/Decode.