¿Tiene sentido usar la instrucción LFENCE en procesadores x86 / x86 64?


A menudo en Internet me parece que LFENCE no tiene sentido en los procesadores x86, es decir, no hace nada, por lo que en su lugar MFENCE podemos absolutamente indoloro usar SFENCE, porque MFENCE = SFENCE + LFENCE = SFENCE + NOP = SFENCE.

Pero si LFENCE no tiene sentido, entonces por qué tenemos cuatro enfoques para hacer Consistencia Secuencial en x86 / x86_64:

  1. LOAD (sin valla) y STORE + MFENCE
  2. LOAD (sin valla) y LOCK XCHG
  3. MFENCE + LOAD y STORE (sin valla)
  4. LOCK XADD ( 0 ) y STORE (sin valla)

Tomado de aquí: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

Así como las actuaciones de Herb Sutter en la página 34 en la parte inferior: https://skydrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&wdo=2&authkey=!AMtj_EflYn2507c

Si LFENCE no hizo nada, entonces el enfoque (3) tendría los siguientes significados: SFENCE + LOAD and STORE (without fence), pero no hay punto en hacer SFENCE antes de LOAD. Es decir, si LFENCE no hace nada, el enfoque (3) no tiene sentido.

¿Tiene algún sentido la instrucción LFENCE en los procesadores x86/x86_64?

RESPUESTA:

1. LFENCE requerido en los casos que se describen en la respuesta aceptada, a continuación.

2. El enfoque (3) no debe verse de forma independiente, sino en combinación con los comandos anteriores. Por ejemplo, approach (3):

MFENCE
MOV reg, [addr1]  // LOAD-1
MOV [addr2], reg  //STORE-1

MFENCE
MOV reg, [addr1]  // LOAD-2
MOV [addr2], reg  //STORE-2

Podemos reescriba el código de aproximación (3) como sigue:

SFENCE
MOV reg, [addr1]  // LOAD-1
MOV [addr2], reg  //STORE-1

SFENCE
MOV reg, [addr1]  // LOAD-2
MOV [addr2], reg  //STORE-2

Y aquí SFENCE tiene sentido para evitar reordenar STORE-1 y LOAD-2. Para esto, el comando after STORE-1 SFENCE limpia Store-Buffer.

Author: Flow, 2013-12-01

3 answers

Bottom line (TL;DR): LFENCE por sí solo parece inútil para ordenar la memoria, sin embargo, no hace que SFENCE sea un sustituto de MFENCE. La lógica" aritmética " de la pregunta no es aplicable.


Aquí hay un extracto de Intel Software Developers Manual, volumen 3 , sección 8.2.2 (la edición 325384-052US de septiembre de 2014), el mismo que usé en otra respuesta

  • Las lecturas no se reordenan con otras lecturas.
  • Las escrituras no se reordenan con lecturas más antiguas.
  • Las escrituras en memoria no se reordenan con otras escrituras, con las siguientes excepciones:
    • escribe ejecutado con la instrucción CLFLUSH;
    • el streaming almacena (escribe) ejecutado con las instrucciones de movimiento no temporales (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS y MOVNTPD); y
    • operaciones de cadena (véase la sección 8.2.4.1).
  • Las lecturas pueden reordenarse con escrituras más antiguas a diferentes ubicaciones pero no con escrituras más antiguas en la misma ubicación.
  • Las lecturas o escrituras no se pueden reordenar con instrucciones de E/S, instrucciones bloqueadas o instrucciones de serialización.
  • Las lecturas no pueden pasar instrucciones LFENCE y MFENCE anteriores.
  • Las escrituras no pueden pasar instrucciones anteriores de LFENCE, SFENCE y MFENCE.
  • LFENCE instrucciones no pueden pasar lecturas anteriores.
  • Las instrucciones de SFENCE no pueden pasar escrituras anteriores.
  • Las instrucciones MFENCE no pueden pase lecturas o escrituras anteriores.

De aquí se deduce que: {[35]]}

  • MFENCE es una valla de memoria completa para todas las operaciones en todos los tipos de memoria, ya sea no temporal o no.
  • SFENCE solo evita el reordenamiento de las escrituras (en otra terminología, es una barrera de almacén), y solo es útil junto con almacenes no temporales y otras instrucciones listadas como excepciones.
  • LFENCE evita reordenar las lecturas con lecturas y escrituras posteriores (i. e. combina barreras LoadLoad y LoadStore). Sin embargo, las dos primeras viñetas dicen que las barreras LoadLoad y LoadStore siempre están en su lugar, sin excepciones. Por lo tanto, LFENCE solo es inútil para ordenar la memoria.

Para apoyar la última afirmación, miré todos los lugares donde LFENCE se menciona en los 3 volúmenes del manual de Intel, y no encontré ninguno que dijera que LFENCE es necesario para la consistencia de la memoria. Incluso MOVNTDQA-la única instrucción de carga no temporal hasta ahora - menciona MFENCE pero no LFENCE.


Actualización: ver respuestas en ¿Por qué es (o no es?) SFENCE + LFENCE equivalente a MFENCE? para las respuestas correctas a las conjeturas a continuación

Si MFENCE es equivalente a una "suma" de otras dos vallas o no es una pregunta difícil. A primera vista, entre las tres instrucciones de valla solo MFENCE proporciona una barrera de carga de almacenamiento, es decir, evita el reordenamiento de lecturas con escrituras anteriores. Sin embargo, la respuesta correcta requiere saber más que las reglas anteriores; a saber, es importante que todas las instrucciones de la cerca se ordenen entre sí. Esto hace que la secuencia SFENCE LFENCE sea más poderosa que una mera unión de efectos individuales: esta secuencia también evita el reordenamiento de StoreLoad (porque las cargas no pueden pasar LFENCE, que no pueden pasar SFENCE, que no pueden pasar almacenes), y por lo tanto constituye una valla de memoria completa (pero también vea la nota (*) a continuación). Sin embargo, tenga en cuenta que el orden importa aquí, y la secuencia LFENCE SFENCE no tiene la misma sinergia efecto.

Sin embargo, mientras que uno puede decir que MFENCE ~ SFENCE LFENCE y LFENCE ~ NOP, eso no significa MFENCE ~ SFENCE. Uso deliberadamente equivalencia ( ~ ) y no igualdad ( = ) para enfatizar que las reglas aritméticas no se aplican aquí. El efecto mutuo de SFENCE seguido de LFENCE hace la diferencia; aunque las cargas no se reordenan entre sí, se requiere LFENCE para evitar el reordenamiento de cargas con SFENCE.

(*) Todavía podría ser correcto decir que MFENCE es más fuerte que la combinación de los otros dos valla. En particular, una nota a la instrucción CLFLUSH en el volumen 2 del manual de Intel dice que "CLFLUSH solo está ordenada por la instrucción MFENCE. No se garantiza que sea ordenado por cualquier otra instrucción de esgrima o serialización o por otra instrucción CLFLUSH."

(Update, clflush ahora se define como fuertemente ordenado (como una tienda normal, por lo que solo necesita mfence si desea bloquear más tarde cargas), pero clflushopt está débilmente ordenado, pero puede ser cercado por sfence.)

 29
Author: Alexey Kukanov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-09 10:22:52

Considere el siguiente escenario: este es el caso crítico donde la ejecución de carga especulativa puede dañar teóricamente la consistencia secuencial

Inicialmente [x] = [y]=0

CPU0:                              CPU1: 
store [x]<--1                      store [y]<--1
load  r1<--[y]                     load r2<--[x]

Dado que x86 permite que las cargas se reordenen con tiendas anteriores a diferentes direcciones, ambas cargas pueden devolver 0. Agregar una lfence solo después de cada tienda no evitaría eso, ya que solo evitan reordenar dentro del mismo contexto, pero como las tiendas se envían después del retiro, puede tener ambas lfences y ambas cargas se comprometen antes de que se realicen y observen las tiendas.

Un mfence por otro lado obligaría a los almacenes a funcionar, y solo entonces permitiría que las cargas se ejecutaran, por lo que verá los datos actualizados en al menos un contexto.

En cuanto a sfences - como se señala en el comentario, en teoría no es lo suficientemente fuerte como para evitar que la carga se reordene por encima de ella, por lo que aún podría leer datos obsoletos. Si bien esto es cierto en lo que respecta a la memoria oficial las reglas de orden se aplican, creo que la implementación actual de x86 uarch lo hace un poco más fuerte (aunque no se compromete a hacerlo en el futuro, supongo). Según esta descripción :

Debido al fuerte modelo de pedido x86, el búfer de carga se husmea por tráfico de coherencia. Un almacén remoto debe invalidar todas las demás copias de una línea de caché. Si una línea de caché es leída por una carga, y luego invalidado por un almacén remoto, la carga debe ser cancelada, ya que potencialmente leer datos no válidos. El modelo de memoria x86 no requiere husmeando en el buffer de la tienda.

Por lo tanto, cualquier carga aún no confirmada en la máquina debe ser snoopable por los almacenes de otros núcleos, haciendo así que el efectivo tiempo de observación de la carga en el punto commit, y no el punto de ejecución (que de hecho está fuera de servicio y puede haber sido realizado mucho antes). Commit se realiza en orden, y por lo tanto la carga debe ser observada después de las instrucciones anteriores-haciendo lfences bastante inútil como he dicho anteriormente en los comentarios, ya que la consistencia se puede mantener de la misma manera sin ellos. Esto es sobre todo especulación, tratando de explicar la concepción común de que las lfences no tienen sentido en x86 - no estoy del todo seguro de dónde se originó y si hay otras consideraciones a la mano - estaría feliz de que cualquier experto apruebe / desafíe esta teoría.

Todo lo anterior se aplica solo a los tipos de mem de WB curso

 7
Author: Leeor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-02 16:17:06

Por supuesto que hace sence!

LFENCE de la hoja de datos de Intel:

Realiza una operación de serialización en todas las instrucciones de carga desde la memoria que fueron emitidas antes de la instrucción de la LFENCE. Esta serialización operación garantiza que cada instrucción de carga que precede en orden del programa la instrucción de LFENCE es globalmente visible antes de cualquier la instrucción de carga que sigue la instrucción LFENCE es global visible.

Memory write instruction like MOV son atómicos si están correctamente alineados. Pero esta instrucción normalmente se ejecuta en la caché de la CPU y no será visible globalmente en este momento para todos los demás subprocesos, porque la memoria LFENCE/SFENCE or MFENCE debe ser preformada primero.

Caso típico:

Si el escritor de subprocesos desbloquea la región de memoria con instrucciones de escritura como memoria alineada MOV, por lo que no hay instrucciones de prefijo LOCK en uso, que la línea de caché donde se formó MOV será visible en un futuro muy corto para todos los demás subprocesos. LFENCE asegúrese de que al lector de hilos que también todas las demás líneas de caché de thread writer son globaly visibe!

 -1
Author: GJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-01 21:09:14