Cuando la CPU con un caché L1 escribe, lo que normalmente sucede es que (suponiendo que la línea de caché en la que está escribiendo ya está en el caché L1) el caché (además de actualizar los datos) marca esa línea de caché como sucia , y escribirá la línea con los datos actualizados en algún momento posterior.
Una posible optimización sería hacer que el caché compare los contenidos de la escritura y los contenidos anteriores del caché, y si son iguales, no marque la línea como sucia. Debido a que esto podría permitir que la memoria caché evite reescrituras en ocasiones, puedo ver cómo el fabricante de la CPU podría considerar que esto vale las puertas necesarias para hacer esta lógica.
Mi pregunta: ¿hay CPU que realicen esta optimización?
Antecedentes de por qué pregunto: estoy escribiendo un código que necesita tener accesos constantes a la memoria; es decir, alguien que puede escuchar el comportamiento del caché no debería poder deducir lo que estoy haciendo. Algunos de mis accesos son escrituras, y en la forma obvia de implementar este código, muchas de las escrituras escribirán los mismos datos que ya están allí. Necesito hacer las escrituras porque, dependiendo de los datos, los datos que estoy escribiendo pueden o no ser los mismos, y es importante realizar la misma acción independientemente. Si la CPU se optimiza al no escribir realmente una 'escritura sin cambios', eso significaría que el comportamiento de la memoria caché variará dependiendo de lo que esté haciendo, lo que subvertiría mi objetivo.
Entonces, ¿hay una CPU que intente optimizar las escrituras de esta manera?
Respuestas:
Después de horas de búsqueda, no pude encontrar una CPU que utilizara esta optimización específica. La mayoría de las optimizaciones mencionadas generalmente se relacionan con hit / miss con operaciones de lectura / escritura y acceso a datos:
(páginas 7 y) https://cseweb.ucsd.edu/classes/fa14/cse240A-a/pdf/08/CSE240A-MBT-L15-Cache.ppt.pdf
Sin embargo, eso no significa que no se pueda realizar esta optimización. En general, es posible acceder mediante programación al tamaño de una línea de caché de CPU. También es posible acceder a los valores actuales en los registros de caché, pero es algo peligroso hacerlo. Si accede a los registros incorrectos en un mal momento, podría estar manipulando los relacionados con un programa en ejecución. O podría modificar inadvertidamente el contenido de las líneas que está intentando leer.
Obteniendo el valor actual en el caché del registro
Además, todas las soluciones teóricas requieren alguna forma de implementación de software (ensamblador). Lo más cercano que he encontrado se relaciona con la arquitectura ARM, que parece permitir la manipulación de caché. Además de esto, también necesitaría saber el tamaño de una línea de caché para su CPU deseada. Podría leer cuidadosamente el contenido de la memoria caché en una ubicación secundaria en la memoria, en incrementos de tamaño de línea, y compararlo con los datos que están a punto de escribirse en los registros (o líneas de memoria caché L1, en este caso).
Leer el contenido de la memoria caché de la CPU
A partir de ahí, puede diseñar un sistema basado en software que evite reescrituras idénticas. Si bien esto está un poco simplificado, es así porque la solución debe ser aplicable a cualquier CPU que exista.
Otra posibilidad que encontré relacionada con la coherencia de caché:
Pasaje relevante de un artículo de Wikipedia sobre coherencia de acche
El punto principal que me llamó la atención, en relación con este problema, fue la descripción de Snarfing:
En otras palabras, posiblemente existen mecanismos ya establecidos. Es solo que es posible que no se usen para la optimización que ha sugerido. Tendría que implementar un software que realizara la comparación de lectura / escritura.
fuente
if (mem != x) { mem = x; }
lugar de hacerlomem = x;
. Esto solo es a veces una optimización para líneas de caché compartidas en un programa de subprocesos múltiples, porque la escritura interfiere con la lectura de otros hilos.Escribir en el caché L1 es una operación muy, muy crítica de tiempo.
Escribir exactamente los mismos datos parece ser bastante raro. Una optimización que acelere las cosas en este caso particular no va a tener mucha aceleración en total.
Por otro lado, esta optimización requiere una comparación de datos antiguos y nuevos en cada escritura en la memoria caché. ¡Lo que empeora esto es que requiere que los datos a escribir estén realmente disponibles en el momento de la escritura!
Ese no suele ser el caso en una CPU moderna. Los datos que se escribirán aún pueden calcularse, por ejemplo. El caché puede seguir adelante, cargar la línea de caché si es necesario, marcar la línea de caché como modificada, etc., incluso antes de que finalice el cálculo. Toda la contabilidad ya se puede realizar, excepto la modificación real de la línea de caché. Si desea comparar los resultados recién escritos y los datos de la línea de caché anterior, eso no es posible.
Como ejemplo, si tiene el código C a [i] = x / y; La división x / y tarda mucho tiempo en realizarse en la mayoría de las CPU. Sin embargo, la mayor parte del trabajo necesario para manejar el almacenamiento del resultado en un [i] ha sucedido mucho antes de que finalice la división; lo único que falta es el movimiento de ocho bytes de resultados a la línea de caché. Una operación que vacía la línea de caché esperará automáticamente hasta que finalice la división. Una operación que lee un [i] probablemente será redirigida para obtener el resultado directamente desde el divisor.
fuente
¿Esa optimización no duplicará el tiempo que la CPU necesita para escribir algo en la memoria caché? Porque cada escritura de línea de caché ahora estará acompañada de una operación de comparación, que no es gratuita.
Entonces, en realidad, la optimización ahora dependerá del factor muy vago: cuántas veces un software promedio reescribe su memoria almacenable en caché con los mismos datos.
fuente