¿Cuál es el costo de la operación atómica (cualquiera de comparación e intercambio o adición / disminución atómica)? ¿Cuántos ciclos consume? ¿Pausará otros procesadores en SMP o NUMA, o bloqueará los accesos a la memoria? ¿Vaciará el búfer de reordenamiento en la CPU fuera de servicio?
¿Qué efectos habrá en la caché?
Estoy interesado en CPU modernas y populares: x86, x86_64, PowerPC, SPARC, Itanium.
Respuestas:
He buscado datos reales de los últimos días y no encontré nada. Sin embargo, hice una investigación que compara el costo de las operaciones atómicas con los costos de los fallos de caché.
El costo del prefijo x86 LOCK, (incluido
lock cmpxchg
para CAS atómico), antes de PentiumPro (como se describe en el documento), es un acceso a la memoria (como una pérdida de caché), + detener las operaciones de memoria de otros procesadores, + cualquier disputa con otros procesadores tratando de BLOQUEAR el autobús. Sin embargo, desde PentiumPro, para la memoria caché de escritura diferida normal (toda la memoria con la que se ocupa una aplicación, a menos que hable directamente con el hardware), en lugar de bloquear todas las operaciones de memoria, solo se bloquea la línea de caché relevante (según el enlace en la respuesta de @ osgx ) .es decir, el núcleo demora la respuesta a las solicitudes de participación MESI y RFO para la línea hasta después de la parte de almacenamiento de la
lock
operación ed real . Esto se denomina "bloqueo de caché" y solo afecta a esa línea de caché. Otros núcleos pueden estar cargando / almacenando o incluso colocando otras líneas al mismo tiempo.En realidad, el caso de CAS puede ser más complicado, como se explica en esta página , sin tiempos, pero con una descripción detallada de un ingeniero de confianza. (Al menos para el caso de uso normal en el que realiza una carga pura antes del CAS real).
Antes de entrar en demasiados detalles, diré que una operación BLOQUEADA cuesta una pérdida de caché + la posible contención con otro procesador en la misma línea de caché, mientras que CAS + la carga anterior (que casi siempre se requiere excepto en mutexes, donde siempre CAS 0 y 1) puede costar dos fallos de caché.
Explica que una carga + CAS en una sola ubicación en realidad puede costar dos fallas de caché, como Load-Linked / Store-Conditional (ver allí para el último). Su explicación se basa en el conocimiento del protocolo de coherencia de caché MESI . Utiliza 4 estados para una línea de caché: M (odificado), E (exclusivo), S (hared), I (no válido) (y por lo tanto se llama MESI), explicado a continuación cuando sea necesario. El escenario, explicado, es el siguiente:
En todos los casos, una solicitud de línea de caché puede ser detenida por otros procesadores que ya están modificando los datos.
fuente
Hice algunos perfiles con la siguiente configuración: Se arrancó la máquina de prueba (AMD Athlon64 x2 3800+), se cambió al modo largo (interrupciones desactivadas) y la instrucción de interés se ejecutó en un bucle, se desenrollaron 100 iteraciones y 1000 ciclos de bucle. El cuerpo del bucle se alineó con 16 bytes. El tiempo se midió con una instrucción rdtsc antes y después del ciclo. Además, se ejecutó un bucle ficticio sin ninguna instrucción (que midió 2 ciclos por iteración de bucle y 14 ciclos para el resto) y el resultado se restó del resultado del tiempo de perfilado de la instrucción.
Se midieron las siguientes instrucciones:
lock cmpxchg [rsp - 8], rdx
" (tanto con coincidencia de comparación como con discrepancia),lock xadd [rsp - 8], rdx
",lock bts qword ptr [rsp - 8], 1
"En todos los casos, el tiempo medido fue de aproximadamente 310 ciclos, el error fue de aproximadamente +/- 8 ciclos
Este es el valor para la ejecución repetida en la misma memoria (en caché). Con una falta de caché adicional, los tiempos son considerablemente más altos. Además, esto se hizo con solo uno de los 2 núcleos activos, por lo que el caché era de propiedad exclusiva y no se requirió sincronización de caché.
Para evaluar el costo de una instrucción bloqueada en un error de caché, agregué una
wbinvld
instrucción antes de la instrucción bloqueada y puse elwbinvld
másadd [rsp - 8], rax
en el ciclo de comparación. En ambos casos, el costo fue de aproximadamente 80.000 ciclos por par de instrucciones. En caso de bloqueo bts, la diferencia de tiempo fue de aproximadamente 180 ciclos por instrucción.Tenga en cuenta que este es el rendimiento recíproco, pero dado que las operaciones bloqueadas son operaciones de serialización, probablemente no haya diferencia en la latencia.
Conclusión: una operación bloqueada es pesada, pero una falta de caché puede ser mucho más pesada. Además: una operación bloqueada no provoca pérdidas de caché. Solo puede causar tráfico de sincronización de caché, cuando una línea de caché no es de propiedad exclusiva.
Para arrancar la máquina, utilicé una versión x64 de FreeLdr del proyecto ReactOS. Aquí está el código fuente de ASM:
fuente
En SMP basado en bus, el prefijo atómico
LOCK
afirma (enciende) una señal de cable de busLOCK#
. Prohibirá otros cpus / dispositivos en el bus para usarlo.Libro Ppro & P2 http://books.google.com/books?id=3gDmyIYvFH4C&pg=PA245&dq=lock+instruction+pentium&lr=&ei=_E61S5ehLI78zQSzrqwI&cd=1#v=onepage&q=lock%20instruction%20pentium&q=false pages
fuente