Tenga en cuenta que AMD Zen también tiene un caché uop, pero se sabe menos sobre sus componentes internos. Así que estás preguntando específicamente sobre el caché uop de Intel en la familia Sandybridge.
Según las pruebas de Agner Fog ( https://www.agner.org/optimize/ , específicamente su pdf de microarquía), está direccionado virtualmente (VIVT), guardando la latencia / potencia de las búsquedas de iTLB para los resultados de uop-cache. Y lo que hace posible integrar aún muy estrechamente el iTLB con el caché L1i, como es normal para un caché VIPT L1.
(También relacionado: ¿Qué técnica de mapeo de caché se usa en el procesador Intel Core i7? para un resumen de ese y otros cachés, y https://stackoverflow.com/tags/x86/info para más rendimiento / enlaces uarch.)
Una vez decodificada una ventana de 32 bytes.
Aquí es donde te equivocaste en tu proceso de pensamiento.
El caché de uop solo almacena en caché los uops que se decodifican a lo largo de la ruta de ejecución (especulativa). Las instrucciones x86 solo se pueden decodificar correctamente si conoce el punto de inicio correcto. Los bytes después de un incondicional. jmp
podría no ser el comienzo de una instrucción en absoluto.
Además, no desea contaminar la caché uop con muchas instrucciones de relleno de un solo byte entre las funciones (por ejemplo, 0x90 NOP o 0xcc
int3
utilizado por MSVC). O en general, con instrucciones "frías" que no se alcanzan durante la ejecución normal después de una rama tomada. Una "línea" / camino de uop-cache termina antes con un salto incondicional, o con un call
.
Los decodificadores heredados son instrucciones de decodificación que la CPU espera ejecutar realmente (introduciéndolos en el caché uop para su reutilización más tarde, y el IDQ para su uso inmediato), o están apagados . A diferencia de P4, los decodificadores heredados no son débiles; son similares a los decodificadores en Core2 / Nehalem, por lo que la ejecución desde L1i generalmente está bien, excepto en el código de alto rendimiento con un tamaño de instrucción promedio grande. No necesitan tratar de "construir rastros" antes de tiempo. (El caché uop es no una caché de rastreo de todos modos; No sigue los saltos. Pero de todos modos, no intenta llenar el caché uop para los 32 bytes de instrucción que podría ser almacenado en caché de inmediato.)
Pero curiosamente, Agner dice " El mismo fragmento de código puede tener varias entradas en la memoria caché μop si tiene varias entradas de salto "
Mi mejor adivinar Cómo funciona realmente la maquinaria de búsqueda de caché:
Dada una dirección virtual de 64 bits para recuperar el código de:
- Los 5 bits bajos son el desplazamiento relativo a un límite de 32 bytes.
- Los siguientes 5 bits son un índice. No 6 bits para líneas L1i de 64 bytes; obtener de la caché uop no se preocupa directamente por eso.
- Los bits más altos (hasta el bit 48) son la etiqueta.
Utilice el índice de 5 bits para seleccionar un conjunto.
Obtenga las 8 formas de ese conjunto (etiqueta + metadatos, y también datos en paralelo porque se trata de un caché de alto rendimiento).
Compara en paralelo para las 8 formas:
- etiqueta bits todos coinciden
- el desplazamiento está dentro del rango de inicio + longitud del código de máquina x86 de esta manera almacena en caché uops para. (Una forma solo puede almacenar en caché uops para 1 bloque contiguo de código de máquina x86).
A lo sumo, una forma en el conjunto tendrá ambas condiciones verdaderas para una dirección de instrucción dada. Si hay uno, este es tu hit, y puedes obtener uops de la forma que coincidió. (Al igual que con un caché de bytes regular, excepto que necesita verificar los metadatos para seleccionar de qué uop comenzar a buscar si saltó al medio de una manera).
Se trata de conjeturas basadas en cómo se realiza el caché de uop y cuando arroja formas. Pero puede ayudarte a obtener un modelo mental útil de ello.
Tenga en cuenta que la dirección no hace necesita ser 16 bytes alineados. Debe admitir de manera eficiente los objetivos de bifurcación que no estén alineados, así como el código de línea recta con límites de instrucción que no se alineen con los límites de 32 bytes. (Lo mejor que puedo decir es que las instrucciones que cruzan un límite de 32 bytes se almacenan en caché de forma uop-caché para la dirección de inicio de la instrucción, incluso si termina en la siguiente línea de caché L1i a través de un límite de 64 bytes).
Los bloques de recuperación / decodificación de L1i para la longitud de la instrucción están alineados, pero la decodificación completa en los decodificadores heredados funciona en hasta 16 bytes de cualquier alineación, tomada de la cola entre la decodificación y la decodificación. La alineación de los puntos de entrada del bucle a ciertos límites de alineación es menos importante de lo que solía ser.
Entonces supongo que hay una comprobación de que la dirección de recuperación coincide exactamente con una de las direcciones de inicio de instrucciones de la forma seleccionada. Esto no se admite de manera eficiente, porque solo el código confuso decodifica los mismos bytes de dos maneras diferentes.
La memoria caché de uop no puede almacenar ambas formas al mismo tiempo, por lo que, al detectar esto, la CPU tiene que recurrir a los decodificadores heredados y descartar las formas de caché uop para este bloque 32B (que ya detectó con el comparador de etiquetas).
Luego puede comenzar a rellenar nuevamente el uop-cache a medida que decodifica uops desde este punto.
Algo similar sucede cuando 3 formas ya están llenas, pero hay más uops del mismo bloque 32B de código de máquina x86. El uop-cache arroja las 3 formas para ese bloque. (No estoy seguro de si recuerda no intentar almacenarlos en la memoria caché para la próxima vez, o si simplemente crea la memoria caché cada vez y la tira cuando llega al límite, en un bucle con 20 bytes individuales). nop
instrucciones por ejemplo.)
Ver Alineación de bifurcaciones para bucles que incluyen instrucciones microcodificadas en las CPU de la familia Intel SnB para algunos detalles sobre este caso . Tenga en cuenta que las instrucciones codificadas micro como div
utilizan toda la forma del caché uop por sí mismos, y pueden llevar fácilmente a llenar los 3 modos y activar los conmutadores DSB a MITE (el caché uop a los conmutadores de decodificación heredados puede crear una burbuja de 1 ciclo en el extremo frontal) ).
Ese Q & amp; A tiene muchos experimentos detallados y conclusiones sobre cómo los uops se almacenan en caché. No tanto sobre cómo se implementa físicamente el caché uop; Eso es puramente conjeturas por mi parte aquí.
También tenga en cuenta que las CPU de Intel antes de Skylake solo pueden agregar 4 uops al IDQ desde el caché de uop, pero de alguna manera no obstaculizan cuando hay formas en el caché de uop que tienen 3 o 6 uops en lugar de 4. Entonces IDK si hay algún tipo del almacenamiento en búfer para la captura uop no ramificada. Esto es un poco de un misterio. Es de esperar que el patrón de 4, 2, 4, 2 se recupere si se obtiene de líneas completas de 6 uops cada una, pero no vemos un cuello de botella en el extremo frontal para los bucles que se ejecutan desde el caché uop con 2 -byte instrucciones como xor eax,eax
. Intel ha declarado que el caché uop solo puede recuperar uops de 1 forma por ciclo, por lo que tal vez el límite de 4 uop sea solo para agregar al IDQ, no para leer desde el caché uop en algún búfer de combinación.