¿Cuál es el significado de los accesos a memoria "no temporales" en x86?

123

Ésta es una pregunta de bajo nivel. En el ensamblaje x86 hay dos instrucciones SSE:

MOVDQA xmmi, m128

y

MOVNTDQA xmmi, m128

El Manual del desarrollador de software IA-32 dice que NT en MOVNTDQA significa Non-Temporal , y que por lo demás es lo mismo que MOVDQA.

Mi pregunta es, ¿qué significa no temporal ?

Nathan Fellman
fuente
6
Tenga en cuenta que SSE4.1 MOVNTDQA xmmi, m128es una carga NT, mientras que todas las demás instrucciones NT son tiendas, excepto prefetchnta. La respuesta aceptada aquí solo parece estar hablando de tiendas. Esto es lo que he podido encontrar sobre las cargas NT . TL: DR: es de esperar que la CPU haga algo útil con la sugerencia de NT para minimizar la contaminación del caché, pero no anulan la semántica fuertemente ordenada de la memoria WB "normal", por lo que tienen que usar el caché.
Peter Cordes
5
Actualización: las cargas de NT pueden no hacer nada útil excepto en las regiones de memoria UCSW en la mayoría de las CPU (por ejemplo, la familia Intel SnB). Sin embargo, las tiendas NT / streaming definitivamente funcionan en la memoria normal.
Peter Cordes
4
@ Peter: ¿Te refieres a la memoria USWC, verdad? Nunca antes había oído hablar de la memoria UCSW o USWC. Buscar en Google el acrónimo incorrecto no fue útil :-)
Andrew Bainbridge
4
@AndrewBainbridge: Sí, el atributo de tipo de memoria WC. Combinación de escritura especulativa que no se puede almacenar en caché. Creo que estaba escribiendo con mayúscula UnCacheable y recordando que se suponía que debía tener 4 letras. : P
Peter Cordes

Respuestas:

147

Las instrucciones SSE no temporales (MOVNTI, MOVNTQ, etc.) no siguen las reglas normales de coherencia de caché. Por lo tanto, los almacenes no temporales deben ir seguidos de una instrucción SFENCE para que otros procesadores puedan ver sus resultados de manera oportuna.

Cuando se producen datos y no se consumen (inmediatamente) de nuevo, el hecho de que las operaciones de almacenamiento de memoria lean primero una línea de caché completa y luego modifiquen los datos almacenados en caché es perjudicial para el rendimiento. Esta operación empuja los datos fuera de las cachés que podrían ser necesarios nuevamente a favor de los datos que no se utilizarán pronto. Esto es especialmente cierto para grandes estructuras de datos, como matrices, que se rellenan y luego se utilizan. Antes de que se llene el último elemento de la matriz, el tamaño total expulsa los primeros elementos, lo que hace que el almacenamiento en caché de las escrituras sea ineficaz.

Para esta y situaciones similares, los procesadores brindan soporte para operaciones de escritura no temporales. No temporal en este contexto significa que los datos no se reutilizarán pronto, por lo que no hay razón para almacenarlos en caché. Estas operaciones de escritura intemporales no leen una línea de caché y luego la modifican; en cambio, el nuevo contenido se escribe directamente en la memoria.

Fuente: http://lwn.net/Articles/255364/

Espo
fuente
15
Buena respuesta, me gustaría señalar que en el tipo de procesador con instrucciones NT, incluso con una instrucción no temporal (es decir, una instrucción normal), la caché de línea no se "lee y luego se modifica". Para una instrucción normal que escribe en una línea que no está en la caché, se reserva una línea en la caché y una máscara indica qué partes de la línea están actualizadas. Esta página web lo llama "sin parada en la tienda": ptlsim.org/Documentation/html/node30.html . No pude encontrar referencias más precisas, solo escuché sobre esto de personas cuyo trabajo es implementar simuladores de procesador.
Pascal Cuoq
2
En realidad, ptlsim.org es un sitio web sobre un simulador de procesador con precisión de ciclo, exactamente el mismo tipo de cosas que están haciendo los chicos que me dijeron sobre "no hay paradas en la tienda". Será mejor que los mencione también en caso de que alguna vez vean este comentario: unisim.org
Pascal Cuoq
1
De las respuestas y comentarios aquí stackoverflow.com/questions/44864033/… parece que SFENCEpuede que no sea necesario. Al menos en el mismo hilo. ¿Podrías mirar también?
Serge Rogatch
1
@SergeRogatch depende del escenario del que esté hablando, pero sí, hay escenarios donde sfencese requiere para las tiendas NT, mientras que nunca es necesario solo para las tiendas normales. Las tiendas NT no están ordenadas con respecto a otras tiendas (NT o no), como ven otros hilos , sin un sfence. Sin embargo, para las lecturas del mismo hilo que hizo las tiendas, nunca es necesario sfence: un hilo dado siempre verá sus propias tiendas en el orden del programa, independientemente de si son tiendas NT o no.
BeeOnRope
40

Espo está bastante acertado. Solo quería agregar mis dos centavos:

La frase "no temporal" significa carecer de localidad temporal. Los cachés explotan dos tipos de localidad: espacial y temporal, y al usar una instrucción no temporal le está indicando al procesador que no espera que el elemento de datos se use en un futuro próximo.

Soy un poco escéptico sobre el ensamblaje codificado a mano que usa las instrucciones de control de caché. En mi experiencia, estas cosas conducen a más errores malignos que cualquier aumento efectivo del rendimiento.

Pramod
fuente
pregunta sobre "ensamblaje codificado a mano que usa las instrucciones de control de caché". Sé que dijiste explícitamente "codificado a mano" ¿qué pasa con algo como un JavaVM? ¿Es este un mejor caso de uso? JavaVM / Compiler ha analizado el comportamiento estático y dinámico del programa y utiliza estas instrucciones intemporales.
Pat
4
No se debe evitar la explotación de propiedades de localidad conocidas (o la falta de ellas) de su dominio, algoritmo o aplicación del problema. Evitar la contaminación del caché es de hecho una tarea de optimización muy atractiva y eficaz. Además, ¿por qué la aversión al montaje? Hay una gran cantidad de oportunidades de ganancias disponibles que un compilador no puede aprovechar
awdz9nld
5
Definitivamente es cierto que un programador de bajo nivel con conocimientos puede superar a un compilador para núcleos pequeños. Esto es genial para publicar artículos y entradas de blog y he hecho ambas cosas. También son buenas herramientas didácticas y ayudan a comprender lo que "realmente" está sucediendo. Sin embargo, en mi experiencia, en la práctica, donde tienes un sistema real con muchos programadores trabajando en él y la corrección y la capacidad de mantenimiento son importantes, el beneficio de la codificación de bajo nivel casi siempre se ve superado por los riesgos.
Pramod
4
@Pramod, ese mismo argumento se generaliza fácilmente a la optimización en general y no está realmente en el alcance de la discusión; claramente, la compensación ya se ha considerado o se ha considerado irrelevante dado el hecho de que ya estamos hablando de instrucciones no temporales
awdz9nld
7

De acuerdo con el Manual del desarrollador de software de arquitecturas Intel® 64 e IA-32, Volumen 1: Arquitectura básica, capítulo "Programación con Intel Streaming SIMD Extensions (Intel SSE)":

Almacenamiento en caché de datos temporales frente a no temporales

Los datos a los que hace referencia un programa pueden ser temporales (los datos se volverán a utilizar) o no temporales (los datos se referenciarán una vez y no se reutilizarán en el futuro inmediato). Por ejemplo, el código de programa es generalmente temporal, mientras que los datos multimedia, como la lista de visualización en una aplicación de gráficos 3D, a menudo no son temporales. Para hacer un uso eficiente de las cachés del procesador, generalmente es deseable almacenar en caché los datos temporales y no los datos no temporales. La sobrecarga de las cachés del procesador con datos no temporales a veces se denomina "contaminar las cachés". Las instrucciones de control de capacidad de caché SSE y SSE2 permiten que un programa escriba datos no temporales en la memoria de una manera que minimiza la contaminación de los cachés.

Descripción de las instrucciones de almacenamiento y carga intemporal. Fuente: Manual del desarrollador de software de arquitecturas Intel 64 e IA-32, volumen 2: referencia del conjunto de instrucciones

LOAD (MOVNTDQA — Cargar pista alineada no temporal de cuatro palabras dobles)

Carga una palabra cuádruple doble desde el operando de origen (segundo operando) al operando de destino (primer operando) utilizando una sugerencia no temporal si la fuente de memoria es el tipo de memoria WC (combinación de escritura) [...]

[...] el procesador no lee los datos en la jerarquía de caché, ni busca la línea de caché correspondiente de la memoria en la jerarquía de caché.

Tenga en cuenta que, como comenta Peter Cordes, no es útil en la memoria WB (escritura diferida) normal en los procesadores actuales porque se ignora la sugerencia de NT (probablemente porque no hay precapturadores de HW compatibles con NT) y se aplica la semántica de carga completa fuertemente ordenada . prefetchntase puede utilizar como carga reductora de contaminación desde la memoria WB

ALMACENAR (MOVNTDQ — Almacenar enteros empaquetados usando una pista no temporal)

Mueve los enteros empaquetados en el operando de origen (segundo operando) al operando de destino (primer operando) usando una sugerencia no temporal para evitar el almacenamiento en caché de los datos durante la escritura en la memoria.

[...] el procesador no escribe los datos en la jerarquía de caché, ni busca la línea de caché correspondiente de la memoria en la jerarquía de caché.

Usar la terminología definida en Rendimiento y políticas de escritura en caché , se pueden considerar como de escritura indirecta (sin asignación de escritura, sin recuperación al escribir).

Finalmente, puede ser interesante revisar las notas de John McAlpin sobre las tiendas intemporales .

chus
fuente
3
SSE4.1 MOVNTDQAsolo hace algo especial en regiones de memoria WC (combinación de escritura no almacenable en caché), por ejemplo, RAM de video. No es útil en absoluto en la memoria WB (escritura diferida) normal en el HW actual, la sugerencia de NT se ignora y se aplica la semántica de carga completa fuertemente ordenada. prefetchntaSin embargo, puede ser útil como carga reductora de contaminación de la memoria WB. ¿Las arquitecturas x86 actuales admiten cargas no temporales (de la memoria "normal")? .
Peter Cordes
2
Eso es correcto, las tiendas NT funcionan bien en la memoria WB, están ordenadas débilmente y, por lo general, son una buena opción para escribir grandes regiones de memoria. Pero las cargas de NT no lo son. El manual x86 en papel permite que la sugerencia de NT haga algo para cargas desde la memoria WB, pero en las CPU actuales no hace nada . (Probablemente porque no hay precapturadores de HW compatibles con NT.)
Peter Cordes
He agregado esa información relevante a la respuesta. Muchas gracias.
chus
1
@LewisKelsey: Las tiendas NT anulan el tipo de memoria. Es por eso que se pueden ordenar débilmente en la memoria WB. El efecto principal es evitar las RFO (aparentemente envían una invalidación que incluso borra otras líneas sucias cuando llegan a mem). También pueden volverse visibles fuera de servicio, por lo que no tienen que esperar hasta después de que se confirme una tienda anterior con falta de caché (normal) o hasta que una carga anterior con falta de caché obtenga datos. es decir, el tipo de cuello de botella sobre el que se pregunta en ¿Es la memoria fuera de cada núcleo siempre conceptualmente plana / uniforme / sincrónica en un sistema multiprocesador? .
Peter Cordes
1
@LewisKelsey: Un borrado de la máquina de pedidos de memoria podría eliminar cualquier carga posterior a una tienda UC que no debería haberse hecho antes, si fuera necesario. Aparte de eso, la orden de confirmación no entra en juego hasta que la tienda se retira del back-end fuera de servicio. Eso no puede suceder hasta que se haya ejecutado la dirección de tienda uop, momento en el que se puede comprobar el tipo de memoria para la dirección. Un uop de dirección de tienda comprueba la TLB cuando se ejecuta; así es como las CPU pueden detectar tiendas con fallas antes de que se retiren. No puede esperar hasta que la entrada SB esté lista para comprometerse con L1d; en ese punto, la ejecución ha pasado.
Peter Cordes