¿Cuánta memoria caché. Un nuevo enfoque para el almacenamiento en caché del procesador. Embalaje y desembalaje

Al realizar varias tareas, el procesador de su computadora recibe los bloques de información necesarios de la RAM. Una vez procesados, la CPU escribe los resultados de los cálculos en la memoria y recibe bloques de datos posteriores para su procesamiento. Esto continúa hasta que se completa la tarea.

Los procesos anteriores se llevan a cabo a una velocidad muy alta. Sin embargo, la velocidad de incluso la memoria RAM más rápida es significativamente menor que la velocidad de cualquier procesador débil. Cada acción, ya sea escribir información o leerla, lleva mucho tiempo. La velocidad de la memoria RAM es diez veces menor que la velocidad del procesador.

A pesar de tal diferencia en la velocidad de procesamiento de la información, el procesador de la PC no está inactivo y no espera a que la RAM emita y reciba datos. El procesador siempre está funcionando y todo gracias a la presencia de memoria caché en él.

El caché es un tipo especial de RAM. El procesador utiliza la memoria caché para almacenar esas copias de información de la memoria RAM principal de la computadora a las que es probable que se acceda en un futuro cercano.

En esencia, la memoria caché actúa como un búfer de memoria de alta velocidad que almacena información que el procesador puede necesitar. Por lo tanto, el procesador recibe los datos necesarios diez veces más rápido que cuando los lee de la RAM.

La principal diferencia entre una memoria caché y un búfer normal son las funciones lógicas integradas. El búfer almacena datos aleatorios, que generalmente se procesan de acuerdo con el esquema "primero recibido, primero emitido" o "primero recibido, último emitido". La memoria caché contiene datos a los que es probable que se acceda en un futuro próximo. Por lo tanto, gracias a la "caché inteligente", el procesador puede funcionar a toda velocidad y no esperar a que se recuperen los datos de una memoria RAM más lenta.

Principales tipos y niveles de caché L1 L2 L3

La memoria caché se fabrica en forma de chips de memoria estática de acceso aleatorio (SRAM) que se instalan en la placa del sistema o se integran en el procesador. En comparación con otros tipos de memoria, la memoria estática puede funcionar a velocidades muy altas.

La velocidad de la memoria caché depende del tamaño de un chip en particular. Cuanto mayor sea el tamaño del chip, más difícil será lograr una alta velocidad para su funcionamiento. Dada esta característica, durante la fabricación del procesador la memoria caché se realiza en forma de varios pequeños bloques, llamados niveles. El más común hoy en día es el sistema de caché de tres niveles L1, L2, L3:

Memoria caché del primer nivel L1 - el más pequeño en volumen (solo unas pocas decenas de kilobytes), pero el más rápido en velocidad y el más importante. Contiene los datos utilizados con mayor frecuencia por el procesador y se ejecuta sin demora. Por lo general, la cantidad de chips de memoria L1 es igual a la cantidad de núcleos del procesador, y cada núcleo accede solo a su propio chip L1.

caché L2 es inferior a la memoria L1 en velocidad, pero gana en volumen, que ya se mide en varios cientos de kilobytes. Está diseñado para almacenar temporalmente información importante a la que es menos probable acceder que la información almacenada en la memoria caché L1.

Caché L3 de tercer nivel - tiene el volumen más grande de los tres niveles (puede alcanzar decenas de megabytes), pero también tiene la velocidad más lenta, que sigue siendo significativamente más alta que la velocidad de la RAM. La caché L3 se comparte entre todos los núcleos del procesador. El nivel de memoria L3 está destinado al almacenamiento temporal de esos datos importantes, cuya probabilidad de acceso es ligeramente inferior a la de la información almacenada en los dos primeros niveles L1, L2. También asegura la interacción de los núcleos del procesador entre sí.

Algunos modelos de procesadores están hechos con dos niveles de memoria caché, en los que L2 combina todas las funciones de L2 y L3.

Cuando una gran cantidad de caché es útil.

Sentirá un efecto significativo de una gran cantidad de caché cuando use programas de archivado, en juegos 3D, durante el procesamiento y la codificación de video. En programas y aplicaciones relativamente "ligeros", la diferencia prácticamente no se nota (programas de oficina, reproductores, etc.).

¿Cuál es el lugar más sucio de la computadora? ¿Piensas en una canasta? Carpetas de usuario? ¿Sistema de refrigeración? ¡No adiviné! ¡El lugar más sucio es el caché! Después de todo, ¡tiene que limpiarse constantemente!

De hecho, hay muchos cachés en una computadora, y no sirven como basureros, sino como aceleradores de equipos y aplicaciones. ¿De dónde viene su reputación como un "vertedero de basura sistémico"? Veamos qué es un caché, cómo sucede, cómo funciona y por qué de vez en cuando.

El concepto y tipos de memoria caché.

Esh o memoria caché es un almacenamiento especial de datos de uso frecuente, al que se accede decenas, cientos y miles de veces más rápido que la RAM u otros medios de almacenamiento.

Las aplicaciones (navegadores web, reproductores de audio y video, editores de bases de datos, etc.), los componentes del sistema operativo (caché de miniaturas, caché de DNS) y el hardware (caché de CPU L1-L3, búfer de cuadros de GPU, etc.) tienen su propio chip de memoria caché, búfer de unidad). Se implementa de diferentes maneras: software y hardware.

  • El caché del programa es solo una carpeta o archivo separado donde, por ejemplo, se descargan imágenes, menús, scripts, contenido multimedia y otro contenido de los sitios visitados. Esta es la carpeta donde el navegador se sumerge por primera vez cuando abre una página web nuevamente. Intercambiar una pieza de contenido del almacenamiento local acelera su carga y.

  • En los discos duros, en particular, el caché es un chip RAM separado con una capacidad de 1-256 Mb, ubicado en la placa electrónica. Recibe información leída de la capa magnética y aún no cargada en la RAM, así como los datos que el sistema operativo solicita con mayor frecuencia.

  • Un procesador central moderno contiene 2-3 niveles principales de memoria caché (también llamada memoria temporal), ubicados en forma de módulos de hardware en el mismo chip. El más rápido y pequeño en volumen (32-64 Kb) es el nivel de caché 1 (L1): se ejecuta a la misma frecuencia que el procesador. L2 está en la posición media en términos de velocidad y capacidad (de 128 Kb a 12 Mb). Y L3 es el más lento y voluminoso (hasta 40 Mb), está ausente en algunos modelos. La velocidad de L3 es solo baja en relación con sus contrapartes más rápidas, pero también es cientos de veces más rápida que la RAM más productiva.

La memoria scratchpad del procesador se utiliza para almacenar datos de uso constante, bombeados desde la RAM e instrucciones de código de máquina. Cuanto más grande es, más rápido es el procesador.

Hoy en día, tres niveles de almacenamiento en caché ya no son el límite. Con la llegada de la arquitectura Sandy Bridge, Intel ha implementado un caché L0 adicional (destinado a almacenar microinstrucciones descifradas) en sus productos. Y las CPU de mayor rendimiento también tienen un caché de cuarto nivel, hecho en forma de un microcircuito separado.

Esquemáticamente, la interacción de los niveles de caché L0-L3 se ve así (por ejemplo, Intel Xeon):

Lenguaje humano sobre cómo funciona todo

Para comprender cómo funciona la memoria caché, imagine a una persona trabajando en un escritorio. Carpetas y documentos que usa todo el tiempo están sobre la mesa ( en caché). Para acceder a ellos, simplemente extienda su mano.

Los papeles que necesita con menos frecuencia se almacenan cerca en los estantes ( en RAM). Para conseguirlos, debes levantarte y caminar unos metros. Y lo que una persona no trabaja actualmente ha sido archivado ( grabado en disco duro).

Cuanto más ancha sea la mesa, más documentos caben en ella, lo que significa que el empleado podrá acceder rápidamente a más información ( cuanto mayor sea la capacidad de caché, más rápido funcionará el programa o dispositivo en teoría).

A veces comete errores: deja papeles sobre la mesa que contienen información incorrecta y los usa en su trabajo. Como resultado, la calidad de su trabajo se reduce ( los errores de caché conducen a fallas de software y hardware). Para corregir la situación, el empleado debe tirar los documentos con errores y colocar los correctos en su lugar ( borrar la memoria caché).

La mesa tiene un área limitada ( la memoria caché es limitada). A veces se puede expandir, por ejemplo, moviendo una segunda tabla, y otras veces no (el tamaño del caché se puede aumentar si el programa brinda esa oportunidad; el caché de hardware no se puede cambiar, ya que está implementado en hardware) .

Otra forma de acelerar el acceso a más documentos de los que puede contener la mesa es encontrar un asistente que sirva papel al trabajador desde el estante (el sistema operativo puede asignar parte de la RAM no utilizada para almacenar en caché los datos del dispositivo). Pero aún es más lento que sacarlos de la mesa.

Los documentos disponibles deben ser relevantes para las tareas actuales. Esta es responsabilidad del propio empleado. Debe limpiar los papeles con regularidad (la extracción de datos irrelevantes de la memoria caché recae "sobre los hombros" de las aplicaciones que la utilizan; algunos programas tienen una función de limpieza automática de caché).

Si un empleado se olvida de mantener el orden en el lugar de trabajo y mantener la documentación actualizada, puede dibujar un horario de limpieza de mesas para sí mismo y usarlo como recordatorio. Como último recurso, confíelo a un asistente (si una aplicación que depende de la memoria caché se ha vuelto más lenta o carga datos obsoletos con frecuencia, use herramientas de limpieza de caché programadas o hágalo manualmente cada pocos días).

De hecho, nos encontramos con "funciones de almacenamiento en caché" por todas partes. Esta es la compra de productos para el futuro y varias acciones que realizamos de pasada, al mismo tiempo, etc. De hecho, esto es todo lo que nos salva de problemas innecesarios y movimientos corporales innecesarios, agiliza la vida y facilita el trabajo. La computadora hace lo mismo. En una palabra, si no hubiera caché, funcionaría cientos y miles de veces más lento. Y no nos gustaría.

Qué es un caché, por qué es necesario y cómo funciona actualizado: 25 de febrero de 2017 por: Johnny mnemotécnico

Casi todos los desarrolladores saben que el caché del procesador es una memoria tan pequeña pero rápida que almacena datos de áreas de memoria visitadas recientemente; la definición es breve y bastante precisa. Sin embargo, el conocimiento de los detalles "aburridos" sobre los mecanismos del caché es necesario para comprender los factores que afectan el rendimiento del código.

En este artículo, veremos una serie de ejemplos que ilustran las diversas características de los cachés y su impacto en el rendimiento. Los ejemplos estarán en C#, la elección del lenguaje y la plataforma no afecta tanto a la evaluación del desempeño ni a las conclusiones finales. Naturalmente, dentro de límites razonables, si elige un idioma en el que leer un valor de una matriz equivale a acceder a una tabla hash, no obtendrá ningún resultado adecuado para la interpretación. Las notas del traductor están en cursiva.

Habracut - - -

Ejemplo 1: acceso a la memoria y rendimiento

¿Cuánto más rápido crees que es el segundo ciclo que el primero?
int arr = nuevo int;

// primero
para (int i = 0; i< arr.Length; i++) arr[i] *= 3;

// segundo
para (int i = 0; i< arr.Length; i += 16) arr[i] *= 3;


El primer ciclo multiplica todos los valores de la matriz por 3, el segundo ciclo solo multiplica cada decimosexto valor. El segundo ciclo solo 6% trabajo el primer ciclo, pero en las máquinas modernas ambos ciclos toman aproximadamente el mismo tiempo: 80ms Y 78ms respectivamente (en mi máquina).

La respuesta es simple: acceso a la memoria. La velocidad de estos bucles está determinada principalmente por la velocidad del subsistema de memoria y no por la velocidad de la multiplicación de enteros. Como veremos en el siguiente ejemplo, el número de accesos a la memoria RAM es el mismo tanto en el primer como en el segundo caso.

Ejemplo 2: Impacto de las líneas de caché

Profundicemos más: probemos otros valores de paso, no solo 1 y 16:
para (int i = 0; i< arr.Length; i += K /* шаг */ ) arr[i] *= 3;

Aquí está el tiempo de ejecución de este ciclo para varios valores del paso K:

Tenga en cuenta que con valores de paso de 1 a 16, el tiempo de funcionamiento prácticamente no cambia. Pero con valores superiores a 16, el tiempo de ejecución se reduce aproximadamente a la mitad cada vez que doblamos el paso. Esto no significa que el ciclo comience a correr más rápido mágicamente, sino que el número de iteraciones también disminuye. El punto clave es el mismo tiempo de ejecución con valores de paso de 1 a 16.

La razón de esto es que los procesadores modernos acceden a la memoria no por bytes, sino por pequeños bloques llamados líneas de caché. Normalmente, el tamaño de la cadena es de 64 bytes. Cuando lee cualquier valor de la memoria, al menos una línea de caché ingresa al caché. El acceso posterior a cualquier valor de esta cadena es muy rápido.

Debido a que 16 valores int ocupan 64 bytes, los bucles con pasos del 1 al 16 acceden al mismo número de líneas de caché, más precisamente, a todas las líneas de caché de la matriz. En el paso 32, se accede a cada segunda línea, en el paso 64, a cada cuarta.

Comprender esto es muy importante para algunos métodos de optimización. El número de accesos depende de la ubicación de los datos en la memoria. Por ejemplo, los datos desalineados pueden requerir dos accesos a la RAM en lugar de uno. Como descubrimos anteriormente, la velocidad de trabajo será dos veces menor.

Ejemplo 3: Tamaños de cachés de primer y segundo nivel (L1 y L2)

Los procesadores modernos suelen tener dos o tres niveles de caché, comúnmente denominados L1, L2 y L3. Puede usar la utilidad CoreInfo o la función API de Windows GetLogicalProcessorInfo para averiguar los tamaños de las cachés en varios niveles. Ambos métodos también brindan información sobre el tamaño de la línea de caché para cada nivel.

En mi máquina, CoreInfo informa cachés de datos L1 de 32 KB, cachés de instrucciones L1 de 32 KB y cachés de datos L2 de 4 MB. Cada núcleo tiene sus propios cachés L1 personales, los cachés L2 son comunes para cada par de núcleos:

Procesador lógico a mapa de caché: *--- Caché de datos 0, nivel 1, 32 KB, Assoc 8, LineSize 64 *--- Caché de instrucciones 0, nivel 1, 32 KB, Assoc 8, LineSize 64 -*-- Caché de datos 1, nivel 1, 32 KB, asociado 8, tamaño de línea 64 -*-- Caché de instrucciones 1, nivel 1, 32 KB, asociado 8, tamaño de línea 64 **-- Caché unificado 0, nivel 2, 4 MB, asociado 16, tamaño de línea 64 --*- Caché de datos 2, Nivel 1, 32 KB, Asociación 8, Tamaño de línea 64 --*- Caché de instrucciones 2, Nivel 1, 32 KB, Asociación 8, Tamaño de línea 64 ---* Caché de datos 3, Nivel 1, 32 KB, Assoc 8, LineSize 64 ---* Caché de instrucciones 3, nivel 1, 32 KB, Assoc 8, LineSize 64 --** Caché unificada 1, nivel 2, 4 MB, Assoc 16, LineSize 64
Comprobemos esta información experimentalmente. Para hacer esto, iteremos a través de nuestra matriz incrementando cada valor 16, una manera fácil de cambiar los datos en cada línea del caché. Cuando llegamos al final, volvemos al principio. Verifiquemos los diferentes tamaños de matriz, deberíamos ver una caída en el rendimiento cuando la matriz ya no cabe en los cachés de diferentes niveles.

El código es así:

pasos int = 64 * 1024 * 1024; // numero de iteraciones
int longitudMod = arr.Longitud - 1; // tamaño de la matriz -- potencia de dos

para (int i = 0; i< steps; i++)
{
// x & lengthMod = x % arr.Length porque potencias de dos
arr[(i * 16) & longitudMod]++;
}


Resultados de la prueba:

En mi máquina, el rendimiento cae después de que se notan 32 KB y 4 MB: estos son los tamaños de los cachés L1 y L2.

Ejemplo 4: Paralelismo de instrucciones

Ahora veamos otra cosa. ¿Cuál de los dos bucles crees que correrá más rápido?
pasos int = 256 * 1024 * 1024;
int a = nuevo int ;

// primero
para (int i = 0; i< steps; i++) { a++; a++; }

// segundo
para (int i = 0; i< steps; i++) { a++; a++; }


Resulta que el segundo bucle se ejecuta casi el doble de rápido, al menos en todas las máquinas que he probado. ¿Por qué? Porque los comandos dentro de los bucles tienen diferentes dependencias de datos. Los comandos del primero tienen la siguiente cadena de dependencias:

En el segundo ciclo, las dependencias son:

Las partes funcionales de los procesadores modernos son capaces de realizar un cierto número de ciertas operaciones simultáneamente, por lo general no un número muy grande. Por ejemplo, es posible el acceso paralelo a los datos del caché L1 en dos direcciones, así como la ejecución simultánea de dos instrucciones aritméticas simples. En el primer ciclo, el procesador no puede usar estas funciones, pero sí en el segundo.

Ejemplo 5: Asociatividad de caché

Una de las preguntas clave que debe responderse al diseñar un caché es si los datos de un área de memoria determinada se pueden almacenar en cualquier celda del caché o solo en algunas de ellas. Tres posibles soluciones:
  1. Caché de mapeo directo, los datos de cada línea de caché en RAM se almacenan en una sola celda de caché predefinida. La forma más sencilla de calcular la asignación es: fila_en_índice % número_de_celdas_caché. No se pueden almacenar en caché dos filas asignadas a la misma celda al mismo tiempo.
  2. Caché parcialmente asociativa de entrada N, cada línea se puede almacenar en N ubicaciones de caché diferentes. Por ejemplo, en un caché de 16 vías, una fila se puede almacenar en una de las 16 celdas que componen el grupo. Por lo general, las cadenas con los mismos bits bajos de índices comparten un grupo.
  3. Caché totalmente asociativo, cualquier cadena se puede almacenar en cualquier ubicación de caché. La solución es equivalente a una tabla hash en su comportamiento.
Las cachés de mapeo directo son propensas a conflictos, por ejemplo, cuando dos filas compiten por una celda, empujándose alternativamente fuera de la caché, la eficiencia es muy baja. Por otro lado, las cachés totalmente asociativas, aunque sin esta desventaja, son muy complejas y costosas de implementar. Las memorias caché parcialmente asociativas son un compromiso típico entre la complejidad y la eficiencia de la implementación.

Por ejemplo, en mi máquina, el caché L2 de 4 MB es un caché semiasociativo de 16 vías. Toda la RAM se divide en conjuntos de líneas por los bits menos significativos de sus índices, las líneas de cada conjunto compiten por un grupo de 16 celdas de caché L2.

Dado que la caché L2 tiene 65 536 celdas (4 * 2 20/64) y cada grupo consta de 16 celdas, tenemos un total de 4096 grupos. Por lo tanto, los 12 bits inferiores del índice de fila determinan a qué grupo pertenece esta fila (2 12 = 4 096). Como resultado, las filas con direcciones divisibles por 262.144 (4.096 * 64) comparten el mismo grupo de 16 celdas y compiten por un lugar en él.

Para que los efectos de la asociatividad funcionen, necesitamos acceder constantemente a una gran cantidad de filas del mismo grupo, por ejemplo, usando el siguiente código:

Public static long UpdateEveryKthByte(byte arr, int K)
{
const int rep = 1024 * 1024; // numero de iteraciones

Cronómetro sw = Cronómetro.StartNew();

int p = 0;
para (int i = 0; i< rep; i++)
{
arr[p]++;

P+=K; if (p >= arr.Length) p = 0;
}

Sw.Stop();
return sw.ElapsedMillisegundos;
}


El método incrementa cada K-ésimo elemento de la matriz. Cuando llegamos al final, empezamos de nuevo. Después de un número bastante grande de iteraciones (2 20), nos detenemos. Hice ejecuciones para varios tamaños de matriz y valores de paso K. Resultados (azul - tiempo de ejecución largo, blanco - pequeño):

Las áreas azules corresponden a aquellos casos en los que, con el cambio constante de datos, el caché no puede acomodar todos los datos requeridos al mismo tiempo. El color azul brillante indica un tiempo de funcionamiento de aproximadamente 80 ms, casi blanco: 10 ms.

Tratemos con las áreas azules:

  1. ¿Por qué aparecen líneas verticales? Las líneas verticales corresponden a los valores de paso en los que se accede a demasiadas filas (más de 16) de un grupo. Para estos valores, el caché de 16 vías de mi máquina no puede contener todos los datos que necesita.

    Algunos de los valores de zancada malos son potencias de dos: 256 y 512. Por ejemplo, considere la zancada 512 y una matriz de 8 MB. En este paso, hay 32 secciones en la matriz (8 * 2 20/262 144), que compiten entre sí por celdas en 512 grupos de caché (262 144/512). Hay 32 parcelas y solo hay 16 celdas en el caché para cada grupo, por lo que no hay suficiente espacio para todos.

    Otros valores de paso que no son potencias de 2 son simplemente desafortunados, lo que provoca muchos accesos a los mismos grupos de caché y también hace que aparezcan líneas azules verticales en la figura. En este punto, los amantes de la teoría de números están invitados a pensar.

  2. ¿Por qué las líneas verticales se rompen en un límite de 4 MB? Con un tamaño de matriz de 4 MB o menos, una caché de 16 vías se comporta igual que una caché totalmente asociativa, es decir, puede contener todos los datos de la matriz sin conflictos. No hay más de 16 áreas luchando por un grupo de caché (262 144 * 16 = 4 * 2 20 = 4 MB).
  3. ¿Por qué hay un gran triángulo azul en la parte superior izquierda? Porque con un pequeño paso y una gran matriz, el caché no puede acomodar todos los datos necesarios. El grado de asociatividad de la caché juega aquí un papel secundario, la limitación está relacionada con el tamaño de la caché L2.

    Por ejemplo, con un tamaño de matriz de 16 MB y un paso de 128, accedemos cada 128 bytes, actualizando así cada línea de la memoria caché de la matriz. Se necesitan 8 MB para almacenar cada línea en el caché, pero mi máquina solo tiene 4 MB.

    Incluso si la caché fuera completamente asociativa, esto no permitiría almacenar 8 MB de datos en ella. Tenga en cuenta que en el ejemplo anterior con stride 512 y un tamaño de matriz de 8 MB, solo necesitamos 1 MB de caché para almacenar todos los datos que necesitamos, pero esto no es posible debido a una asociatividad de caché insuficiente.

  4. ¿Por qué el lado izquierdo del triángulo está ganando gradualmente su intensidad? La intensidad máxima recae en el valor de paso de 64 bytes, que es igual al tamaño de la línea de caché. Como vimos en el primer y segundo ejemplo, el acceso secuencial a la misma cadena cuesta casi nada. Digamos, con un paso de 16 bytes, tenemos cuatro accesos a memoria por el precio de uno.

    Dado que el número de iteraciones es el mismo en nuestra prueba para cualquier valor de paso, el paso más económico genera menos tiempo de ejecución.

Los efectos detectados también se conservan en valores grandes de los parámetros:

La asociatividad de caché es algo interesante que puede aparecer bajo ciertas condiciones. A diferencia de los otros problemas discutidos en este artículo, no es tan grave. Ciertamente, esto no es algo que requiera atención constante al escribir programas.

Ejemplo 6: uso compartido de caché falso

En máquinas de varios núcleos, puede encontrar otro problema: la coincidencia de caché. Los núcleos del procesador tienen cachés parcial o completamente separados. En mi máquina, los cachés L1 están separados (como de costumbre) y hay dos cachés L2 compartidos por cada par de núcleos. Los detalles pueden variar, pero en general, los procesadores multinúcleo modernos tienen cachés jerárquicos de varios niveles. Además, los cachés más rápidos, pero también los más pequeños, pertenecen a núcleos individuales.

Cuando uno de los núcleos modifica el valor en su caché, los otros núcleos ya no pueden usar el valor anterior. El valor en los cachés de otros núcleos debe actualizarse. Además, debe actualizarse toda la línea de caché porque los cachés operan en datos de nivel de fila.

Demostremos este problema con el siguiente código:

privado estático int s_counter = new int;

UpdateCounter vacío privado (posición int)
{
para (int j = 0; j< 100000000; j++)
{
s_contador = s_contador + 3;
}
}


Si en mi máquina de cuatro núcleos llamo a este método con los parámetros 0, 1, 2, 3 simultáneamente desde cuatro subprocesos, entonces el tiempo de ejecución será 4,3 segundos. Pero si llamo al método con los parámetros 16, 32, 48, 64, entonces el tiempo de ejecución será solo 0,28 segundos.

¿Por qué? En el primer caso, es muy probable que los cuatro valores procesados ​​por los subprocesos en un momento dado acaben en la misma línea de caché. Cada vez que un núcleo incrementa un valor, marca las ubicaciones de caché que contienen ese valor en otros núcleos como no válidas. Después de esta operación, todos los demás núcleos tendrán que volver a almacenar en caché la línea. Esto hace que el mecanismo de almacenamiento en caché no funcione, lo que reduce el rendimiento.

Ejemplo 7: complejidad del hardware

Incluso ahora, cuando los principios del funcionamiento de la memoria caché no son un secreto para usted, el hardware seguirá sorprendiéndolo. Los procesadores difieren entre sí en los métodos de optimización, la heurística y otras sutilezas de implementación.

La caché L1 de algunos procesadores puede acceder a dos celdas en paralelo si pertenecen a grupos diferentes, pero si pertenecen al mismo grupo, solo de forma secuencial. Que yo sepa, algunos incluso pueden acceder a diferentes cuartos de la misma celda en paralelo.

Los procesadores pueden sorprenderlo con optimizaciones inteligentes. Por ejemplo, el código del ejemplo anterior sobre el intercambio falso de caché no funciona como se esperaba en la computadora de mi hogar; en los casos más simples, el procesador puede optimizar el rendimiento y reducir los efectos negativos. Si el código se modifica ligeramente, todo encaja.

Aquí hay otro ejemplo de extrañas peculiaridades de hierro:

privado estático int A, B, C, D, E, F, G;

Vacío estático privado Rareza()
{
para (int i = 0; i< 200000000; i++)
{
<какой-то код>
}
}


si en cambio<какой-то код>sustituya tres opciones diferentes, puede obtener los siguientes resultados:

Incrementar los campos A, B, C, D lleva más tiempo que incrementar los campos A, C, E, G. Aún más extraño, incrementar los campos A y C lleva más tiempo que los campos A, C Y E, G. No sé exactamente cuáles son las razones de esto, pero quizás estén asociadas con los bancos de memoria ( si, si, con las habituales cajas de ahorro de memoria de tres litros, y no lo que pensabas). Si tiene alguna idea sobre esto, no dude en comentar.

En mi máquina, no se observa lo anterior, sin embargo, a veces hay resultados anormalmente malos; lo más probable es que el programador de tareas haga sus propias "correcciones".

La lección que se puede aprender de este ejemplo es que es muy difícil predecir completamente el comportamiento del hardware. Sí, Poder predecir mucho, pero necesita confirmar constantemente sus predicciones a través de mediciones y pruebas.

Conclusión

Espero que todo lo discutido te haya ayudado a comprender la estructura de los cachés del procesador. Ahora puedes poner en práctica lo que aprendiste para optimizar tu código.

Los chips en la mayoría de las computadoras de escritorio modernas tienen cuatro núcleos, pero los fabricantes de chips ya han anunciado planes para pasar a seis núcleos, y los procesadores de 16 núcleos están lejos de ser poco comunes para los servidores de gama alta en la actualidad.

Cuantos más núcleos, mayor es el problema de asignar memoria entre todos los núcleos mientras trabajan juntos. Con un aumento en el número de núcleos, es cada vez más rentable minimizar la pérdida de tiempo en la gestión de núcleos durante el procesamiento de datos, porque la tasa de intercambio de datos va a la zaga de la velocidad del procesador y el procesamiento de datos en la memoria. Puede acceder físicamente al caché rápido de otra persona, o puede usar el suyo lento, pero ahorra tiempo de transferencia de datos. La tarea se complica por el hecho de que la cantidad de memoria solicitada por los programas no se corresponde claramente con la cantidad de memoria caché de cada tipo.

Físicamente, solo se puede colocar una cantidad muy limitada de memoria lo más cerca posible del procesador: el caché del procesador de nivel L1, cuyo volumen es extremadamente insignificante. Daniel Sanchez, Po-An Tsai y Nathan Beckmann, investigadores del Laboratorio de Ciencias de la Computación e Inteligencia Artificial del MIT, han enseñado a una computadora a configurar sus diferentes tipos de memoria en una jerarquía flexible de programas en modo de tiempo real. El nuevo sistema, llamado Jenga, analiza las necesidades de volumen y la frecuencia de los accesos a la memoria del programa y reasigna la potencia de cada uno de los 3 tipos de caché del procesador en combinaciones que brindan una mayor eficiencia y ahorro de energía.


Para empezar, los investigadores probaron el aumento del rendimiento con una combinación de memoria estática y dinámica cuando trabajaban en programas para un procesador de un solo núcleo y obtuvieron una jerarquía principal: qué combinación es mejor usar. Desde 2 tipos de memoria o desde uno. Se evaluaron dos parámetros - retraso de la señal (latencia) y energía consumida durante el funcionamiento de cada uno de los programas. Aproximadamente el 40% de los programas comenzaron a funcionar peor con una combinación de tipos de memoria, el resto, mejor. Habiendo fijado a qué programas les "gusta" el rendimiento mixto y a cuáles les gusta el tamaño de la memoria, los investigadores construyeron su sistema Jenga.

Probaron virtualmente 4 tipos de programas en una máquina virtual con 36 núcleos. Programas probados:

  • omnet: banco de pruebas de red modular objetivo, biblioteca de simulación C y plataforma de simulador de red (azul en la figura)
  • mcf - Framework de metacontenido (color rojo)
  • astar - Software de visualización de realidad virtual (verde)
  • bzip2 - archivador (púrpura)


La imagen muestra dónde y cómo se procesaron los datos de cada uno de los programas. Las letras muestran dónde se ejecuta cada aplicación (una por cuadrante), los colores muestran dónde residen sus datos y el sombreado indica el segundo nivel de la jerarquía virtual cuando está presente.

Niveles de caché

La memoria caché de la CPU se divide en varios niveles. Para procesadores universales: hasta 3. La memoria más rápida es el caché de primer nivel: caché L1, ya que está ubicado en el mismo chip que el procesador. Consta de una caché de instrucciones y una caché de datos. Algunos procesadores sin caché L1 no pueden funcionar. La caché L1 opera a la frecuencia del procesador y se puede acceder a ella en cada ciclo de reloj. A menudo es posible realizar múltiples operaciones de lectura/escritura al mismo tiempo. El volumen suele ser pequeño, no más de 128 KB.

El caché L1 interactúa con el caché de segundo nivel - L2. Es el segundo más rápido. Por lo general, se encuentra en el chip, como L1, o muy cerca del núcleo, como en un cartucho de procesador. En los procesadores más antiguos, el conjunto de chips de la placa base. El volumen de caché L2 es de 128 KB a 12 MB. En los procesadores multinúcleo modernos, la caché de segundo nivel, ubicada en el mismo chip, es una memoria separada: con un tamaño de caché total de 8 MB, cada núcleo tiene 2 MB. Por lo general, la latencia de la caché L2 ubicada en el chip central es de 8 a 20 ciclos centrales. En tareas que involucran numerosos accesos a un área de memoria limitada, por ejemplo, un DBMS, su uso completo aumenta diez veces el rendimiento.

La caché L3 suele ser incluso más grande, aunque algo más lenta que la L2 (debido a que el bus entre L2 y L3 es más estrecho que el bus entre L1 y L2). L3 generalmente se encuentra separado del núcleo de la CPU, pero puede ser grande: más de 32 MB. La caché L3 es más lenta que las cachés anteriores, pero aún más rápida que la RAM. En sistemas multiprocesador es de uso común. El uso de una caché de tercer nivel está justificado en una gama muy limitada de tareas y es posible que no solo no proporcione un aumento en el rendimiento, sino que viceversa y provoque una disminución general en el rendimiento del sistema.

Deshabilitar el caché de segundo y tercer nivel es más útil en problemas matemáticos cuando la cantidad de datos es menor que el tamaño del caché. En este caso, puede cargar todos los datos a la vez en el caché L1 y luego procesarlos.


De vez en cuando, Jenga reconfigura las jerarquías virtuales a nivel del sistema operativo para minimizar la cantidad de intercambio de datos, teniendo en cuenta las limitaciones de recursos y el comportamiento de la aplicación. Cada reconfiguración consta de cuatro pasos.

Jenga distribuye los datos no solo en función de los programas que se envían (a los que les encanta la memoria grande de una sola velocidad o a los que les encanta la velocidad de las cachés mixtas), sino también en función de la proximidad física de las celdas de memoria a los datos que se procesan. Independientemente de qué tipo de caché requiera el programa por defecto o por jerarquía. Lo principal es minimizar el retraso de la señal y el consumo de energía. Dependiendo de cuántos tipos de memoria le "gusten" al programa, Jenga modela la latencia de cada jerarquía virtual con uno o dos niveles. Las jerarquías de dos niveles forman una superficie, las jerarquías de un nivel forman una curva. Luego, Jenga proyecta el retraso mínimo en las dimensiones de VL1, lo que da como resultado dos curvas. Finalmente, Jenga usa estas curvas para seleccionar la mejor jerarquía (es decir, tamaño VL1).

El uso de Jenga dio un efecto tangible. El chip virtual de 36 núcleos es un 30 % más rápido y utiliza un 85 % menos de energía. Por supuesto, por ahora, Jenga es solo una simulación de una computadora en funcionamiento y pasará algún tiempo antes de que vea ejemplos reales de este caché e incluso antes de que los fabricantes de chips lo adopten si les gusta la tecnología.

Configuración de una máquina nuclear condicional 36

  • Procesadores. 36 núcleos, x86-64 ISA, 2,4 GHz, LLC similar a Silvermont: 8B de ancho
    sibuscar; bpred de 2 niveles con BHSR de 512 x 10 bits + PHT de 1024 x 2 bits, decodificación/emisión/cambio de nombre/compromiso de 2 vías, IQ y ROB de 32 entradas, LQ de 10 entradas, SQ de 16 entradas; 371 pJ/instrucción, 163 mW/potencia estática central
  • cachés L1. 32 KB, cachés de instrucciones y datos divididos asociativos por conjuntos de 8 vías,
    latencia de 3 ciclos; 15/33 pJ por acierto/fallo
  • Servicio de captadores previos. Prebuscadores de flujo de 16 entradas modelados y validados contra
    Nehalem
  • cachés L2. 128 KB privados por núcleo, conjunto asociativo de 8 vías, inclusive, latencia de 6 ciclos; 46/93 pJ por acierto/fallo
  • Modo coherente (Coherencia). Bancos de directorio de latencia de 6 ciclos y 16 vías para Jenga; directorios L3 en caché para otros
  • NOC mundial. Malla 6×6, flits y enlaces de 128 bits, enrutamiento X-Y, enrutadores canalizados de 2 ciclos, enlaces de 1 ciclo; 63/71pJ por enrutador/transmisión de flujo de enlace, 12/4 mW de potencia estática de enrutador/enlace
  • Bloques de memoria estática SRAM. 18 MB, un banco de 512 KB por mosaico, zcache de 4 vías para 52 candidatos, latencia de banco de 9 ciclos, partición Vantage; 240/500 pJ por acierto/fallo, 28 mW/banco de energía estática
  • DRAM apilada de memoria dinámica multicapa. 1152 MB, una bóveda de 128 MB por 4 mosaicos, aleación con MAP-I DDR3-3200 (1600 MHz), bus de 128 bits, 16 rangos, 8 bancos/rango, búfer de fila de 2 KB; 4,4/6,2 nJ por acierto/fallo, 88 mW/potencia estática de bóveda
  • memoria principal. 4 canales DDR3-1600, bus de 64 bits, 2 rangos/canal, 8 bancos/rango, búfer de fila de 8 KB; 20 nJ/acceso, potencia estática de 4 W
  • tiempos DRAM. tCAS=8, tRCD=8, tRTP=4, tRAS=24, tRP=8, tRRD=4, tWTR=4, tWR=8, tFAW=18 (todas las temporizaciones en tCK; la DRAM apilada tiene la mitad de tCK como memoria principal )

El caché es una memoria integrada en el procesador, en la que se escriben los datos (comandos) de la RAM más utilizados, lo que acelera significativamente el trabajo.

Tamaño de caché L1 (de 8 a 128 KB)
La cantidad de memoria caché en el primer nivel.
La caché L1 es un bloque de memoria de alta velocidad ubicado directamente en el núcleo del procesador.
Copia los datos recuperados de la RAM.

Guardar las instrucciones principales le permite aumentar el rendimiento del procesador debido a la mayor velocidad de procesamiento de datos (el procesamiento desde el caché es más rápido que desde la RAM).

La capacidad de la memoria caché del primer nivel es pequeña y se calcula en kilobytes.
Por lo general, los modelos de procesador "más antiguos" tienen una memoria caché L1 grande.
Para los modelos de varios núcleos, se indica la cantidad de caché L1 para un núcleo.

Tamaño de caché L2 (de 128 a 12288 KB)
La cantidad de memoria caché en el segundo nivel.
La caché L2 es un bloque de memoria de alta velocidad que realiza las mismas funciones que la caché L1 (consulte "Tamaño de caché L1"), pero con una velocidad más lenta y un volumen mayor.

Si elige un procesador para tareas que requieren muchos recursos, será preferible un modelo con una gran cantidad de caché L2.
Para los procesadores multinúcleo, se indica la cantidad total de caché L2.

Tamaño de caché L3 (de 0 a 16384 KB)
La cantidad de memoria caché en el tercer nivel.
La caché L3 integrada, combinada con un bus de sistema rápido, forma un enlace de datos de alta velocidad a la memoria del sistema.

Como regla general, solo las CPU para soluciones de servidor o ediciones especiales de procesadores de "escritorio" están equipadas con un caché de tercer nivel.

La caché L3 está disponible, por ejemplo, en líneas de procesadores como Intel Pentium 4 Extreme Edition, Xeon DP, Itanium 2, Xeon MP y otros.

Twin BiCS FLASH: una nueva tecnología de memoria flash 3D

El 11 de diciembre de 2019, en el IEEE International Electronic Devices Meeting (IEDM), TOKYO-Kioxia Corporation anunció una tecnología de memoria flash 3D: Twin BiCS FLASH.

Controlador AMD Radeon Software Adrenalin Edition 2020 19.12.2 WHQL (agregado)

El 10 de diciembre, AMD presentó el megacontrolador Radeon Software Adrenalin 2020 Edition 19.12.2 WHQL.

Actualización acumulativa de Windows 10 1909 KB4530684

El 10 de diciembre de 2019, Microsoft lanzó la actualización acumulativa KB4530684 (compilación 18363.535) para la actualización de noviembre de 2019 de Windows 10 (versión 1909) en sistemas basados ​​en procesadores x86, x64 (amd64), ARM64 y Windows Server 2019 (1909) para sistemas basados ​​en x64 .

Controlador NVIDIA Game Ready GeForce 441.66 WHQL

El controlador NVIDIA GeForce Game Ready 441.66 WHQL incluye soporte para MechWarrior 5: Mercenaries y Detroit: Become Human, y agrega soporte G-SYNC para monitores MSI MAG251RX y ViewSonic XG270.