Pregunta ¿Cuándo se requieren las instrucciones x86 LFENCE, SFENCE y MFENCE?


Ok, he estado leyendo los siguientes Qs de SO con respecto a las vallas de la CPU x86 (LFENCE, SFENCE y MFENCE)

y:

y debo ser honesto, todavía no estoy totalmente seguro de cuándo se requiere una valla. Estoy tratando de entender desde la perspectiva de eliminar los bloqueos completamente soplados y tratar de usar un bloqueo granular más fino a través de vallas, para minimizar los retrasos de latencia.

En primer lugar, hay dos preguntas específicas que no entiendo:

A veces, al hacer una tienda, una CPU escribirá en su búfer de tienda en lugar de la memoria caché L1. Sin embargo, no entiendo los términos en los que una CPU hará esto.

CPU2 puede desear cargar un valor que haya sido escrito en el almacenamiento intermedio de almacenamiento de CPU1. Según tengo entendido, el problema es que la CPU2 no puede ver el nuevo valor en el almacenamiento intermedio de almacenamiento de la CPU1. ¿Por qué no puede el protocolo MESI simplemente incluir búferes de tienda de descarga como parte de su protocolo?

De manera más general, ¿podría alguien intentar describir el escenario general y ayudar a explicar cuándo? LFENCE/MFENCE y SFENCE instrucciones son requeridas?

NB Uno de los problemas que se leen en torno a este tema es la cantidad de artículos escritos "en general" para múltiples arquitecturas de CPU, cuando solo estoy interesado específicamente en la arquitectura Intel x86-64.


32
2017-12-22 01:40


origen


Respuestas:


La respuesta más simple: debe usar una de 3 vallas (LFENCE, SFENCE, MFENCE) para proporcionar uno de 6 datos de consistencia:

  • Relajado
  • Consumir
  • Adquirir
  • Lanzamiento
  • Adquisición-Liberación
  • Secuencial

C ++ 11:

Inicialmente, debería considerar este problema desde el punto de vista del grado de acceso a la memoria, que está bien documentado y estandarizado en C ++ 11. Deberías leer primero: http://en.cppreference.com/w/cpp/atomic/memory_order

x86 / x86_64:

1. Adquirir-Liberar consistencia: Entonces, es importante entender que en el x86 para acceder a la RAM convencional (marcada de forma predeterminada como WB - Write Back, y el mismo efecto con WT (Write Throught) o UC (Uncacheable)) usando asm MOV sin ningún comando adicional proporciona automáticamente el orden de memoria para Adquirir-Liberación de consistencia - std::memory_order_acq_rel. Es decir. para esta memoria tiene sentido usar solo std::memory_order_seq_cst solo para proporcionar consistencia secuencial. Es decir, cuando estás usando: std::memory_order_relaxed o std::memory_order_acq_rel entonces el código ensamblador compilado para std::atomic::store() (o std::atomic::load()) será el mismo, solo MOV sin ningún L/S/MFENCE.

Nota: Pero debe saber que no solo el compilador CPU y C ++ puede reordenar operaciones con memoria, y las 6 barreras de memoria siempre afectan en el compilador C ++ independientemente de la arquitectura de la CPU.

Entonces, debe saber cómo puede compilarse de C ++ a ASM (código de máquina nativo) o cómo puede escribirlo en el ensamblador. Para proporcionar cualquier Consistencia excluya Secuencial puede escribir fácilmente MOV, por ejemplo MOV reg, [addr] y MOV [addr], reg  etc.

2. Consistencia Secuencial: Pero para proporcionar consistencia secuencial debe usar implícita (LOCK) o cercas explícitas (L / S /MFENCE) como se describe aquí: ¿Por qué GCC no usa LOAD (sin cerca) y STORE + SFENCE para consistencia secuencial?

  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)

Por ejemplo, GCC usa 1, pero MSVC usa 2. (Pero debes saber que MSVS2012 tiene un error: ¿La semántica de `std :: memory_order_acquire` requiere instrucciones del procesador en x86 / x86_64? )

Luego, puedes leer Herb Sutter, tu enlace: https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c

Excepcion a la regla:

Esta regla es verdadera para el acceso al usar MOV a la RAM convencional marcada por defecto como WB - Write Back. La memoria está marcando en el Tabla de páginas, en cada PTE (página de tabla Enrty) para cada página (4 KB de memoria continua).

Pero hay algunas excepciones:

  1. Si marcamos la memoria en la Tabla de páginas como Escribir combinados (ioremap_wc() en POSIX), automáticamente solo proporciona Adquirir consistencia, y debemos actuar como en el siguiente párrafo.

  2. Ver respuesta a mi pregunta: https://stackoverflow.com/a/27302931/1558037

  • Las escrituras en la memoria no se reordenan con otras escrituras, con el siguientes excepciones:      
    • escrituras ejecutadas con la instrucción CLFLUSH;
    • almacenes de transmisión (escrituras) ejecutados con las instrucciones de movimiento no temporal (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS y MOVNTPD); y
    • operaciones de cuerda (ver Sección 8.2.4.1).

En ambos casos, 1 y 2, debe usar SFENCE entre dos escribe en la misma dirección, incluso si desea Acquire-Release Consistency, porque aquí automáticamente solo proporciona Acquire Consistency y debe hacer Release (SFENCE) tú mismo.

Responde tus dos preguntas:

A veces, al hacer una tienda, una CPU escribirá en el búfer de su tienda   en lugar de la caché L1. Sin embargo, no entiendo los términos de   que una CPU hará esto?

Desde el punto de vista del usuario, el caché L1 y el Tampón de Tienda actúan de manera diferente. L1 rápido, pero Store-Buffer más rápido.

  • Store-Buffer: es una cola sencilla donde solo se almacena Written, y que no se puede reordenar: está hecha para aumentar el rendimiento y ocultar la latencia de acceso a la caché (L1 - 1ns, L2 - 3ns, L3 - 10ns) (CPU-Core piense que Write ha almacenado en la memoria caché y ejecuta el siguiente comando, pero al mismo tiempo sus escrituras solo se guardan en el búfer de la tienda y se guardarán en la memoria caché L1 / 2/3 más tarde), es decir, CPU-Core no necesita esperar cuando las Escrituras se hayan almacenado en la memoria caché.

  • Caché L1 / 2/3: parece una matriz asociada transparente (dirección - valor). Es rápido, pero no el más rápido, ya que x86 proporciona automáticamente la consistencia de adquisición-liberación mediante el uso de caché coherente protocolo MESIF/MOESI. Se hace para una programación de hilos múltiples más simple, pero disminuye el rendimiento. (Verdaderamente, podemos usar algoritmos y estructuras de datos de Write Contentions Free sin utilizar el caché coherente, es decir, sin MESIF / MOESI, por ejemplo, sobre PCI-Express) Protocolos MESIF / MOESI funciona sobre QPI que conecta núcleos en CPU y núcleos entre diferentes CPU en sistemas multiprocesador (ccNUMA)

CPU2 puede desear cargar un valor que ha sido escrito en CPU1   almacenador de almacenamiento Según tengo entendido, el problema es que CPU2 no puede ver el   nuevo valor en el buffer de tienda de CPU1.

Sí.

¿Por qué no puede el protocolo MESI simplemente   incluye el lavado de buffers de la tienda como parte de su protocolo?

El protocolo MESI no puede incluir búferes de tienda de descarga como parte de su protocolo, porque:

  • Los protocolos MESI / MOESI / MESIF no están relacionados con el búfer de tienda y no lo conocen.
  • Vaciar automáticamente Buffer Store en cada Writes disminuiría el rendimiento y lo haría inútil.
  • La descarga manual de Buffer de Tienda en todos los CPU-Cores remotos (no sabemos en qué Core store-buffer contiene Write requerido) utilizando algún comando - disminuiría el rendimiento (en 8 CPUs x 15 Cores = 120 Cores al mismo tiempo Store -Buffer - esto es terrible)

Pero al descargar manualmente Buffer de tienda en el núcleo de la CPU actual, sí, puede hacerlo ejecutando SFENCE mando. Puedes usar SFENCE en dos casos:

  • Para proporcionar consistencia secuencial en la RAM con Write Back cacheable
  • Para proporcionar la consistencia de adquisición-liberación en excepciones de la regla: RAM con Write Combined cacheable, para escrituras ejecutadas con la instrucción CLFLUSH y para comandos SSE / AVX no Temporales

Nota:

Necesitamos LFENCE en cualquier caso en x86 / x86_64? - la pregunta no siempre es clara: ¿Tiene sentido alguna instrucción LFENCE en procesadores x86 / x86_64?

Otra plataforma:

Luego, puede leer como en teoría (para un procesador esférico in vacuo) con Store-Buffer y Invalidate-Queue, su enlace: http://www.puppetmastertrading.com/images/hwViewForSwHackers.pdf

Y cómo puede proporcionar consistencia secuencial en otras plataformas, no solo con L / S / MFENCE y LOCK pero y con LL / SC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html


31
2017-12-24 10:37