##¿Que es una memoria cache? Este tipo de memorias, junto con el pipeline y el advenimiento de las arquitecturas RISC constituyen una de las mejoras sucesivas al modelo de Von Neumann (Seccion 1.14). El bajo costo y crecimiento vertiginoso en la velocidad de los procesadores en relacion con los Mhz de sus pulsos reloj, no ha sido acompañado historicamente en igual medida por las memorias a las que ellos acceden. Asi en el periodo en que los Mhz de las UCP pasaron de 100 a 50, las DRAMS solo mejoraron de 100 a 70 nseg. Se necesita que las memorias a las que las UCP acceden sean baratas, de gran capacidad de almacenamiento,y que puedan suministrar instrucciones y datos tan prontamente como las UCP pueda procesarlos (en el tiempo de un ciclo de reloj de una cpu). Tambien deben permitir gran "ancho de banda" (bytes transmitidos por segundo).
Las memorias "cache" ubicadas entre la UCP y la memoria principal (fig. 1.77.a), de pequeña capacidad en relacion con esta, pero varias veces mas rapidas, son una solucion de compromiso entre costo y velocidad. Contienen las instrucciones y datos de memoria a los que la UCP accedio ultimamente, siendo tambien a los que mas probablemente accedera proximamente, como se discute a continuacion "Cache" significa oculta,escondida,en el sentido que la UCP envia una direccion por el bus de direcciones desconociendo la existencia del cache,que es un hardware tambien oculto al programador.
En general esta en los niveles de los procesos de datos se trata que el acceso a la informacion requerida sea rapido y economico. Para tal fin en los procesos de datos se tiene en cuenta el principio de localidad o proximidad, el cual estipula que si ya se consulto informacion,es muy probable:
- que la misma pronto sea consultada otra vez (localidad o proximidad temporal)
- que pronto se consulte informacion cercana,vecina a ella (localidad o proximidad espacial)
Por ejemplo, la apertura de archivos de un computador ha sido concebida de acuerdo con este principio. Asi, cuando en el Word abrimos un archivo, y luego lo cerramos, si enseguida o en otra oportunidad queremos abrir un archivo, el nombre del ultimo archivo cerrado sera el primero en aparecer en una lista ordenada de los mas recientes archivos consultados. De este modo se estima que es muy factible que volvamos a consultarlos (proximidad temporal). Por otro lado, si abrimos un archivo de una carpeta, y luego pedimos abrir otro, el Word automaticamente mostrara dicha carpeta (proximidad espacial), pues en la mayoria de los casos el archivo buscado es uno de la carpeta en uso, (proximidad espacial). En ambos casos se evita que el usuario abra carpetas innecesariamente, pudiendo asi acceder mas rapidamente a la informacion que necesita.
Vale decir, que del conjunto de todos los archivos almacenados en el disco rigido no se accede a todos ellos con igual probabilidad, sino que generalmente se consulta un subconjunto que pertenecen a una misma carpeta o a unas pocas en relacion con todo el disco; y ademas se accede a ellos repetidamente. Tambien en el caso de la memoria principal, en cualquier lapso breve de tiempo en los accesos y es corriente acceder repetidamente a esas direcciones (proximidad temporal).
Los programas constan de secuencias de instrucciones que estan en direcciones consecutivas de memoria, siendo frecuente que secuencias se vuelvan a ejecutar n veces, dando lugar a los "ciclos". Lo primero implica que es muy probable que las direcciones de dos intrucciones que se ejecutan una tras otra sean muy cercanas.
A su vez, los datos que estas instrucciones procesan, si contituyen elementos ordenados de un vector o una matriz, o los cercanos a la cima de una pila, se encuentran vecinos en una zona acotada de memoria, y los programas ordenan operar una y otra vez sobre estos datos.
Por lo tanto, la ejecucion de un programa se va realizando en secuencias de instrucciones relativamente cortas, que mayormente se ejecutan muchas veces, siendo que tambien los datos que cada secuencia procesa estan en direcciones proximas, los cuales asimismo en general son accedidas repetidamente. En este caso tambien resulta para un conjunto de instrucciones y datos a procesar almacenados en memoria, que sus elementos no son accedidos con igual probabilidad;sino que durante cada lapso del proceso de datos (que ellas operan), localizados en dos zonas reducidas de memoria principal (cuyos espacios de direcciones varian a medida que se ejecuta el programa). En especial se accede a bloques de datos de gran longuitud en el procesamiento de textos,planillas y multimedia.
Los contenidos de estas dos zonas DRAM que almacenan instrucciones y datos que la UCP necesita acceder por estar procesandolos o para procesarlos proximamente, se copian en una memoria SRAM pequeña (como ser 512 KB o 1 MB frente a 128 MB de la DRAM) pero de acceso mucho mas rapido para la UCP que la DRAM: "el cache" o "antememoria". De este modo la UCP leera del cache las intrucciones y datos mas rapidamente que de memoria ,sin necesidad de acceder a ella.
Desde otra perspectiva, un cache permite simular una memoria principal DRAM de gran capacidad, pero con un tiempo de acceso semejante al de la SRAM de la cache. Este tiempo no debe superar el lapso T que media entre un pulso reloj y el siguiente, a fin que la UCP no se quede "esperando" inactiva mas de un pulso reloj. Cada pulso extra de espera ("wait state") en cada lectura o escritura, implica una perdida de performance de la UCP. Esto se manifiesta en un mayor tiempo en la ejecucion de los programas.
Asi,mientras los procesadores como el 80286 no superaban los 10 Mhz,o sea periodo T = 100 nseg , (seccion 1.7) ,dado que el tiempo de acceso de una DRAM entonces era de unos 90 nseg,en general no superaba dicho tiempo T. Pero ya en el 80386 de 33 Mhz, o sea T = 30 nseg ,el acceso a la DRAM apenas bajo a 70 nseg,superando el tiempo T (sin contar el tiempo que suma el controlador de memoria) , por lo que se uso un cache externo (LEVEL 2 = L2) para minimizar los "wait states". Con el 80846 rondando los 100 Mhz (T = 10 nseg) el acceso a un cache L2 superaba dicho T ,debiendose incorporar un cache dentro del 486 (LEVEL1 = L1) , usando un L2 para acceder mas rapido a este en lugar de la memoria, si la informacion a acceder no estaba en L1. Estos dos niveles de cache se usan hoy en dia para un mejor rendimiento , pudiendo existir mas niveles.
Un cache guarda en las celdas que constituyen sus "lineas" un subconjunto de bloques de la memoria. Cada linea almacena un bloque de bytes consecutivos de la memoria (por ejemplo 16 o 32). El cache requiere un subsistema circuital complejo denomidado controlador de cache que cumple varias funciones, siendo las mas importantes:
a. Interpreta la direccion que envia la UCP por el bus de direcciones a fin de determinar si el contenido correspondiente a ella esta (acierto= hit ) o no (fallo = miss ). En el primer caso permitira que la UCP acceda al cache, y en el segundo a la memoria con la consiguiente perdida de tiempo. Para tal determinacion cuenta con una rapida memoria auxiliar: la tag "memory".
b. En los caches con correspondencia asociativa, decide cual bloque sera reemplazado por otro proveniente de memoria cuando ocurre el fallo.
c. Implementa la forma en que los resultados obtenidos por la UCP se guardaran en memoria.
###¿Cómo es la estructura de un caché de correspondencia directa?
Mientras que un chip de memoria está organizado como una sucesión de celdas independientes que pueden guardar un byte, identificable cada una por su dirección (fig. 1.77.a), un caché se organiza en un conjunto de líneas que típicamente guardan un bloque de 16 ó 32 bytes cada una. Cada línea se identifica y localiza en el caché por su número de "entrada" o "índice", que viene a ser como su dirección para localizarla en la SRAM. El número de líneas es una potencia de dos.
A los fines didácticos supondremos (fig. 1.77.b) una memoria de 2^6^ bytes (direcciones 000000 a 111111), y un caché con capacidad para 8 bytes estructurado en 2^k^=4 líneas que guardan 2^p^=2 bytes (2^k^x2^p^=2^2^x2^1^=8) con 2^k^=4 entradas numeradas 00, 01, 10, 11 (números de k=2 bits).
Cada línea guarda un "bloque" fijo de bytes consecutivos de memoria. En este ejemplo los bloques son de 2 bytes (2 campos) el de la derecha de la línea para direcciones de memoria terminadas en 1 (p=0), y el de la izquierda para las terminadas en 0 (p=1).
En cualquier instante una copia de un subconjunto de bloques de la memoria está presente en el caché, siendo que su número es mucho mayor que el de líneas de un caché. Para establecer en que número de línea se asigna un bloque de memoria que debe pasar al caché en reemplazo de uno residente en él, se utiliza un algoritmo de correspondencia. Este opera con la dirección de memoria que produjo el fallo usando aritmética del módulo. En el caso de las direcciones se reduce a una correspondencia determinada por un subconjunto de bits de cada una de ellas, por ser las direcciones números binarios sucesivos cuya cantidad es una potencia de dos.
En un caché de correspondencia directa, cada bloque de memoria se adjudica siempre a una misma línea, cuyo número de entrada (dirección en el caché) es un subconjunto de bits del número binario que es la dirección de cualquiera de los bytes del bloque. Así, en la fig. 1.77.b los contenidos de todas las direcciones de memoria cuyos bits en "italica" son 00, como ser 000000 ó 000001 ó 001000 ó 001001 ó 010000 ó 010001 ó 011000 ó 011001 ó... ó xxx00x... ó 111000 ó 111001 sólo se pueden guardar en la línea 00 del caché. Según terminen en 0 ó 1 irán a la izquierda o derecha, respectivamente.
Análogamente, los contenidos de direcciones con bits indicados 01 tales como 000010 ó 000011 ó 001010 ó 001011 ó 010010 ó 010011 ó 011010 ó 011011 ó... ó xxx01x... ó 111010 ó 111011 se guardarán siempre en la línea 01.
Direcciones del tipo xxx01x y xxx11x deben guardarse en las líneas 10 y 11, respectivamente.
En general, si un caché tiene 2^k^ líneas (4 en este ejemplo) y cada una guarda 2^p^ bytes (2 en este caso), para cada dirección se usarán los últimos p bits de la derecha para indicar en que posición de la línea se guardará el byte correspondiente a esa dirección; y los siguientes k bits (a la izquierda de esos p bits) se emplean para indicar el número de línea dónde estará dicho byte. En el ejemplo, k = 2 bits de línea (líneas 00, 01, 10, 11), y p=1 bit (el byte puede estar en la posición 0 ó 1 dentro de una línea).
Como se verá, para cada dirección de memoria, los t bits que están a la izquierda de los k bits de línea (en este caso t=3) sirven para que el controlador determine si el contenido de dicha dirección está o no en el caché. Dichos t bits constituyen el "tag" (etiqueta) de una dirección. Así, 010 es el tag de la dirección 010011.
Puesto que cada línea guarda un bloque de 2^p^ bytes consecutivos de memoria, las direcciones de los bytes de un bloque que está en una línea tendrán igual tag, ya que ellas sólo difieren en sus últimos p bits de la derecha.
Determinaremos t, k, p para una memoria DRAM de 2^32^ bytes (4GB) que usa un caché SRAM de 512 KB = 2^19^ bytes organizado en 32768 líneas = 2^15^ líneas que guardan 16 bytes = 2^4^ bytes (se verifica que 2^15^x2^4^ = 2^19^ bytes ). Puesto que 2^15^ = 2^k^ resulta que k=15 (números de línea 000000000000000 a 111111111111111), y p=4 (en cada línea cada una de las 2^p^ =2^4^ =16 posiciones que guardan un byte se identifica por los últimos p=4 bits de su dirección: 0000 a 1111). Dado que cada dirección tiene 32 bits, resulta: t = 32 - (15 + 4) = 13 bits para cada tag.
Por ejemplo, en una dirección de 32 bits como 10110100111001101110111010101101, debe considerarse que 1011010011100 es el tag; 110111011101010 es el número de línea, y 1101 indica dentro de ésta la posición del byte correspondiente a la dirección dada. Son comunes cachés de 32 bytes por línea.
Por lo tanto la estructura del caché determina los numeros de bits de k y p, siendo que los de t son los que restan del número n de bits de cada direccion de memoria: t = n - (k + p)
El controlador de caché posee una "tag memory": una SRAM que contiene un tag por cada línea del caché, que es el mismo para todas las direciones de los 2^p^ bytes que ella guarda (fig.1.77.b), pues las mismas sólo difieren en sus últimos p bits de la derecha (p = 1 en la fig.1.77.b). Cuando luego de un fallo se transfiere un bloque de bytes consecutivos de memoria hacia linea de caché, el controlador escribe en su "tag memory" el tag de las direcciones de esos bytes. Si luego la UCP ordena leer el contenido de una dirección de memoria, ella será interceptada por el controlador, que rápidamente comparará el tag de la misma con el tag de la "tag memory" vinculado al número de línea correspondiente a esa dirección. Si el circuito comparador indica igualdad de tags, es un acierto, o sea que en la línea del caché correspondiente a ese tag está el byte que la UCP direccionó, y por lo tanto dicho byte será proporcionado por el caché casi al mismo tiempo de la indicación de acierto. De no ser así resulta un fallo, por lo que el controlador permitirá leer en la memoria el contenido de dicha dirección (fig. 1.77), el cual llegará a la UCP (en la que ocurrirán "wait states"), y el mismo también pasará a la línea de cache citada -que antes no lo contenía- junto con el byte de la dirección adyacente, remplazándose así el anterior contenido de esa línea. Asimismo, en la "tag memory" se cambia el tag de esta línea por el tag del nuevo bloque. Trataremos de concretar esta descripción en el caché "básico" de la fig. 1.77.b, para lo cual supondremos que sucedieron las siguientes asignaciones, siendo que al hacer cada asignación se escribió el tag de cada línea -entre paréntesis- en la tag memory del controlador.
línea 00 : contenidos 11011101 y 00010101 de las direcciones 011000 y 011001 (011) línea 01 : contenidos 01010001 y 10010111 de las direcciones 011010 y 011011 (011) línea 10 : contenidos 11111100 y 01111101 de las direcciones 111100 y 111101 (111) línea 11 : contenidos 11010101 y 00110111 de las direcciones 001110 y 001111 (001)
Supongamos ahora que la UCP quiera leer la memoria, para lo cual por el bus de direcciones envía la dirección 011010, que será interceptada por el controlador. Así se determina que se trata de la linea 01, y se compara su tag (011) con el de la dirección. Como ambos son iguales resulta un acierto, por lo que el caché proporcionará el contenido 01010001 correspondiente a la posición 0 de esa línea, siendo 0 el último bit de la dirección. A tal fin a la salida del caché existe un multiplexor que mediante el valor de este último bit permite seleccionar si por sus salidas aparecerá el byte de las posiciones (campos) 0 ó 1. Si la direccién hubiese sido 101010, al comparar para la linea 01 su tag existente (011) con el 101 de esa dirección resultaría un fallo. Entonces se accederá a memoria para obtener los contenidos de las direcciones 101010 y 101011, los cuales reemplazarán a los anteriores 01010001 y 10010111. Luego el nuevo contenido de la posición 0 de dicha línea pasará a la UCP. En la "tag memory" se reemplazará 011 por 101. Como en el bloque traído de memoria también está el byte de la dirección siguiente (101011) a la solicitada, muy probablemente dicho byte será perdido por la UCP en el próximo acceso, por lo cual en el mismo ocurrirá un acierto. Teniendo en cuenta que en la práctica un bloque puede tener 16 ó 32 bytes, al ser llevado al caché junto con el byte solicitado se guardarán bytes de las direcciones consecutivas siguientes a la que ocasionó el fallo. De este modo al llegar más bytes que los solicitados, en forma automatica se trata de aprovechar la proximidad espacial, pues es dable esperar los bytes que llegaron "de mas" anticipadamente en el bloque, sean los próximos en ser accedidos en el caché, resultando una sucesión de aciertos.
Lo anterior también sirve para subrayar el hecho de que un caché recibe información desde memoria solamente cuando ocurre un fallo, o sea en el caso que el byte direccionado por la UCP no se encuentra en él. Ello implica por un lado, que la información fluye de memoria hacia el caché en forma discontinua, pues la UCP accede continuamente al caché. Por lo tanto el tráfico desde memoria hacia la UCP se reduce notablemente, posibilitando a su vez que la memoria pueda ser accedida con menos conflictos con la UCP por parte de dispositivos de E\S que realizan ADM: acceso directo a memoria (fig. 1.72). Por otra parte se verifica que la próxima información a la que seguramente la UCP accederá llega en forma automática: como se accede a un bloque de direcciones consecutivas de memoria, junto con los bytes que se direccionaron (que provocaron el fallo) vienen a la línea del caché que se reemplaza los bytes de las direcciones siguientes que próximamente serán accedidos por la UCP.
Además de seguido, por lo general los controladores también piden el bloque con las direcciones siguientes al bloque que contenía la dirección del fallo, el cual irá a otra linea del caché. Así en éste por lo menos existirán dos bloques (líneas) con direcciones consecutivas.
En la "tag memory" SRAM se determina si un contenido de ella (tag) está o no, para lo cual se compara el tag de la direccion generada por la UCP con el tag de la línea del caché accedida, utilizando un circuito comparador por línea. Este funcionamiento es propio de las denominadas "memorias asociativas", en las cuales se puede así determinar si un número -en este caso el de un tag- se encuentra o no en ellas. Para no perder tiempo, a la par que se accede al tag de una linea mediante el campo de k bits de la dirección (00,01,10 ó 11 en el ejemplo), tambien se accede a una copia del bloque contenido en esa línea, para que aparezca en las salidas del caché, haya haya acierto o fallo. Si hay acierto, parte del mismo (seleccionado con los p bits de la dirección) irá a la UCP. En caso de fallo simplemente no pasa a la UCP.
Un cache con más bytes por línea, responderá mejor cuando la UCP accede a una zona con buena proximidad espacial, como ser una larga secuencia de instrucciones consecutivas. En cambio cuando ocurre un fallo (< 10 % de los accesos) tendá que acceder a un mayor número de bytes sucesivos en memoria que un caché con menos bytes por línea.
En el controlador (fig. 1.77.b) además de los "tags" existe para cada línea un bit de validación (V) que sirve al controlador para saber si los contenidos de una línea son válidos. Por ejemplo, cuando se enciende el computador todas las líneas tendrán su V=0, de modo que si la UCP genera una dirección que por casualidad está en el caché así se indica que los contenidos de la línea correspondiente son inválidos, puesto que son "basura" accidental. Luego, en los primeros instantes de la ejecución de un programa, las primeras direcciones de intrucciones y datos no estarán en la "tag memory", ocurriendo un gran número de fallos; pero con cada nuevo bloque que es traído de memoria, el mismo contendrá bytes de direcciones que siguen a la que la UCP quiere acceder, con lo cual comenzará a funciona la proximidad espacial y temporal. Asimismo, para cada línea donde hubo reemplazo de bloque, el controlador pondrá su V=1.
Los caches de correspondencia directa si bien presentan una circuitería sencilla, el hecho de que se adjudique cada bloque de memoria siempre a la misma línea (por ej cada dirección xxx01x irá a la línea 01) puede ocasionar a veces ima disminución en la tasa de aciertos. Tal sería el caso en que se ejecutan instrucciones que direccionan en forma repetitiva datos de dos bloques de memoria, los cuales por sus direcciones deben ser adjudicados, casualmente, a una misma línea del caché. Por lo tanto, en ese lapso constantemente el controlador debeía ir cambiando el bloque que está en esa línea, pasando el cache en forma alternada uno y otro de esos dos bloques de la memoria. Estas situaciones se solucionan con compiladores más inteligentes, que no generen este tipo de accesos.
Los problemas del tipo anterior no pueden ocurrir en los cachés con correspondencia totalmente asociativa donde cualquier bloque puede ser adjudicado por el controlador a cualquier línea, lo cual permite aprovechar mejor el pincipio de prozimidad en el acceso al caché, posiblitando una mayor tasa de aciertos.
En la fig 1.77.b, por ejemplo el bloque de direcciones 101010 y 101011 seria factible asignarlo a una cualquiera de las líneas del caché (suponiendo igualmente 8), sgún mejor convenga, y no sólo a la línea 01.
El controlador de este caché cumplimenta un algoritmo que permite determinar a cuál línea (por ej la menos accedida últimamente) se asignará el bloque de memoria que debe entrar en el caché, en reemplazo de otro bloque. O sea que el número de línea no se obtiene a partir de la dirección que produjo un fallo.
Para determinar si hay o no acierto se requiere comparar el tag de la dirección a la que la UCP quiere acceder, con el tag de cada una de las líneas en la "tag memory". Puesto que se requiere rapidez habrá que hacer múltiples comparaciones sumultáneas, resultando compleja y limitada en velocidad la circuiteria de comparación. Además los comparadores deben tener muchas entradas, dado que cada tag comprende bastantes bits, pues son los de cada dirección amenos los p bits de la derecha (para la fig. xxx, el tag sería de t=5 bits, y p=1). Por ello sólo esta correspondencia sólo es viable en cachñes relativamente pequeños, con pocas líneas.
A diferencia de esto, en el caché de correspondencia directa tratado, cada bloque a asignar iba a una línea predeterminada, fija, según su dirección. En él se reemplaza al bloque existente, sin considerar si éste fue o no recientemente accedido, o sea que no se explota a fondo la proximidad temporada de los contenidos.
La correspondencia asociativa por conjunto (de 2k lineas) con c conjuntos o vias (que implican c alternativas de asignación), es una solución de copromiso entre la correspondencia directa y la totalmente asociativa.Como en la fig. 1.77.b el número de línea donde irá un bloque está determinado por k bits comunes a todas las direcciones de los bytes de ese bloque. Pero hay lineas (vias) con igual número de linea. El controlador conforme a un algoripmo, adjudicael bloque a una de dichas c lineas: la menos accedida últimamente.
Reformaremos (fig.1.77.c) el cache de 4 lineas de la fig.1.77.b de modo de tener para cada número de linea 2 lineas que guardan un bloque de 2 bytes cada una. Así se forman c=2 conjuntos de lineas designados vía 0 y vía 1. En cada vía la posición de cada bytes se identifican con 0 y 1. Todas las direcciones del tipo xxxx 0 irán ala línea 0, y las del tipo xxxx1x a la linea 1, siendo que el útimo bit de la derecha indica si irá a la posición 0 ó 1 de la línea. Ahora cada tag tendrá 4 bits.
Así, el bloque de direcciones 011001 (tag 0110) irá siempre a la linea 0, y el controlador decidirá si se será la linea 0 de la vía 0 ó la línea 0 de la via 1. Para tal fin además del tag, cada linea de cada vía, junto con su bit de validez V, tiene un bit "LRU" (least reciently used, o sea usada menos recientemente). Cada vez que una línea de una vía es accedida, el controlador pone en 1 su bit LRU, y 0 el bit LRU de igual número de línea de la otra vía.
En la fg.1.77.c para un cáche de igual tamaño que el de la fig. 1.77.b, apararecen reubicados los mismos bloques de esta última como se indica, con un valor supuesto para el bit LRU de cada uno.
Supongamos que hubo un fallo al querer asignar el bloque de direcciones 010000 y 010001 (de contenidos 10000101 y 11110000, no dibujados en la fig. 1.77.b). El mismo deberá ir a número de línea 0, y se asignará a la vía cuyo bit LRU vale 0, pues ello implica que el bloque que está en dicha vía(0 en este caso) ha sido accedido antes que el bloque de la otra vía, dado que éste con LRU=1 es más probable que sea accedido próximamente. Asimismo se colocará el tag (0100) en lugar del tag del bloque reeplazado. La nueva situación del caché y del controlador aparece el la fig.1.77.d.
Si luego la UCP quiere acceder otra vez a la dirección 010000, el controlador comparará el tag 0100 con los dos tags de los dos bloques de número de línea 0 para determinar en que vía está el bloque. En cada acierto, un multiplexor -ubicado en las salidas del caché- seleccionará por su tag el bloque accedido entre los dos posibles para un número de líneas, el cuál aparacerá en dichas salidas.
Con este esquema se evita el conflicto antes citado en la correspondencia directa, cuando dos bloques que iban a un mismo número de linea eran accedidos en forma alternada. Ahora estarian en igual número de línea, pero cada bloque en una vía distinta. La alternancia en el acceso sólo produciría el cambio de valor de los bits LRU de los dos bloques de igual número de línea.
Si bien estos cachés necesitan más comparadores que lo de correspondencia directa y en concecuencia un mayor tiempo de acceso, son menos coplejos y más rápido que los de correspondencia totalmente asociativa, por lo que resultan una buena solución de compromiso entre ambos.
Si tiene 4 vías, el controlador tiene 4 posibilidades para asgnar un bloque a un número de línea.
La estrategia de usar dos cachés multinivel, uno muy pequeño dentro del procesador (level1 - L1) y otro externo (L2), busca que L1 sea de acceso sea extra rápido, mientras que L2 se encargue de manejar los fallos de L1, de manera de minimizar los "wait states" de la UCP. Cuando el caché L2 accede a un bloque de memoria principal debido a un fallo, lo hace en modo "ráfaga" ("burst"), esto es el tiempo de acceso al primer byte del bloque (por ej. de 32 bytes) es mayor, pero los subsiguientes bytes por estar en direcciones consecutivas se acceden varias veces más rápido.
Hasta ahora hemos tratado las lecturas de instrucciones y datos en un caché, siendo que ellas predominan sobre las escrituras. Pero también la UCP requiere en menor grado guardar en memoria principal resultados de datos que ha procesado cuando una instrucción así lo ordena.
El controlador de caché también maneja la estrategia de escritura del caché y memoria principal.
Una forma denominada "*write through" ("a través" del caché) consiste en escribir (actualizar) simultáneamente ambos, lo cual conlleva tiempo. Para mejorar esto, suele usarse un "buffer" de escritura, que es escrito rápodamente junto con el caché, y que guarda resultados hasta que sean escritos en memoria.
En caso que la dirección a actualizar no se encuentre en el caché, solo se escribe la memoria.
Otra forma, "write back", o "post-escritura" consiste en marcar en el caché las líneas que la UC escribió en él, de forma que cuando la línea así marcada sea reemplazada, el bloque que contiene sea escrito en memoria principal. Esto último supone que durante un lapso de tiempo, el cachó y la memoria tendrían información diferente, situación conocida como "incoherencia". puede ocurrir entonces que una porción de memoria tengan informcación desactualizada. Para hacer por ejemplo una lectura de esa porción hacia el disco rígido se debe acceder al caché, lo cual hace más complejo el hardware.
##¿Que es una jerarquía de memorias?
A los fines de que la UPC tenga un tiempo de acceso a la cantidad de información que necesita leer o escribir lo más bajo posibley a un costo razonable; y como la memoria más lenta es mas barata, la memoria de un computador está organizada (fig. 1.78) según una jerarquí a de niveles de memorias. Ella combina la localidad temporal y espacial con lo que la tecnología de memorias brinda en cuanto a velocidades de acceso, costo y capacidad de almacenamiento. Así se tiene:
-
En el nivel superior (fig. 1.78), dentro del procesador, está la memoria más rápida (cachés internos L1 y registros). Le siguen el caché externo L2 y la memoria principal, cercanos a la UPC y comunicados directamente con la UPC a través de buses internos.
-
Cada nivel es más pequeño, más rápido, más caro por byte almacenado, y accedido con mas frecuencia que el nivel inferior; y sólo puede intercambiar información con el nivel adyacente. Se busca tener la mayor capacidad con el menor costo por byte almacenado (como preveen los discos) a la par que el tiempo de acceso de un nivel inferior a otro superior vecino sea lo menor posible, en especial para la UPC.
-
La información contenida en un nivel también está en el nivel siguiente inferior.
Al tratar los cachés se vio que una UPC con la memoria principal DRAM de 64MB y tacc = 50 nseg. y un caché SRAM de 512KB y tacc = 20 nseg. pueden hacer que la UPC en más del 90% de los accesos que éstos sean de 20 nseg. O sea, es como si la UPC tuviera una memoria de 64MB y tacc = 20 nseg., siendo que resultaría muy caro tener 64MB de SDRAM.
Con igual técnica, entre ésa memoria DRAM y el disco duro se puede simular mediante el sistema operativo una memoria virtual de muchos GB, con un tacc de acceso aceptable y sin costo adicional.
Igualmente los CDs amplían económocamente la capacidad del rígido.
Se trata siempre, entre dos niveles adyacentes, de soluciones de compromiso ente costo y velocidad.
En síntesis, para cada computador se busca construir una jerarquía de memoria tal que para el usuario simule una memoria con una capacidad de amacenamiento auxiliar virtualmente ilimitada, y con un tiempo de acceso tan rápido hoy día, como el primer nivel de memoria caché incorporado al procesador.