Microarquitectura: explicando los entresijos de un procesador – Parte 2/2

Al ser un tema algo complejo, he dividido el artículo en esta segunda parte para no alargar demasiado el anterior. Aun así, es extenso. Sigo en él el tema iniciado en la primera parte, donde intenté explicar cómo funciona una CPU, pero haciendo uso del diseño de la microarquitectura moderna para ello.

En el anterior mostré los conceptos fundamentales que deberías conocer sobre los diagramas de una CPU moderna, y en esta segunda parte «destriparé» las claves de una microarquitectura para que te hagas una idea de cómo ha evolucionado en la forma de tratar a las instrucciones y datos cuando se procesan procesados.

Decía la mujer de Jim Keller, para mí el arquitecto que más sabe de procesadores de alto rendimiento en el mundo y artífice de AMD Zen, que su marido llevaba años dibujando los mismos diagramas. Y es verdad que muchos diagramas se parecen enormemente, pero tienen algunas diferencias clave que cambian el comportamiento y el rendimiento de la CPU.

Explicación a fondo de una microarquitectura moderna AMD Zen

La arquitectura del procesador o microarquitectura, ya dije que es una implementación particular de una ISA. Con ella se puede determinar la forma en la que se van a manejar las instrucciones y datos. De este diseño dependerá el rendimiento IPC que tenga, la cantidad de unidades de ejecución (superescalar), la profundidad del cauce segmentado (pipeline), la cantidad de instrucciones y threads que pueda ejecutar de forma simultánea, si se procesa en orden o fuera de orden, etc.

Para ejecutar un programa (conjunto de instrucciones y datos), la CPU necesita una serie de pasos básicos. El primero sería buscar o leer las instrucciones a ejecutar y luego los datos asociados necesarios. Entonces se ordenará a las unidades de ejecución apropiada que haga la operación necesaria, y luego se obtiene el resultado.

A pesar de que todos los procesadores hacen lo mismo, las diferencias entre el esquema que siguen, la cantidad de unidades funcionales diferentes que poseen (para enteros, coma flotante, cache, fetching, etc.), hacen que de una microarquitectura a otra haya grandes diferencias.

Introducción a Zen / Zen+ y sus claves

Tras la fallida AMD Fusion, la empresa completa se reinventó y puso en marcha un ambicioso plan que ha dado resultados. Por primera vez tras los K7 y K8 han estado en una posición en la que han dañado muy seriamente a Intel. Y ese ambicioso plan se ha denominado con el codename Zen.

El objetivo era conseguir un 40% a 52% más de IPC (6 instrucciones frente a las 4 de su antecesor), es decir, de instrucciones por ciclo de reloj que es capaz de ejecutar. Con un mejor diseño, una cache mejorada y optimización de la eficiencia se consiguió.

Eso incluye una serie de mejoras que incluyen también colas de retirada más largas, de load/store, planificadores de instrucciones mayores, mejora del ancho de banda, unidad de predicción de saltos avanzada con redes neuronales artificiales, un nuevo sistema SMT (frente al anterior CMT) capaz de ejecutar 2 threads por núcleo, etc. Por supuesto, todo eso ha venido acompañado de mejoras en los procesos de fabricación con transistores FinFET, nodos más pequeños, etc., lo que permite miniaturizar más el die, menor consumo/menos TDP, mayor frecuencia de reloj, menor latencia, etc.

Uno de los detalles que más llama la atención de Zen, la que se usa como base para Zen+ (2º Generación) y Zen 2 (3º Generación), es que han incluido una cache o buffer de microoperaciones, como también tienen algunos diseños Intel (véase Conroe). En Bulldozer no se tenía dicha cache, por eso requería a la CPU obtener la información desde otros niveles de la memoria cache. Eso está haciendo que AMD recupere terreno perdido con respecto a Intel en el rendimiento single-core, ya que en los últimos años descuidó un poco la zona del Front-end.

Las mejoras en la predicción de bifurcaciones se ha mejorado enormemente también, y hay un nuevo decodificador de instrucciones capaz de decodificar 4 instrucciones CISC (AMD64 o x86-64) a varias microoperaciones simples tipo RISC (recuerda que te hablé de RISC-like).

Una vez decodificadas, las microoperaciones pasan a una cola, con ayuda del buffer de operaciones, para poder entregar hasta 6 de ellas en cada ciclo para el planificador. Éste último será el que decida cuándo se irán ejecutando en las unidades funcionales de ejecución (back-end), según vayan quedando desocupadas (idle).

El motivo de que la cola sea mayor a la cantidad de instrucciones que puede decodificar el decodificador es porque, como ya sabes, algunas instrucciones se pueden dividir en más de una microops como ya sabes. Por cierto, esta cola alimentará tanto a las unidades funcionales de enteros como a las de coma flotante, pero separándolas. Eso difiere de las microarquitecturas de Intel, que tienen un sistema unificado y que no separa como en AMD.

En AMD, el lado que conecta con la parte de enteros del back-end alimentará la ALU, AGU y Load/Store (cada unidad puede realizar 2 cargas de 16-bytes y un almacenamiento de 16-bytes por ciclo usando la cache L1D de 32KB y 8 vías tipo write-back).

En el lado del coma flotante, se alimentarán las unidades FMAC o AVX (vectorial). Al tener dos puertos de multiplicación y otros dos de suma, eso puede permitir dos operaciones FMAC a la vez o una AVX de 256-bit por cada ciclo de reloj. Así es como AMD consigue gran paralelismo a nivel de instrucción.

En cuanto a los niveles de cache, hay 3 niveles, al igual que en su antecesor. Pero hay pequeños cambios. Algunos ya los he citado. Tenemos la L1 para datos, L1 para instrucciones, L2 unificada y L3 unificada:

  • L1I: la de primer nivel para instrucciones es de 64 KB y 4-way, frente a 2-way de los Bulldozer por cada módulo (recuerda que usa módulos y no núcleos completos, ya que compartían la FPU, algo muy criticado en esos antiguos diseños y que se ha reparado en Zen).
  • L1D: ahora, el nivel 1 para datos se ha diseñado con 32 KB de memoria y 8-way, pero es de tipo write-back. En los Bulldozer se tenía 16 KB, 4-way y era de tipo write through.
  • L2: la memoria cache de nivel 2 se ha diseñado con una capacidad de 512 KB y 8-way por núcleo. Antes se usaba un esquema de 2MB y 16-way por módulo.
  • L3: en el nivel 3 se puede llegar a los 2MB de capacidad y 16-way. Eso es bastante distante de los 64-way por núcleo de la anterior microarquitectura.

Por supuesto, se han mejorado los anchos de banda de las memorias y se han reducido las latencias para un acceso más rápido. Por cierto, en cuanto al TLB, en AMD Zen hay dos: ITLB y DTLB. Se separa para instrucciones y datos, como es habitual, y en el caso del ITLB tiene varios niveles L0, L1, L2 con 8, 64 y 512 entradas respectivamente, además de protección por paridad. Para el DTLB se tiene L1, L2, con 64 y 1532 entradas respectivamente, así como protección por paridad también.

Todo lo que he venido explicando sobre x-way, por si no sabes a qué me refiero, te lo resumo de forma sencilla. Para mejorar la transición memoria-CPU se usa una técnica conocida como interleaving. Eso significa que se divide la memoria en bloques o vías (way). Por ejemplo, si tienes un 2-way, permitirá a la CPU trabajar de manera independiente con cada una de las vías. Eso quiere decir que se pueden hacer dos accesos (lectura o escritura) simultáneamente.

Por otro lado, también he hablado del write-through y write-back. Son dos formas de operar de la memoria. En el primero, se modifica tanto la cache como la memoria principal (RAM) para que no haya datos obsoletos y mantener una coherencia. Es un sistema simple para su implementación, pero necesita escribir dos veces, lo que no es muy bueno en cuanto a rendimiento.

Por eso, en esos sistemas se suele incluir un write buffer para paliar la pérdida de tiempo. En cambio, en el write-back, solo escribe en la cache y, solo en caso de que la información escrita vaya a ser reemplazada, también lo modifica en la memoria principal. Eso mejora el rendimiento, mejorando la velocidad y reduciendo el ancho de banda ocupado en estos accesos. El único inconveniente es que es un poco más compleja de implementar, y hay que añadir un bit adicional en cada línea de cache llamado dirty bit (indica si es necesario la escritura en otro nivel de memoria o no).

En cuanto a AMD Zen+, si recuerdas la estrategia Tick-Tock de Intel (Sandy Bridge fue una nueva microarquitectura que se fabricó con nodo de 32nm en el «tock», igual que su antecesor, y para el «tick» se usaron 22nm), AMD ha hecho algo similar. Zen es la mejora de la microarquitectura con respecto a sus antecesores y Zen+ toma ventaja de las mejoras en los procesos de fabricación para obtener más rendimiento.

Explicación de la Zen 2

AMD Zen 2 no es una mejora del proceso de fabricación con respecto a Zen, como lo era Zen+. En este caso sí que se han implementado muchas mejoras en la microarquitectura, aunque también se ha acompañado de un proceso de 7nm en algunos casos, que la hace aún más poderosa. Según estimaciones debe tener un 15% más de rendimiento IPC con respecto a Zen+ a igual frecuencia reloj. También se han optimizado para obtener un 1.25x de rendimiento a igual consumo (TDP). Combinando esos datos se consigue +75% de rendimiento/vatio frente a la antecesora y un +45% frente a la competencia.

Chiplets son diseños que usan varios dados en un mismo empaquetado. Para conseguir un mayor core-count, AMD ha optado por este sistema usando, por ejemplo, 4 chiplets con 8 cores cada uno para obtener recuentos de 32 núcleos en algunos diseños EPYC, Threadripper, etc. Para interconectarlos entre sí, se usa un chip o die adicional fabricado en 12nm que tiene la lógica de conexión. Para el futuro ya está pensando en mejorar esto con tecnología de empaquetamiento 3D. Eso aumenta el yield (rendimiento) en la fabricación de los wafers, ya que reduce la superficie del dado frente a los diseños monolíticos de Intel. Eso permite integrar más y más núcleos y que sean más baratos. El inconveniente que tiene es que la comunicación entre ellos puede no ser tan eficiente al tener que pasar de un dado a otro. Aunque Infinity Fabric de AMD ha puesto su fuerza bruta para minimizar este problema.

Además de agregar algunas mejoras de seguridad, y optimizaciones varias, así como nuevas tecnologías, AMD también se ha encargado de rediseñar el back-end y front-end con respecto a Zen para conseguir esas cifras.

Incluso se han agregado algunas nuevas instrucciones al repertorio (ISA) como es habitual en algunos casos. Por ejemplo, se ha incluido la CLWB para que un programa pueda regresar datos a una memoria no volátil en caso de recibir un comando de detención, evitando que se pierdan datos. La otra instrucción agregada es WBNOINVD, que permite predecir algunos bloques de memoria cache que se necesitarán para cálculos futuros y así estarán listos para acelerar el proceso.

También aparece una mejora en cuanto a la cache para micro-ops, ya que se ha aumentado a 4K de longitud (duplicado), aprovechando el espacio dejado al reducir la L1I a la mitad. Ten en cuenta que el espacio en el dado de silicio no puede crecer en exceso, por eso AMD ha simulado varios escenarios de rendimiento con el doble de L1I y mitad de cache para micro-ops, o con la mitad y doble de cache para micro-ops, para determinar cuál de los dos consigue más rendimiento. Al final han optado por el segundo.

La memoria cache L3 se ha duplicado frente a la capacidad vista en Zen/Zen+, se ha reducido a la mitad la capacidad de la L1I (pero se ha duplicado la asociatividad con 8 vías en vez de 4), BTB mayor para L1 (de 256 entradas para predicción ha pasado a 512), mejoras en las memorias del TLB, se han aumentado a 180 entradas registros para el renombre (en vez de las 160 de antes), hay 3 AGUs en vez de 2 unidades.

Aunque en el front-end se ve parecido a Zen, pero hay algunos cambios destacados en el diseño, como un predictor diferente y en el que se ha pasado de 4K de entradas a 7K. Es un TAGE (TAgged GEometric), lo que tiene ventajas, que en mi opinión, frente a otros predictores, son:

  • Etiquetado de entradas: algo que no hacen otros, y simplemente usan el historial y la dirección para indexar las entradas. Eso podría causar que en casos más largos se pudiera tener varios alias para una misma entrada. Eso con el etiquetado no pasa, determinando con certeza a la entrada que corresponde (especialmente importante en los predictores híbridos).
  • Selección de entrada: en este sentido también tiene ventajas, y tienen que ver con lo dicho en el anterior punto, ya que permiten hacer la selección de la entrada adecuada gracias a una granularidad más fina.
  • Mayor historial: también en referencia con lo anterior, se permiten usar historiales más largos. Todos estos puntos para recuperar en la L2 (para L1 se sigue usando uno basado en redes neuronales con perceptrón) mejoran bastante las rutas de predicción con un 30% menos de predicciones erróneas.

También hay soporte para AVX-256 en una sola operación (AVX2), sin tanta penalización para la frecuencia. Aquí ya no se necesita dividir una instrucción AVX2 en dos microoperaciones como en Zen/Zen+, solo se traduce en una sola microoperación. Por cierto, en cuando a las unidades de decodificación, cola y despacho no hay demasiados cambios para alimentar a las unidades de enteros y coma flotante…

Zen 2 basa una de sus claves de rendimiento precisamente en este soporte total para las extensiones de instrucciones vectoriales AVX2. El ancho de las unidades de ejecución ya no es de 128-bit, ahora es de 256-bit para permitir el cálculo en un solo ciclo en lugar de dividirlo en dos. A esto me refería en el párrafo anterior al decir «sin penalización de frecuencia».

También mejora las L/S de 256-bit, por lo que las unidades FMA pueden alimentarse de forma continuada. En cuanto a la unidad de coma flotante, aceptan colas de hasta 4 micro-ops por cada ciclo de reloj desde la unidad de despacho. Alimentan así un registro de 160 entradas y de ahí para a las unidades de ejecución para que sean alimentadas con datos de 256-bit en el sistema de carga y almacenamiento.

Además de todo eso, en el back-end también hay otra serie de cambios físicos y optimizaciones para mejorar el rendimiento en ciertas operaciones de cálculo repetitivas o con ciertas instrucciones multimedia. Incluso se ha reducido la latencia para la multiplicación de coma flotante. Ahora en vez de consumir 4 ciclos se consumen solo 3 de ellos (recuerda que no todas las instrucciones u operaciones necesitan de los mismos ciclos).

Los planificadores de las unidades enteras aceptan hasta 6 micro-ops por ciclo, y se alimentan por el buffer de reordenamiento de 224 entradas (en lugar de las 192 entradas de su antecesor). Técnicamente la unidad para enteros tiene 6 puertos que se componen de 4x ALUs, y 3 AGUs (como ya dije)… ¿falta un puerto? Sí, bueno… Los planificadores están constituidos por 4 colas de 16 entradas para las ALUs y de una sola cola para AGUs de 28 entradas, aunque para la unidad AGU se permitan alimentaciones de hasta 3 microoperaciones por ciclo.

Por cierto, no todas las AGUs son iguales. Al parecer, AMD ha optado por usar una AGU0 y AGU1 para que puedan hacer tanto cargas como almacenamiento, mientras que la AGU2 solo puede hacer almacenamiento. Esto es lo más óptimo para la mayor parte de los programas de uso cotidiano según ha determinado AMD con sus simulaciones.

Por cierto, AMD usa un término que es CCX (Core CompleX). Ya expliqué lo de los chiplets. Pues un CCX sería un conjunto de 4 núcleos agrupados. Pues bien, cada uno de esos CCX comparte una misma cache L3 con un tamaño de 16 MB. Al aumentar de 8MB a 16MB, la latencia ha aumentado ligeramente, lo que no es bueno.

  • Latencia de L1 es de 4 ciclos.
  • Latencia de L2 es de 12 ciclos.
  • Latencia de L3 ha aumentado de 35 a 40 ciclos. Aunque al poder manejar más datos e instrucciones podría paliar ese aumento de ciclos gracias a evitar mayor cantidad de fallos de cache.

Y termino con Infinity Fabric, un potente bus que AMD ha implementado y que ya cité. Ahora se ha actualizado a la versión IF2, con soporte para PCIe 4.0. Eso supone un aumento del ancho de bus de 256-bit a 512-bit para entrelazar a los CCXs. Parece que la mejora de eficiencia en general ha supuesto una mejora del 27% frente a IF1. Además, el reloj de IF2 se ha desacoplado de la frecuencia de la memoria principal DRAM. Eso permitió que la memoria principal pudiera ir más rápido en ceritos escenarios.

Si lo recuerdas, AMD ya hizo un gran trabajo con el bus HyperTransport. Un consorcio formado por varias importantes empresas hizo que esta tecnología la pudieran usar otros como Apple, Transmeta, Cisco, Broadcom, NVIDIA, Sun Microsystems (ahora Oracle), etc.

Infinity Fabric ha sido una evolución de HyperTransport. De hecho, no es una tecnología de bus nueva, se trata de un superset de ésta otra. De esa forma podían unir de forma rápida CPUs, GPUs o entre CCXs.Y a pesar de su complejidad, los resultados son alentadores.

Por ejemplo, para un chiplet de 4 dados, como el EPYC o Threadripper, IF permite una rotación de 180º en las comunicaciones para un enlace directo de todos los chips del empaquetado. Si se asume que se usa un sistema con DDR4-2400 (con reloj de 1200Mhz) se consiguen 38,4 GB/s bidireccionales de enlace die-to-die y uno total de 153,6 GB/s. O con una DDR4-2666 (clock de la DRAM de 1333.33Mhz), entonces cada enlace die-to-die tiene un ancho de banda bidireccional de 42,667 GB/s y un total de 170,667 GB/s.

Ya tenemos fuera Zen3 y viene Zen4… los ingenieros de AMD ya trabajan incluso en Zen5. Las microarquitecturas necesitan varios años de diseño al ser tan complejas. Pero estas ya las dejaré para otro post…

Isaac

Apasionado de la computación y la tecnología en general. Siempre intentando desaprender para apreHender.

2 comentarios sobre “Microarquitectura: explicando los entresijos de un procesador – Parte 2/2

  • el 08/05/2020 a las 1:12 PM
    Permalink

    Hola,

    He leido este articulo y la primera parte y me gustaria compartir mi opinion sobre el mismo.
    Primero indicar que soy ingeniero de software hace +20 años y algo de arquitectura conozco, pero vamos, lo que di en la universidad poco mas.
    He intentado seguir el hilo del articulo y supongo que es debido a la complejidad del tema que me ha sido imposible.
    A parte de dar una vision muy general (Von neumann), describes las partes y el funcionamiento de forma independiente, que me parece correcto.
    Sobre los componentes, seri mas adecuado indicar cual se funcionalidad, con que otros componentes estan directamente relacionados y poco mas, sin dar detalles mas profundos ni distinguir tipos o variantes, al principio.
    Y lo que mas hecho de menos, una vez se describen los componentes es algo, un hilo conductor que lo relaciones todo. Yo por ejemplo describiria la ejecucion de un pequeño progrsm e iria relatando como la cpu (sus componentes) van procesando las instrcciones. Asi quedaria muy claro cual es la funcionalidad de cada componente y como se relacionan entre ellos para conseguir el objetivo.
    Una vez entendido eso, entonces introduciria las variantes, mejoras, hibridaciones con explicaciones mas tecnicas si así se requiere o el tiempo lo permite de los componentes.

    Sigo este blog por que el tema me interesa mucho y realmente hay poco contenido de calidad en español, y menos aun con mas profundidad tecnica.
    Te doy las gracias y te animo a que sigas asi. Entro asiduamente para ver si hay contenido nuevo a diario.

    Offtopic:
    Veo que estas muy intereso en el proyecto EPI pero en mi humilde opinion lo que de verdad daria independencia es que la UE sea capaz de poder fabricar un procesador, no hace falta que sea a gran escala. Creo que sin desmerecer el diseño en el mundo de los procesadores el paso entre la teoria y la practica es abismal.
    Ya se que la inversion es descomunal, pero tambien creo que las instalaciones de Intel o TSMC son megafabs, ademas creo que la tecnologia de litografia que usan es europea (Holandesa?).

    Saludos

    Respuesta
    • el 08/05/2020 a las 2:00 PM
      Permalink

      Hola,
      Gracias por tu comentario.
      Tengo pensado explicar con código la relación que comentas y las partes. Estoy experimentando con un emulador de RISC-V muy interesante y publicaré algo al respecto en un futuro. De esa forma se entenderá mejor. De hecho, en los de introducción a la programación, compilación, etc., ya expliqué algo relacionado en cómo ejecutan instrucciones y demás…
      Ten en cuenta que son temas extremadamente complejos, la enciclopedia que escribí me llevó miles de páginas y 7 volúmenes… no es algo que se pueda explicar fácilmente en un artículo sin extenderlo demasiado.
      En cuanto a lo que comentas de EPI, sí, sería genial que Europa tuviera una foundry avanzada para fabricar chips. Pero por pequeña que sea la fab, es un gasto inmenso. Y cada actualización para pasar de un nodo a otro implicaría una inversión muy grande. Es por eso que cada vez más empresas se deshacen de sus fábricas y se transforman en fabless como AMD, Motorola, Philips, etc. Ni siquiera esas empresas tan potentes pueden hacer frente a ciertos gastos… En Europa ahora mismo se puede fabricar a 28nm (fab europea), o a 12nm (fab en territorio europeo, pero propiedad extranjera), y eso es un proceso muy anticuado para los actuales microprocesadores. Es triste, pero es así.
      Un saludo!

      Respuesta

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

A %d blogueros les gusta esto:

Si continuas utilizando este sitio aceptas el uso de cookies. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar