03.09.2015 Views

Segundo parcial Junio 2007

Segundo parcial Junio 2007

Segundo parcial Junio 2007

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Arquitectura e Ingeniería de Computadores<br />

2ō Parcial (Arquitecturas Multiprocesador)<br />

Jueves, 21 de junio de <strong>2007</strong><br />

¡Acuérdate de poner tu nombre en todas las hojas que utilices!<br />

¡Justifica claramente todas tus contestaciones!<br />

SOLUCIONES<br />

1. (3 puntos) Explicar brevemente cada una de las cuestiones que a continuación se plantean<br />

(se valorará la capacidad de concreción del alumno).<br />

a) (0,25 puntos) Dada un multiprocesador formado por varios nodos, cada uno con la estructura<br />

siguiente, explicar a qué categoría o categorías de las estudiadas en clase puede pertenecer la<br />

máquina.<br />

b) (0,25 puntos) ¿Qué significa la expresión speed-up superlineal? ¿Se te ocurre algún caso en que<br />

esto pudiera darse?<br />

c) (0,25 puntos) ¿En qué consiste un directorio jerárquico? ¿En qué se diferencia de un directorio<br />

plano basado en memoria?<br />

d) (0,25 puntos) Explicar la utilidad del estado E para un protocolo de coherencia de caches y el<br />

motivo por el que la inclusión éste es recomendable en arquitecturas SMP comerciales.<br />

e) (0,50 puntos) Para el siguiente fragmento de código explicar si es preferible (se producen menos<br />

fallos de cache) un protocolo de coherencia basado en actualización (DRAGON) o en invalidación<br />

(MESI). Suponer que inicialmente todas las variables están a cero, que flag y A están en líneas<br />

de memoria distintas y que las caches de los procesadores sólo contienen las variables locales de<br />

cada proceso.<br />

P1<br />

P2<br />

int i; int i;<br />

for (i=0; i


g) (0,25 puntos) ¿Qué es el ancho de banda de la bisección de una red? ¿Por qué es importante<br />

esta medida?<br />

h) (0,25 puntos) Explicar el algoritmo de encaminamiento “edge cube” para hipercubos.<br />

i) (0,25 puntos) Explicar el problema de la implementación software centralizada de las barreras<br />

estudiada en clase (ilustrar la explicación con un ejemplo).<br />

j) (0,25 puntos) Explicar el problema más importante que la implementación de los cerrojos basada<br />

en array (array-based lock) tiene en arquitecturas ncc-NUMA y cómo podría ser resuelto.<br />

Solución<br />

a) En primer lugar se trata de un multiprocesador de memoria compartida, puesto que la comunicación<br />

está integrada a nivel del sistema de memoria. Además, es un multiprocesador NUMA<br />

puesto que cada nodo tiene una memoria local “cercana”. Así pues, las categorías a las que podría<br />

pertenecer son cc-NUMA y ncc-NUMA.<br />

b) Significa que la ganancia en velocidad que obtenemos conforme aumentamos el número de procesadores<br />

se incrementa en mayor medida que el número de procesadores. Este fenómeno puede<br />

surgir como consecuencia de que al aumentar el número de procesadores también estamos aumentando<br />

el número de otros recursos (cache, memoria principal, ...), de lo que se pueden beneficiar<br />

algunas aplicaciones.<br />

c) En un directorio jerárquico la información de directorio se organiza en una estructura de datos<br />

lógica de tipo árbol, en la que las hojas representan los nodos de procesamiento, cada uno con<br />

su memoria local, y los nodos intermedios contienen la información de directorio. La diferencia<br />

con un directorio plano basado en memoria es que para éste último la información de directorio<br />

para cada bloque de memoria reside en un lugar fijo y conocido (el nodo home), mientras que<br />

para un directorio jerárquico hay que encontrarla atravesando la jerarquía.<br />

d) El estado E es un estado exclusivo (hay una única copia del bloque de datos en las caches) pero<br />

no propietario (memoria principal está actualizada). Un procesador puede escribir un dato en<br />

estado E sin generar fallo de cache, y por lo tanto permite que un programa secuencial genere el<br />

mismo número de fallos de cache en una arquitectura monoprocesador y en una multiprocesador.<br />

El motivo por el que se emplea en SMPs comerciales es porque uno de los usos más importantes<br />

de éstos es la ejecución de lotes de trabajos secuenciales (máquinas de throughput)<br />

e) El protocolo basado en actualización se comporta mejor. Hay dos variables compartidas: flag<br />

y A. La variable A es escrita por P1 y leída por P2, por lo que un protocolo de actualización<br />

generaría una transacción de Update en cada iteración del bucle (fallo de escritura), mientras<br />

que uno de invalidación generaría 2 (Fallo de escritura + fallo de lectura). Para la variable flag<br />

ocurre algo similar, se escribe y se lee en cada iteración del bucle (por procesadores diferentes),<br />

con lo que un protocolo basado en actualización genera menos fallos.<br />

f) Un modelo relajado de memoria trata de conseguir mejores prestaciones que el modelo de consistencia<br />

secuencial. Concretamente, trata de mantener un modelo de programación simple (aunque<br />

no tanto como la consistencia secuencial) pero permite reordenaciones de determinados accesos<br />

a memoria con el objetivo de mejorar el rendimiento. Para que el programador pueda forzar<br />

explícitamente los órdenes que el modelo relaja (y por lo tanto, se comporte como el modelo de<br />

consistencia secuencial) se incluyen instrucciones especiales en el ISA del procesador.<br />

2


g) Se define como la suma de los anchos de banda del mínimo número de enlaces que separan la<br />

red en dos mitades. Da una idea del ancho de banda máximo de una red de interconexión, ya<br />

que bajo tráfico uniforme la mitad de los mensajes habrán de “cruzar” la bisección.<br />

h) Cada nodo en un hipercubo viene identificado por un número binario. Para hacer llegar un<br />

mensaje desde un nodo origen hasta uno destino se calcula la operación XOR de los identificadores<br />

binarios de origen y destino y se cruzan (en un determinado orden) aquellas dimensiones para<br />

las que el resultado de la operación XOR es 1.<br />

i) El problema es que se puede producir un interbloqueo si se hace uso de la misma variable barrera<br />

en dos puntos del programa. En concreto cuando se libera la barrera en el primer punto, todos<br />

los procesos deben salir antes de que un proceso vuelva a entrar en la misma variable barrera<br />

en el segundo punto. Como ejemplo, podríamos tener que uno de los procesos que alcanzó la<br />

barrera en el primer punto permanece expulsado de la CPU cuando el último proceso en llegar a<br />

la barrera la libera. Si uno de los procesos alcanza el segundo punto del programa antes de que<br />

el proceso anterior haya visto la liberación de la barrera se produce el interbloqueo.<br />

j) El problema es que la dirección de memoria sobre la que un proceso ha de realizar la espera<br />

activa no es conocida a priori en esta implementación de los locks. De esta forma, esta dirección<br />

podría corresponder con una memoria remota, con lo que no podría ser almacenada en la<br />

cache del proceso que realiza la espera activa. Esto ocasionaría una gran cantidad de tráfico<br />

(una transacción de red por cada lectura hecha durante la espera activa). La solución pasa por<br />

modificar la implementación de los cerrojos para asegurar que cada procesador realiza la espera<br />

activa sobre una posición de memoria local. Esto se hace, por ejemplo, en la implementación de<br />

los cerrojos con encolado software (Software Queuing Lock).<br />

2. (3 puntos) Suponer un multiprocesador SMP con 10 procesadores y el protocolo de coherencia<br />

de caches MSI estudiado en clase. Para implementar las barreras se ha optado por la versión software<br />

centralizada con “cambio de sentido” (sense-reversal) estudiada en clase.<br />

a) (0,5 puntos) Explica las variables compartidas necesarias para llevar a cabo esta implementación,<br />

así como el cometido de cada una de ellas. Para cada cada variable, indica también por cuáles<br />

de los procesos es accedida y cómo (por ejemplo, leída)<br />

b) (1 punto) Dado que el multiprocesador proporciona la versión de los cerrojos ticket-lock estudiada<br />

en clase, calcula el número de fallos de cache que se producirían cuando 10 procesos (cada uno<br />

ejecutándose en un procesador diferente) atravesaran una barrera. Para dicho cálculo suponer<br />

que los procesos alcanzan la llamada BARRIER exactamente a la misma vez y que el árbitro<br />

de bus otorga el control del mismo siguiendo un orden FIFO (para las peticiones que llegan al<br />

mismo tiempo el árbitro da prioridad a las de los procesadores con un identificador más bajo),<br />

que inicialmente la cache asociada a cada procesador no almacena ninguna variable compartida<br />

(sí las variables locales al proceso), y que las variables compartidas identificadas en el apartado<br />

a) residen en bloques de memoria diferentes.<br />

c) (0,5 puntos) Cambiamos el protocolo de coherencia MSI por uno MESI optimizado para el patrón<br />

migratorio (implementa la transición M → I para BusRead y el bloque es cargado en estado<br />

E en la cache del procesador que tiene el fallo de lectura 1 ). Bajo las mismas condiciones del<br />

apartado anterior, ¿cuántos fallos de cache se producirían ahora?<br />

d) (0,5 puntos) El ISA de los procesadores de la máquina dispone del par de instrucciones LL y SC,<br />

que podrían ser empleadas directamente en el código de las barreras para ahorrar las llamadas<br />

a los procedimientos de librería LOCK y UNLOCK. Muestra cómo quedaría el código de la<br />

implementación de las barreras en este caso.<br />

1 Notar que esto obliga a notificar a memoria los reemplazos de bloques de datos en estado E<br />

□<br />

3


e) (0,5 puntos) Para el nuevo código de las barreras, ¿cuántos fallos de cache se producirían?<br />

Solución<br />

a) La implementación software de las barreras centralizadas con “sense-reversal” emplea tres variables<br />

compartidas:<br />

counter: variable de tipo entero que se va incrementando con cada proceso que llega a la<br />

barrera. Cuando su valor alcanza el número de procesos se procede a la liberación de la<br />

barrera. Esta variable es leída y escrita por todos los procesos.<br />

lock: variable de tipo cerrojo que es empleada para asegurar el acceso en exclusión mutua<br />

a la variable anterior. Este cerrojo es adquirido y liberado por todos los procesos.<br />

flag: variable de tipo entero usada para realizar la espera ocupada. Todos los procesos la<br />

leen salvo el último en llegar a la barrera, que modifica su valor para notificar la liberación<br />

de la misma al resto.<br />

b) Para calcular el número de fallos de cache que se producen para que todos los procesos logren<br />

pasar la barrera, vamos a mostrar lo que ocurriría para el primer proceso que entra en la misma:<br />

El número de fallos de cache que se producen hasta que el primer proceso logra adquirir el<br />

cerrojo son: 10 como consecuencia de la instrucción fetch&increment (uno por proceso) +<br />

10 como consecuencia de la lectura de now_serving (uno por proceso).<br />

Después, dentro de la sección crítica el proceso leerá y posteriormente escribirá el contenido<br />

del contador compartido, lo que ocasionará 2 fallos de cache con el protocolo MSI de clase.<br />

Finalmente, el lock es liberado mediante una escritura de now_serving que ocasiona un<br />

fallo de cache y el proceso que efectúa la liberación queda realizando la espera activa sobre<br />

el flag compartido, lo que ocasiona un nuevo fallo de cache.<br />

En total se producen 24 fallos de cache. El resto de procesos irán entrando en la sección crítica<br />

conforme vayan viendo que el valor del contador now_serving coincide con el valor de su ticket.<br />

De esa forma el número de fallos como consecuencia de la lectura de now_serving se irá reduciendo<br />

en 1 conforme un nuevo proceso entre en la sección crítica y el número de fallos de cache<br />

para el resto de procesos salvo el último será de ∑ 7<br />

i=0<br />

(13 − i). El último proceso en entrar a la<br />

barrera procede de la misma forma, salvo que en lugar de realizar la espera activa sobre el flag,<br />

escribe esta variable para notificar la liberación de la barrera, así como resetea el contador. Esto<br />

ocasiona 1 fallo de cache para escribir la variable flag. Para resetar el contador, sin embargo, no<br />

se produce fallo de cache, puesto que el proceso ya lo modificó con anterioridad y está en estado<br />

M en su cache. Finalmente, los procesos que están en la espera ocupada sufren 1 fallo de lectura<br />

cada uno para “ver” el nuevo valor de flag.<br />

De esta forma, el número total de fallos de cache es de: 24 + 13 + 12 + 11 + 10 + 9 + 8 + 7 +<br />

6 + 5 + 9 = 114.<br />

c) La sustitución del protocolo MSI de clase por el MESI con la optimización del patrón migratorio<br />

descrita en el enunciado supone las siguientes modificaciones en cuanto a comportamiento se<br />

refiere:<br />

La primera lectura a un bloque de datos hará que se cargue en cache en estado E, y por lo<br />

tanto no ocasionará fallo en caso de que el procesador quiera escribirlo con posterioridad.<br />

4


Cuando un procesador sufre un fallo de lectura para un bloque que otro procesador tiene en<br />

estado M, el bloque de datos se trae en estado E (en lugar de S), con lo que una posterior<br />

escritura por parte del que tiene el fallo de lectura no genera fallo de cache.<br />

De esta forma, nos ahorramos uno de los dos fallos que se producirían en la sección crítica como<br />

consecuencia de la lectura y posterior modificación de la variable counter, dado que la lectura<br />

traería el bloque de datos en estado E, con lo que la escritura posterior no ocasionaría fallo.<br />

De esta forma, el número total de fallos de cache es de: 23 + 12 + 11 + 10 + 9 + 8 + 7 + 6 +<br />

5 + 4 + 9 = 104.<br />

d) El pseudocódigo de la implementación de las barreras con cambio de sentido utilizando el par<br />

LL/SC quedaría como sigue:<br />

struct bar_type {<br />

int counter;<br />

int flag = 0;}<br />

bar_name;<br />

BARRIER (bar_name, p) {<br />

local_sense = !(local_sense);<br />

incr: ll reg1, bar_name.counter<br />

addi reg1, reg1, 1<br />

sc bar_name.counter, reg1<br />

beqz incr<br />

}<br />

if (reg1 == p-) {<br />

bar_name.counter = 0;<br />

bar_name.flag = local_sense;<br />

} else<br />

while (bar_name.flag != local_sense) {};<br />

e) Asumiendo el protocolo MSI, el número de fallos de cache para esta nueva implementación se<br />

ve reducido de manera significativa. Cuando el primer proceso atraviesa la barrera se producen<br />

10 fallos para las instrucciones de LL, 1 fallo para el SC que tiene éxito. Después todos los<br />

procesos salvo éste vuelven a intentar el LL. El proceso que ha logrado aumentar el valor de<br />

counter observaría un nuevo fallo de cache cuando intentase leer la variable flag usada para la<br />

implementación de la espera activa. En total 12 fallos de cache.<br />

De esta forma, el número total de fallos sería: ∑ 9<br />

i=0 (12 − i) + 9 = 84 □<br />

3. (1,5 puntos) Para el siguiente segmento de código indica, justificando la respuesta, cuáles son<br />

los resultados posibles que se imprimirían por pantalla en los siguientes casos (supón que todas las<br />

variables están inicialmente a cero):<br />

P1 P2 P3<br />

A = 1 while (!flag1) {} while (!flag2) {}<br />

flag1 = 1 B = 2 if (!flag1) print (“Error”)<br />

flag2 = 1 else print (A,B)<br />

a) (0,5 puntos) Multiprocesador que implementa el modelo de consistencia secuencial.<br />

5


) (0,5 puntos) Multiprocesador que implementa un modelo de consistencia tipo PSO y preserva<br />

la atomicidad de las escrituras.<br />

c) (0,5 puntos) Multiprocesador que implementa el modelo de consistencia tipo PSO con escrituras<br />

no atómicas.<br />

Solución<br />

a) Bajo el modelo de consistencia secuencial el único resultado que podría dar la ejecución del<br />

programa es la impresión por pantalla del par (A,B) = (1,2). Puesto que la escritura de flag1 y<br />

flag2 se produce después de actualizar los valores de A y B, y además, la escritura de flag2 se<br />

produce después de la de flag1, éste es el único resultado posible.<br />

b) El modelo de consistencia PSO permite que una operación de lectura se complete antes que<br />

una escritura que la precede en el orden de programa, y que escritura a distintas posiciones de<br />

memoria puedan finalizar en desorden. Por otro lado el que las escrituras sean atómicas significa<br />

que son visibles a todos los procesos a la misma vez (una vez un proceso observa el valor de una<br />

escritura ésta es vista también por el resto).<br />

Para nuestro código, la atomicidad de las escrituras asegura que no se va a imprimir el mensaje<br />

de error por pantalla, ya que el hecho de que P2 vea la escritura a flag1 por parte de P1 significa<br />

que P3 también la va a ver tras observar el cambio del valor de flag2. Sin embargo, puesto que el<br />

orden de las escrituras que cada proceso hace no está garantizado de ninguna forma, el programa<br />

podría imprimir por pantalla uno de los siguiente 4 valores para el par (A,B) = {(0,0), (1,0),<br />

(0,2), (1,2)}.<br />

c) Finalmente, si eliminamos la restricción de que las escrituras sean atómicas, además de los<br />

valores para (A,B) mostrados en el apartado anterior, la ejecución del código podría resultar en<br />

la impresión del mensaje de error por pantalla, ya que P3 podría observar la modificación de<br />

flag2 por parte de P2 pero no la de flag1 por parte de P1.<br />

4. (2,5 puntos) Dado un multiprocesador de memoria compartida cc-NUMA con la siguiente<br />

configuración:<br />

El multiprocesador está formado por 16 nodos.<br />

Cada nodo consta de 1 procesador con una frecuencia de 2 GHz, una cache L2 de 1 MB (el<br />

procesador dispone además de caches L1 separadas para datos e instrucciones) y una porción<br />

de 64 GBytes de la memoria total de la máquina.<br />

El tiempo de acceso a memoria es de 150 ciclos de procesador, mientras que acceder a la L2<br />

requiere 15 ciclos de procesador (tanto para accesos locales como remotos).<br />

El tamaño para las líneas de cache L2 es de 64 bytes.<br />

La coherencia de las caches L2 se mantiene empleando el protocolo de coherencia basado en<br />

directorio estudiado en clase (protocolo MSI), extendido con los estados O y E (protocolo<br />

MOESI) y se usa full-map (vector de bits) como código de compartición. Se implementan<br />

las transacciones de red RedUpgr y RedUpgrOK. El directorio se almacena en memoria<br />

principal y el acceso al mismo se realiza en paralelo con el acceso al bloque de memoria<br />

correspondiente. Suponemos además que las escrituras a memoria por parte del controlador<br />

□<br />

6


de memoria (tanto al directorio como a bloques de datos) ocurren instantáneamente. Además,<br />

cuando un fallo de escritura requiere el envío de varios mensajes de invalidación éstos han<br />

de ser enviados en secuencia por parte del controlador de directorio (no envía una nueva<br />

invalidación hasta haber recibido la confirmación para la anterior).<br />

La red de interconexión es una malla 4×4 con encaminamiento X-Y, los enlaces tienen 8 bytes<br />

de ancho y una frecuencia de 500 MHz. Se emplea la estrategia de conmutación de conmutación<br />

de paquetes (store-and-forward), y suponemos que el router no introduce ningún retardo en<br />

los mensajes (solamente los enlaces). El tamaño de un mensaje que no lleva datos es de 8<br />

bytes (para los de datos habría que sumar el número de bytes de datos transmitidos).<br />

Los nodos se numera de izquierda a derecha de arriba a abajo empezando por el cero.<br />

a) (0,75 puntos) Suponer la siguiente secuencia de operaciones de memoria sobre el bloque B<br />

realizada por tres procesadores (las operaciones ocurren en el orden en que aparecen en la<br />

secuencia y una operación no comienza hasta que la que la precede ha finalizado, el nodo origen<br />

para este bloque es el 15). Mostrar el vector de estados en cache del bloque de datos después<br />

de cada operación así como indicar qué operaciones de memoria ocasionarán fallos de L2 y<br />

para éstas mostrar el estado del directorio antes y después de cada fallo de cache, así como<br />

las transacciones de red que generaría el directorio para resolverlo:<br />

r0 w0 r1 r15 w0 r0 r1 w1 r0 r15<br />

b) (0,25 puntos) Calcular la memoria total requerida por la estructura de directorio así como la<br />

sobrecarga de memoria que se introduce (considerar únicamente el código de compartición).<br />

c) (0,25 puntos) Como alternativa a la organización de directorio anterior se considera la utilización<br />

de punteros limitados como código de compartición. Concretamente se dispone de dos punteros<br />

por entrada de directorio y como estrategia de desbordamiento la de eliminar a uno de los compartidores<br />

(el que tenga el bloque en estado S y en caso de empate el más antiguo). Caso de<br />

desbordamiento lo primero que hace el controlador de directorio es liberar el puntero correspondiente.<br />

Calcular la sobrecarga de memoria en este caso (considerar de nuevo únicamente el código<br />

de compartición).<br />

d) (0,5 puntos) Repetir el apartado a) suponiendo la organización para el directorio del apartado<br />

anterior.<br />

e) (0,75 puntos) Vamos a calcular el impacto que sobre el rendimiento tiene el esquema de punteros<br />

limitados anterior. Para ello vamos a usar como métrica el tiempo de directorio medio por fallo<br />

de L2 (se define como el número total de ciclos de procesador que el directorio emplea en<br />

resolver todos los fallos de L2, dividido entre el número total de fallos resueltos). Calcula el<br />

tiempo de directorio medio por fallo de L2 para ambas organizaciones de directorio, e indica qué<br />

organización es mejor y por cuánto.<br />

Solución<br />

a) La siguiente tabla resume la información pedida. Los distintos accesos a memoria han sido<br />

numerados según la posición que ocupan en la secuencia. Los aciertos en cache han sido marcados<br />

como hit. En cursiva se muestran las transacciones de red que no son generadas por el directorio,<br />

sino por las caches en respuesta a una solicitud por parte de éste.<br />

b) Cada nodo tiene una porción de 64 GB de la memoria total y el tamaño de la línea de cache es<br />

de 64 bytes. De esta forma, el número total de líneas de memoria para cada nodo es de<br />

7


Estado<br />

Directorio Directorio en caches<br />

antes después (P 0 , P 1 , P 15 ) Transacciones de red<br />

(1) r0 NC {} P {P 0 } (E,I,I) RedDato<br />

(2) w0 Hit (M,I,I) –<br />

(3) r1 P {P 0 } O {P 0 , P 1 } (O,S,I) RedBusc → RedBuscOK<br />

(4) r15 O {P 0 , P 1 } O {P 0 , P 1 , P 15 } (O,S,S) RedBusc → RedBuscOK<br />

(5) w0 O {P 0, P 1, P 15} P {P 0} (M,I,I) RedInv 1 → RedInvOK 1 →<br />

RedInv 15 → RedInvOK 15 → RedUpgrOK<br />

(6) r0 Hit (M,I,I) –<br />

(7) r1 P {P 0} O {P 0, P 1} (O,S,I) RedBusc → RedBuscOK<br />

(8) w1 O {P 0 , P 1 , P 15 } P {P 1 } (I,M,I) RedInv 0 → RedInvOK 0 → RedUpgrOK<br />

(9) r0 P {P 1 } O {P 0 , P 1 } (S,O,I) RedBusc → RedBuscOK<br />

(10) r15 O {P 0 , P 1 } O {P 0 , P 1 , P 15 } (S,O,S) RedBusc → RedBuscOK<br />

64×2 30 Bytes<br />

64Bytes<br />

= 2 30 .<br />

Cada entrada de directorio contiene un vector de bits (16 bits, uno por nodo) con el que se<br />

identifica a todos los compartidores. De esta forma, la cantidad de memoria total por nodo para<br />

el directorio será de 2 30 × 2 = 2 31 Bytes. Multiplicando dicha cantidad por el número total de<br />

nodos obtenemos que la cantidad de memoria para el directorio en todo el multiprocesador es<br />

de 32 GB.<br />

La sobrecarga de memoria considerando únicamente el código de compartición la podemos obtener<br />

dividiendo el tamaño del mismo entre el tamaño de la línea de cache, o lo que es lo mismo<br />

2Bytes<br />

64Bytes<br />

= 0, 03125 → 3, 125 %.<br />

c) La sobrecarga de memoria en este caso (de nuevo considerando únicamente el código de compartición)<br />

la podemos obtener dividiendo el tamaño del nuevo código de compartición (2 punteros)<br />

entre el tamaño de la línea de cache. Puesto que la máquina cuenta con 16 procesadores, cada<br />

puntero tendrá log 2 16 = 4 bits, con lo que los dos punteros suman 1 Byte. De esta forma<br />

nos queda que la sobrecarga de memoria se reduce a la mitad con respecto a la que teníamos<br />

originalmente:<br />

1Byte<br />

64Bytes<br />

= 0, 015625 → 1, 5625 %.<br />

d) Los accesos a memoria que se verían afectados por el cambio en la estructura del directorio son<br />

los marcados con los números (4), (5) y (10). Para (4) y (10) el número de compartidores final<br />

excede el número de punteros disponibles, por lo que para poder proporcionar la copia del bloque<br />

de datos en cada uno de esos accesos hay que invalidar primero a uno de los dos compartidores<br />

ya existentes. Por su parte, el acceso (5) necesita enviar una invalidación menos.<br />

Estado<br />

Directorio Directorio en caches<br />

antes después (P 0, P 1, P 15) Transacciones de red<br />

(4) r15 O {P 0, P 1} O {P 0, P 15} (O,I,S) RedInv 1 → RedInvOK 1 →<br />

RedBusc → RedBuscOK<br />

(5) w0 O {P 0, P 15} P {P 0} (M,I,I) RedInv 15 → RedInvOK 15 → RedUpgrOK<br />

(10) r15 O {P 0, P 1} O {P 1, P 15} (I,O,S) RedInv 0 → RedInvOK 0 → RedBusc → RedBuscOK<br />

e) Calculamos ahora el número de ciclos de procesador que emplea el directorio en resolver cada<br />

fallo de L2 para el esquema de directorio original:<br />

(1) r0: en este caso el fallo lo resuelve una vez ha obtenido el bloque de datos de memoria<br />

principal (según nos dice el enunciado éste se obtiene a la misma vez que la información de<br />

directorio) → 150 ciclos.<br />

8


(3) r1: una vez se obtiene la información de directorio se pasa a buscar la copia del bloque<br />

del procesador 0 (es la única válida). Ello requiere enviar la transacción de red de RedBusc<br />

del nodo 15 al 0, que según el encaminamiento X-Y supondrá atravesar 6 enlaces de la red,<br />

después habrá que acceder a la cache remota para buscar el dato y finalmente la recepción<br />

por parte del directorio de la respuesta al mensaje de búsqueda (por la semántica del estado<br />

O este mensaje no llevará copia del bloque de datos) dará por finalizado el fallo. De esta<br />

manera, el número total de ciclos de procesador necesarios:<br />

150 + 6 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 6 × 1 × 4 = 150 + 24 + 15 + 24 = 213 ciclos de<br />

procesador.<br />

(4) r15: al igual que en caso anterior, una vez se obtiene la información de directorio se<br />

pasa a buscar la copia del bloque del procesador 0 (que es el que tiene el dato en estado O).<br />

De esta manera, el número total de ciclos de procesador coincide con el del caso anterior:<br />

150 + 6 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 6 × 1 × 4 = 150 + 24 + 15 + 24 = 213 ciclos de<br />

procesador.<br />

(5) w0: en este caso anterior, una vez se obtiene la información de directorio se pasa a<br />

invalidar las copias del bloque de los procesadores 1 y 15. Ello requiere enviar dos mensajes<br />

de invalidación desde el nodo 15, que además habrán de ser serializados según dice el enunciado<br />

(el segundo mensaje no se envía hasta que la confirmación de la primera invalidación<br />

ha sido recibida por el directorio). El envío de la invalidación al nodo 1 require atravesar 5<br />

enlaces, después habrá que acceder a la cache remota para invalidar y finalmente la recepción<br />

por parte del directorio de la respuesta a la invalidación hará que se envíe la segunda<br />

invalidación al nodo 15. En este caso no hay que salir a la red puesto que la invalidación<br />

va dirigida a la cache local. La respuesta a esta invalidación dará por finalizado el fallo. De<br />

esta manera, el número total de ciclos de procesador necesarios:<br />

150+5× 8Bytes<br />

8Byte<br />

×4+15+5×1×4+15 = 150+20+15+20+15 = 220 ciclos de procesador.<br />

(7) r1: al igual que en caso (3), una vez se obtiene la información de directorio se pasa a<br />

buscar la copia del bloque del procesador 0 (que es el que tiene el dato en estado O). De<br />

esta manera, el número total de ciclos de procesador coincide con el del caso anterior:<br />

150 + 6 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 6 × 1 × 4 = 150 + 24 + 15 + 24 = 213 ciclos de<br />

procesador.<br />

(8) w1: este caso es similar al (5), una vez se obtiene la información de directorio se pasa a<br />

invalidar la copia del bloque del procesador 0. El envío de la invalidación al nodo 0 require<br />

atravesar 6 enlaces. De esta manera, el número total de ciclos de procesador necesarios:<br />

150 + 6 × 8Bytes<br />

8Byte<br />

× 4 + 15 + 6 × 1 × 4 + 15 = 150 + 24 + 15 + 24 = 213 ciclos de procesador.<br />

(9) r0: de manera similar al caso (3), una vez se obtiene la información de directorio se<br />

pasa a buscar la copia del bloque del procesador 1. De esta manera, el número total de<br />

ciclos de procesador sería:<br />

150 + 5 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 5 × 1 × 4 = 150 + 20 + 15 + 20 = 205 ciclos de<br />

procesador.<br />

(10) r15: igual que en caso anterior, una vez se obtiene la información de directorio se pasa<br />

a buscar la copia del bloque del procesador 1. De esta manera, el número total de ciclos de<br />

procesador coincide con el del caso anterior:<br />

150 + 5 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 5 × 1 × 4 = 150 + 20 + 15 + 20 = 205 ciclos de<br />

procesador.<br />

Por lo tanto, el tiempo de directorio medio por fallo de L2 para el caso del directorio full-map<br />

es 150+213+213+220+213+213+205+205<br />

8<br />

= 204 ciclos de procesador.<br />

Para el caso del directorio con punteros limitados tan sólo cambia el tiempo de directorio para<br />

los accesos (4), (5) y (10):<br />

9


(4) r15: antes de poder enviar el RedBusc hay que invalidar la copia en el nodo 1 para<br />

liberar el puntero. Esto supone añadir los siguientes ciclos a los 213 que ya teníamos:<br />

213 + 5 × 8Bytes<br />

8Bytes<br />

× 4 + 15(cacheremota) + 5 × 1 × 4 = 213 + 20 + 15 + 20 = 268 ciclos de<br />

procesador.<br />

(5) w0: puesto que el acceso anterior supuso la invalidación de la copia del nodo 1, estos<br />

ciclos nos los ahorramos ahora:<br />

220 − (5 × 1 × 4 + 15 + 5 × 1 × 4) = 165 ciclos de procesador.<br />

(10) r15: al igual que para el acceso (4), antes de poder enviar el RedBusc hay que invalidar<br />

la copia en el nodo 0 para liberar el puntero. Esto supone añadir los siguientes ciclos a los<br />

213 que ya teníamos:<br />

205 + 6 × 1 × 4 + 15(cacheremota) + 6 × 1 × 4 = 205 + 63 = 268 ciclos de procesador.<br />

Por lo tanto, el tiempo de directorio medio por fallo de L2 para el caso del directorio con<br />

punteros limitados es 150+213+268+165+213+213+205+268<br />

8<br />

= 212 ciclos de procesador, con lo<br />

que el rendimiento se degrada un 3,9 %.<br />

□<br />

10

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!