Chiplets de AMD: El truco que resucitó a Ryzen

¿Te fue útil?

Compras una estación de trabajo “de 16 núcleos”, lanzas una compilación y el gráfico de latencias parece un sismógrafo durante una pequeña crisis existencial.
O aprovisionas un host EPYC reluciente y ves que un microservicio vuela mientras otro arrastra—mismo código, misma carga, mismo día.

Esa es la era de los chiplets en producción: núcleos más baratos, más núcleos y una topología que castigará sin piedad las suposiciones perezosas.
La estrategia de chiplets de AMD no solo “mejoró el rendimiento”. Resucitó a Ryzen como línea de productos al cambiar las matemáticas de fabricación—y cambió cómo los operadores
deben diagnosticar cuellos de botella, ubicar memoria y fijar trabajo.

Chiplets en una frase (y por qué importó)

Una CPU por chiplets es un procesador construido a partir de múltiples dies más pequeños—típicamente dies de núcleos junto con un die de E/S—conectados por una interconexión de alta velocidad.

Si eres un SRE, tradúcelo así: el cómputo es modular, la E/S está centralizada y el acceso a memoria ya no es “uniforme” aunque tu planificador finja que sí.
Si eres ingeniero de almacenamiento, tradúcelo en: los controladores PCIe y de memoria viven en un die distinto a los núcleos que hacen checksum, codificación de borrado,
compresión y networking.

AMD puso esto en el mainstream. Y AMD lo hizo justo cuando los dies monolíticos de alto conteo de núcleos se volvían incómodamente caros de fabricar con fiabilidad.
Los chiplets fueron el truco que permitió a AMD enviar muchos núcleos con frecuencias competitivas y márgenes razonables, mientras iteraba rápidamente entre generaciones.

Contexto histórico rápido: los hechos concretos que prepararon el terreno

Unos cuantos hechos importan porque explican por qué los chiplets no fueron una elección de diseño simpática—fueron una vía de escape. Tenlos a mano.

  1. Las primeras CPU de escritorio Ryzen basadas en Zen de AMD se lanzaron en 2017, terminando un largo periodo donde “AMD vs Intel” no era un debate serio de rendimiento en muchos segmentos.
  2. Zen 2 (2019) fue el gran pivote hacia chiplets para el mainstream: los núcleos de CPU se movieron a varios dies más pequeños, emparejados con un die de E/S separado en un nodo de proceso distinto.
  3. El die de E/S en Zen 2 normalmente estaba en un nodo maduro (más antiguo, más barato, mayor yield), mientras los chiplets de núcleos iban a un nodo de vanguardia.
  4. EPYC “Rome” (Zen 2) escaló a muchos chiplets en servidores, probando el modelo en altos conteos de núcleos antes de que los escritorios absorbieran completamente las implicaciones.
  5. Infinity Fabric se convirtió en la “columna vertebral” que hizo factible el cómputo modular sin convertir cada fallo de caché en un desastre.
  6. La economía del yield se volvió brutal en nodos avanzados: cuanto mayor el die, más probable que un defecto arruine la pieza entera. Dies más pequeños mejoran la salida usable por oblea.
  7. Los chiplets habilitaron binning agresivo: AMD pudo mezclar chiplets de núcleo y segmentar SKUs sin diseñar un nuevo die monolítico cada vez.
  8. Los planificadores de Windows y Linux tuvieron que ponerse al día: la conciencia de la topología importa más cuando los núcleos están separados en dies y los controladores de memoria están en otro lugar.

La historia no es “AMD inventó los chiplets.” La historia es que AMD los operacionalizó a escala para piezas de consumo y servidor de una forma que cambió la pendiente precio/rendimiento.

Cómo funcionan realmente los chiplets de AMD: CCDs, IODs y la interconexión entre ellos

Las piezas: CCD y IOD

En los diseños por chiplets de AMD, normalmente tienes:

  • CCD (Core Complex Die): el tile de cómputo. Aquí residen los núcleos de CPU y sus cachés.
  • IOD (I/O Die): el tile que aloja controladores de memoria, controladores PCIe y, a menudo, otra infraestructura “no glamour” pero esencial.
  • Interconexión: Infinity Fabric enlaza estos dies.

Operacionalmente, eso significa que el núcleo de CPU que ejecuta tu proceso puede estar a un salto de die del controlador de memoria que maneja su tráfico DRAM y a un salto de die
del root complex PCIe que lleva las interrupciones NVMe. Ese salto es rápido. No es gratis.

La topología: “NUMA, pero sútil”

NUMA es más antiguo que la mayoría de los dashboards que miramos. Pero los chiplets lo volvieron relevante para gente que antes lo ignoraba.
Incluso dentro de un mismo socket, la latencia a memoria puede variar dependiendo de en qué CCD está tu núcleo y qué controlador de memoria (en el IOD) está sirviendo la petición.

Definición práctica: si una carga de trabajo es amigable con caché, los chiplets son mayormente una ganancia. Si es sensible a latencia de memoria con muchos accesos aleatorios,
los chiplets pueden convertirse en un impuesto de topología a menos que programes y asignes cuidadosamente.

Infinity Fabric: lo que te da y lo que te cobra

Infinity Fabric es la interconexión que cose los dies. No es “solo un bus.” Es un ecosistema: sincronización, coherencia
y cómo los dies de núcleos hablan con el die de E/S y, en sistemas multi-socket, potencialmente con otro socket.

En la práctica:

  • Mejor caso: la fabric es lo suficientemente rápida como para que la modularidad parezca invisible, y obtienes muchos núcleos a buen precio.
  • Peor caso: programas hilos across dies, rebotas líneas de caché y conviertes tu latencia p99 en un rasgo de personalidad.

Una cita para mantenerte honesto cuando te tienten a simplificar la topología:
La latencia es un impuesto que pagas por cada petición; el throughput es un dividendo que quizá cobres o no.
— Brendan Gregg (idea parafraseada)

Dos chistes en total, usados con responsabilidad

Chiste 1: Los chiplets son geniales porque ahora puedes tener ocho pequeñas CPUs discutiendo sobre coherencia de caché en lugar de una gran CPU haciéndolo en silencio.

Por qué esto resucitó a Ryzen: rendimiento de obleas, bins, cadencia y segmentación de productos

Economía de fabricación: dies más pequeños, mejores yields

Seamos directos: los chiplets permiten a AMD vender más silicio bueno por oblea. Los defectos ocurren. Son normales. Lo que importa es cuánto producto puedes rescatar.
Con un gran die monolítico, un defecto puede arruinar mucha área. Con múltiples dies más pequeños, un defecto arruina un chiplet.

Eso lo cambia todo: coste por núcleo usable, cuán agresivo puedes ser con el conteo de núcleos y cuántos SKUs puedes rentablemente enviar.
También significa que AMD puede usar nodos de vanguardia para los núcleos de CPU mientras mantiene la E/S en un nodo maduro más barato y a menudo eléctricamente más manejable para interfaces analógicas.

Flexibilidad de binning: mezclar piezas buenas en productos buenos

Los chiplets desbloquean binning práctico. Si un CCD tiene un núcleo con características ligeramente peores, puedes down-binear ese chiplet a un SKU inferior. Otro CCD con mejores características
puede ir a un SKU con mayor reloj. El IOD permanece en la misma familia. Esa modularidad mantiene la pila de productos completa sin exigir yields heroicos.

Esto también explica por qué obtienes piezas de gama media “sorprendentemente buenas” que overclockean como si quisieran demostrar algo: a menudo están hechas de chiplets excelentes que
no encajaron en un SKU superior por razones no relacionadas con rendimiento (inventario, demanda, segmentación).

Iteración más rápida: actualizar la E/S por separado de los núcleos (o viceversa)

Con chiplets, AMD puede evolucionar la arquitectura de núcleos y el nodo de proceso sin rehacer todo el subsistema de E/S a la misma cadencia.
Eso reduce riesgo. También reduce el tiempo al mercado. El IOD es complejo y está lleno de interfaces que son dolorosas en la punta de la tecnología.

Para los operadores, el efecto descendente es sutil: verás generaciones donde el cómputo crudo salta, pero la latencia de memoria o el comportamiento de E/S cambian de forma distinta.
No asumas que “CPU nueva” significa “misma topología con más GHz.”

Segmentar escritorio vs servidor sin reinventarlo todo

AMD puede escalar los mismos bloques básicos entre las familias Ryzen y EPYC, ajustando conteos y características de E/S para adecuarse a los mercados.
Eso no es solo eficiencia de negocio—es por qué Ryzen volvió con rendimiento creíble y por qué EPYC se convirtió en una opción seria para centros de datos.

Realidad de operaciones: dónde ayudan los chiplets y dónde castigan

Dónde los chiplets son una clara ventaja

  • Cargas paralelas: granjas de compilación, renderizado, compresión, cifrado, analítica, consolidación de VM—cualquier cosa que escale con núcleos y tolere algo de variación de localidad.
  • Escala coste-efectiva: más núcleos por dólar a menudo supera un p99 ligeramente peor, siempre que seas honesto sobre necesidades de cola de latencia.
  • Disponibilidad y diversidad de SKUs: el mercado acaba con CPUs “extrañamente específicas” que encajan en roles concretos de la flota.

Dónde los chiplets te castigan

El modo de fallo usualmente no es “lento.” Es “inconsistente.” Una ejecución está bien. La siguiente es 30% peor. Luego reinicias y mejora,
lo que convence a todos de que fue “transitorio.” No lo fue.

  • Planificación ciega a NUMA: hilos y asignaciones de memoria derivan por los dies.
  • Tormentas de interrupciones aterrizando en los núcleos equivocados: interrupciones de NIC/NVMe golpean un CCD lejano del trabajo.
  • Contención de locks entre dies: estructuras de datos compartidas rebotan líneas de caché sobre la fabric.
  • Sensibilidad a la latencia de memoria: stores clave-valor, cargas tipo trading, ciertas bases de datos y todo lo que viva de chase de punteros.

Chiste 2: Si tu rendimiento “mejora después de un reinicio”, felicidades—has inventado la ruleta de topología.

Qué hacer al respecto (alto nivel)

Trata la topología como un recurso de primera clase. Eso significa:

  • Mide latencia y ancho de banda de memoria, no solo la utilización de CPU.
  • Fija (pin) cargas críticas y su memoria al mismo nodo NUMA cuando sea posible.
  • Sé deliberado con las opciones de BIOS que alteran clocks de la fabric, estados de energía e intercalado de memoria.
  • Vigila la distribución de interrupciones y la afinidad de colas en NICs y NVMe de alto rendimiento.

Guion de diagnóstico rápido: encuentra el cuello de botella antes de que termine la reunión

Cuando un host Ryzen/EPYC por chiplets se siente “mal”, no tienes tiempo para filosofar. Necesitas una triage rápida que reduzca el espacio.

Primero: confirma la topología y la exposición NUMA

  • ¿Cuántos nodos NUMA ve el SO? ¿Mapean a las expectativas?
  • ¿La memoria está poblada uniformemente entre canales?
  • ¿Los núcleos están repartidos entre CCDs de forma que el planificador entienda?

Segundo: decide si el cuello de botella es cómputo, memoria o E/S

  • Limitado por cómputo: IPC alto, alta utilización de núcleos, p99 estable.
  • Limitado por memoria: IPC bajo, ciclos en stall altos, fallos de LLC altos, tráfico NUMA desigual.
  • Limitado por E/S: colas respaldadas, iowait alto, interrupciones en un subconjunto pequeño de CPUs, estrangulamiento PCIe, picos de latencia NVMe.

Tercero: busca “accidentes de topología”

  • Workloads migrando entre nodos NUMA (misconfiguración de cpuset/cgroup o comportamiento del scheduler).
  • Interrupciones NIC/NVMe mal asignadas.
  • Asignaciones de memoria remotas de los hilos que las usan (NUMA balancing peleando contigo).

Cuarto: valida ajustes de firmware y comportamiento de energía

  • Acoplamiento de clocks de la fabric, velocidad de memoria y estados de energía (C-states, CPPC, P-states).
  • Decisiones SMT on/off para latencias en cola.
  • Perfiles de rendimiento deterministas si tu proveedor los ofrece.

Quinto: solo entonces toca la afinación de la aplicación

Si la topología está equivocada, afinar la aplicación es puro teatro de rendimiento. Arregla la colocación primero.

Tareas prácticas con comandos: demostrar topología, medir, decidir

Estas son tareas que realmente ejecuto cuando se sospecha de la topología por chiplets. Cada una incluye: un comando, qué significa la salida y la decisión que tomas.
Suposición: host Linux. Si usas otra cosa, tu día ya es suficientemente complicado.

Task 1: Identify the CPU model and stepping

cr0x@server:~$ lscpu | egrep 'Model name|Socket|Thread|Core|NUMA|Vendor|CPU\(s\)'
CPU(s):                               64
Vendor ID:                            AuthenticAMD
Model name:                           AMD EPYC 7xx2 32-Core Processor
Thread(s) per core:                   2
Core(s) per socket:                   32
Socket(s):                            1
NUMA node(s):                         4
NUMA node0 CPU(s):                    0-15
NUMA node1 CPU(s):                    16-31
NUMA node2 CPU(s):                    32-47
NUMA node3 CPU(s):                    48-63

Significado: Un socket, 4 nodos NUMA expuestos. Eso es una señal de topología: la localidad de memoria importa incluso “dentro de una CPU”.

Decisión: Si la carga es sensible a latencia, planifica pinning NUMA y binding de memoria; de lo contrario acepta y enfócate en throughput.

Task 2: Validate NUMA memory availability per node

cr0x@server:~$ numactl --hardware
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 64512 MB
node 0 free: 60210 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 64512 MB
node 1 free: 61102 MB
node 2 cpus: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 2 size: 64512 MB
node 2 free: 60001 MB
node 3 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
node 3 size: 64512 MB
node 3 free: 61234 MB
node distances:
node   0   1   2   3
  0:  10  12  12  12
  1:  12  10  12  12
  2:  12  12  10  12
  3:  12  12  12  10

Significado: La memoria está provisionada equitativamente; la matriz de distancias muestra coste local vs remoto.

Decisión: Si un nodo tiene mucha menos memoria (o falta), corrige la población de DIMMs o el intercalado BIOS antes de culpar a la aplicación.

Task 3: Verify memory speed and channel population signals

cr0x@server:~$ sudo dmidecode -t memory | egrep 'Locator:|Speed:|Configured Memory Speed:|Size:'
Locator: DIMM_A1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_B1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_C1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s
Locator: DIMM_D1
Size: 32 GB
Speed: 3200 MT/s
Configured Memory Speed: 3200 MT/s

Significado: La velocidad configurada coincide con la nominal. Si ves 2133/2400 en una plataforma que debería correr a 3200, estás pagando un silencioso penal de latencia y ancho de banda.

Decisión: Arregla el perfil/compatibilidad de memoria en BIOS; revisa mezcla de DIMMs y reglas de población.

Task 4: See which CPUs are getting hammered by interrupts

cr0x@server:~$ cat /proc/interrupts | head -n 12
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
  24:  18423922          0          0          0          0          0          0          0  IR-PCI-MSI 524288-edge  nvme0q0
  25:         12          0          0          0          0          0          0          0  IR-PCI-MSI 524289-edge  nvme0q1
  40:   9234411          0          0          0          0          0          0          0  IR-PCI-MSI 1048576-edge  enp65s0f0-TxRx-0
  41:         34          0          0          0          0          0          0          0  IR-PCI-MSI 1048577-edge  enp65s0f0-TxRx-1

Significado: CPU0 está siendo machacada por colas NVMe y NIC. Eso suele correlacionar con jitter, picos de softirq y “por qué un core está al 100%?”

Decisión: Distribuye IRQs: habilita irqbalance (con cuidado), o asigna afinidad manualmente para colas críticas cerca del nodo NUMA del workload.

Task 5: Map a device to its NUMA node (NIC/NVMe locality)

cr0x@server:~$ cat /sys/class/net/enp65s0f0/device/numa_node
1

Significado: Esa NIC es local al nodo NUMA 1.

Decisión: Coloca los hilos de procesado de red más intensos en CPUs del nodo 1, y considera bindear buffers/procesamiento de red allí.

Task 6: Check PCIe link width/speed for “why is my NVMe slow?”

cr0x@server:~$ sudo lspci -s 41:00.0 -vv | egrep 'LnkCap:|LnkSta:'
LnkCap: Port #0, Speed 16GT/s, Width x4, ASPM L1, Exit Latency L1 <4us
LnkSta: Speed 8GT/s (downgraded), Width x4 (ok)

Significado: El dispositivo puede hacer 16GT/s pero está corriendo a 8GT/s. Eso es una pérdida real de throughput y latencia.

Decisión: Revisa ajustes BIOS PCIe, risers, cableado de slot y retimers. No “optimices” software por un problema de negociación hardware.

Task 7: Verify CPU frequency behavior under load (power states matter)

cr0x@server:~$ sudo apt-get -y install linux-tools-common linux-tools-generic >/dev/null
cr0x@server:~$ sudo turbostat --quiet --Summary --interval 1 --num_iterations 3
     Time_Of_Day_Seconds  Avg_MHz  Busy%  Bzy_MHz  IRQ   SMI   PkgTmp  PkgWatt
                54421.9     2875   62.3     4012  812     0      61     142.3
                54422.9     2910   64.1     3988  799     0      62     145.0
                54423.9     2842   60.8     4020  821     0      61     141.7

Significado: Ves MHz efectivos y Bzy_MHz. Si Bzy_MHz se colapsa bajo carga moderada, restricciones de energía o térmicas están golpeando.

Decisión: Para servicios críticos de latencia, selecciona un perfil de energía determinista y considera limitar C-states profundos.

Task 8: Inspect per-NUMA-node memory allocation of a process

cr0x@server:~$ pidof memcached
24831
cr0x@server:~$ numastat -p 24831
Per-node process memory usage (in MBs) for PID 24831 (memcached)
        Node 0  Node 1  Node 2  Node 3   Total
Huge       0.0     0.0     0.0     0.0     0.0
Heap   5120.0  1024.0   980.0   990.0  8114.0
Stack     8.0     8.0     8.0     8.0    32.0

Significado: El heap está repartido entre nodos. Eso puede estar bien para throughput; puede ser terrible para latencia de cola si los hilos están mayoritariamente en un nodo.

Decisión: Liga el proceso y su memoria a un nodo (o particiona por nodo). O ejecuta explícitamente múltiples instancias por nodo NUMA.

Task 9: Observe remote vs local memory accesses (kernel NUMA stats)

cr0x@server:~$ egrep 'numa_(hit|miss|foreign|interleave|local|other)' /proc/vmstat
numa_hit 428112233
numa_miss 2219921
numa_foreign 1941122
numa_interleave 0
numa_local 426331900
numa_other 1920333

Significado: numa_miss y numa_foreign muestran asignaciones cruzadas de nodo. Que suban rápido durante un incidente de latencia es una bandera roja.

Decisión: Investiga migración de procesos, NUMA balancing automático y la política de memoria. Arregla la colocación antes de tocar el código.

Task 10: Confirm scheduler and cgroup CPU pinning (is the service drifting?)

cr0x@server:~$ systemctl show -p AllowedCPUs -p AllowedMemoryNodes myservice.service
AllowedCPUs=
AllowedMemoryNodes=

Significado: Vacío significa “sin restricción.” Si esperabas pinning, no está ocurriendo.

Decisión: Añade CPUAffinity/AllowedCPUs y restricciones de nodos de memoria, o usa cpuset cgroup para imponer colocación.

Task 11: Pin a benchmark to one NUMA node to measure locality impact

cr0x@server:~$ numactl --cpunodebind=1 --membind=1 bash -lc 'python3 - <

Significado: Esto es una prueba burda de “tocar memoria”. Repite con bindings de diferentes nodos. Si los tiempos varían mucho, la localidad importa para tu clase de carga.

Decisión: Si las variaciones son grandes, diseña despliegues alrededor del sharding NUMA o binding explícito.

Task 12: Measure interconnect/topology with hwloc (visualize the chiplets)

cr0x@server:~$ sudo apt-get -y install hwloc >/dev/null
cr0x@server:~$ lstopo-no-graphics | head -n 30
Machine (256GB total)
  Package L#0
    NUMANode L#0 (P#0 64GB)
    L3 L#0 (32MB)
      L2 L#0 (512KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0
        PU L#0 (P#0)
        PU L#1 (P#1)
    NUMANode L#1 (P#1 64GB)
    L3 L#1 (32MB)
      L2 L#1 (512KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1
        PU L#2 (P#16)
        PU L#3 (P#17)

Significado: Puedes ver nodos NUMA y agrupaciones L3. En diseños por chiplets, estas agrupaciones a menudo se alinean con límites CCD/CCX.

Decisión: Usa esta vista para diseñar conjuntos de CPU para servicios: mantiene hilos comunicativos dentro del mismo dominio L3 cuando sea posible.

Task 13: Spot cross-die cache line bouncing with perf (lock contention hint)

cr0x@server:~$ sudo perf stat -e cycles,instructions,cache-misses,LLC-load-misses -p 24831 -- sleep 10
 Performance counter stats for process id '24831':

    38,112,004,991      cycles
    52,984,222,101      instructions              #    1.39  insn per cycle
       812,113,992      cache-misses
       204,113,100      LLC-load-misses

      10.003221861 seconds time elapsed

Significado: Altos LLC misses e IPC relativamente bajo pueden indicar presión de memoria. Combina esto con stats NUMA para distinguir “limitado por memoria” de “mala colocación.”

Decisión: Si los LLC misses se disparan cuando los hilos se dispersan por nodos, vuelve a pinnear; si los misses son inherentes, rediseña el layout de datos o la estrategia de caché.

Task 14: Check for Linux automatic NUMA balancing behavior

cr0x@server:~$ cat /proc/sys/kernel/numa_balancing
1

Significado: 1 significa que el balanceo NUMA automático está habilitado. Puede ayudar cargas generales, pero también causar migraciones impredecibles para servicios sensibles a la latencia.

Decisión: Si haces pinning explícito, considera deshabilitarlo (a nivel sistema o mediante aislamiento de la carga) y mide antes/después.

Task 15: Verify transparent hugepages status (latency vs throughput trade)

cr0x@server:~$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

Significado: THP está siempre activado. Esto puede ser bueno para throughput, pero puede añadir picos de latencia durante colapsos/defrag en algunas cargas.

Decisión: Para servicios sensibles a p99, haz benchmarks con THP=never o madvise y decide según p99, no según el promedio.

Task 16: Check memory bandwidth saturation quickly (vmstat + mpstat)

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 8123456 123456 987654   0    0     1     3  900 2200 45  8 45  2  0
 8  0      0 8012345 123456 988000   0    0     0     0 1100 5200 62 10 28  0  0
 9  0      0 7999999 123456 987900   0    0     0     0 1200 6000 65 11 24  0  0
 7  0      0 7988888 123456 987800   0    0     0     0 1180 5900 64 10 26  0  0

Significado: Muchos hilos en runnable (r) con iowait (wa) bajo sugiere presión de CPU/memoria más que de almacenamiento. Combina con perf/numastat para ver si es saturación de ancho de banda o latencia.

Decisión: Si la CPU está ocupada pero IPC es bajo y los NUMA misses suben, arregla la colocación; si no, considera reducir concurrencia o mejorar comportamiento de caché.

Tres micro-historias corporativas desde las trincheras

Mini-historia 1: El incidente causado por una suposición errónea

Un equipo movió una API sensible a latencia desde un host Intel de doble socket a una caja EPYC de un solo socket. El plan de migración fue simple:
“Mismos núcleos, misma RAM, menos sockets, así que debe ser más simple.” Su prueba de carga incluso se veía bien—al principio.

En producción no. p95 se mantuvo, p99 se disparó, y el on-call recibió la clásica combinación de alertas: latencia de solicitudes elevada, utilización de CPU normal, sin saturación clara de E/S.
El dashboard se veía tranquilo de la misma forma que un bosque tranquilo justo antes de que descubras que estás perdido.

La suposición incorrecta fue tratar “un socket” como “uniforme.” El servicio tenía una gran caché en memoria y unos pocos mutex muy calientes.
El scheduler migró hilos entre nodos NUMA dentro del socket, las asignaciones de memoria derivaron y las líneas de caché rebotaron sobre la fabric.
La latencia promedio no gritó. La latencia en cola sí.

La solución fue aburrida pero decisiva: pinnear el servicio a un nodo NUMA, bindear la memoria a ese nodo y ejecutar dos instancias en lugar de una instancia grande.
También movieron las interrupciones NIC al mismo nodo. El p99 se estabilizó. El equipo aprendió una nueva humildad: humildad topológica.

Accion postmortem que importó: añadir comprobaciones de NUMA y afinidad de IRQ al checklist de readiness, no a la página wiki de “tuning avanzado” que nadie lee.

Mini-historia 2: La optimización que se volvió en contra

Un servicio pesado en almacenamiento (piensa: metadata, checksums, compresión) estaba limitado por CPU en picos. Alguien propuso un cambio simple:
“Repartamos los hilos workers por todos los núcleos para maximizar paralelismo.” También activaron escalado automático agresivo basado en CPU, porque claro que sí.

El throughput mejoró en microbenchmarks. Los gráficos celebraban. Entonces el job semanal pegó y todo se fue al suelo:
los delays en colas subieron, el p99 se dobló y el sistema se comportó como si tuviera un generador de números aleatorios en el scheduler.

El revés fue contención cross-die. Repartir workers por CCDs aumentó el paralelismo, sí, pero también aumentó el tráfico de estado compartido.
La cola “global” y algunas tablas hash compartidas se convirtieron en hotspots de coherencia. La interconexión hizo su trabajo; la carga la castigó por ser útil.

La solución fue contraintuitiva si solo crees en conteos de núcleos: reducir el chatter cross-die mediante shardear colas por nodo NUMA y pinnear pools de workers.
Algunos workers quedaron inactivos y la utilización total de CPU bajó. La latencia mejoró. El throughput se mantuvo aceptable. Los gráficos dejaron de ser excitantes,
que es lo que quieres en producción.

La lección real: en CPUs por chiplets, “más núcleos” no es sinónimo de “más estado compartido barato.” Si tu algoritmo asume compartir barato, estás sujetando una granada por el alfiler.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Otra organización operaba una flota mixta: workstations Ryzen para CI y servidores EPYC para producción. Tenían una costumbre que parecía dolorosamente aburrida:
cada nuevo lote de hardware recibía una corrida estandarizada de validación de topología, y los resultados se adjuntaban al registro del activo.

Un trimestre, llegó un lote de servidores con una sutil misconfiguración de BIOS del proveedor: intercalado de memoria y un perfil de energía que favorecía
eficiencia por sobre latencia determinista. Nada estaba “roto.” Nada falló POST. Las máquinas incluso pasaron burn-in básico.

Pero su corrida de validación lo detectó: la latencia de memoria era mayor que en el lote anterior, y bajo carga el comportamiento de frecuencias era inconsistente.
Porque tenían baselines, tenían prueba. No discutieron desde sensaciones; discutieron desde mediciones.

Lo arreglaron antes de producción: ajustaron perfiles BIOS, estandarizaron firmware y repitieron las pruebas. El lote se unió a la flota sin ruido.
Sin incidente. Sin reunión de emergencia. Sin arqueología nocturna de “por qué p99 derivó”.

La práctica aburrida gana porque escala. Los heroísmos no. Si quieres fiabilidad, institucionaliza las comprobaciones poco glamurosas.

Errores comunes: síntoma → causa raíz → solución

1) Síntoma: p99 se dispara mientras CPU% parece correcto

Causa raíz: hilos migran entre nodos NUMA; las asignaciones de memoria se vuelven remotas; el tráfico de coherencia aumenta entre CCDs/IOD.

Solución: pinnear CPU y memoria (cpuset/numactl), shardear por nodo NUMA y validar con numastat -p y contadores NUMA en /proc/vmstat.

2) Síntoma: un core está al 100%, softirq alto, latencia de red con jitter

Causa raíz: afinidad de IRQ colapsada en una sola CPU (a menudo CPU0), o colas mal configuradas.

Solución: distribuir interrupciones, alinear colas con localidad NUMA, verificar con /proc/interrupts y el nodo NUMA del dispositivo en sysfs.

3) Síntoma: throughput NVMe menor de lo esperado tras cambio de hardware

Causa raíz: enlace PCIe entrenado a menor velocidad (downgrade), slot equivocado o ajustes BIOS limitando velocidad de enlace.

Solución: revisar lspci -vv LnkSta vs LnkCap; corregir slot/riser/BIOS; re-testear antes de tocar ajustes de sistema de archivos.

4) Síntoma: el rendimiento varía ejecución a ejecución con la misma carga

Causa raíz: NUMA balancing automático, deriva del scheduler o distintos patrones de asignación inicial.

Solución: imponer colocación; deshabilitar/ajustar NUMA balancing para el servicio; validar repitiendo una corrida benchmark pinneda.

5) Síntoma: “Más hilos” reduce throughput

Causa raíz: contención de locks cross-die; colas compartidas; ping-pong de líneas de caché.

Solución: shardear estado por nodo NUMA/CCD; reducir locks globales; usar pools de workers por nodo; medir LLC misses y contención de locks.

6) Síntoma: throughput estable, pero stalls largos periódicos

Causa raíz: colapso/defrag de THP, reclaim de memoria o transiciones de frecuencia/energía.

Solución: probar THP=never/madvise; asegurar margen suficiente; establecer perfiles de energía deterministas para sistemas sensibles a latencia.

7) Síntoma: la base de datos parece “CPU bound” pero IPC es bajo

Causa raíz: en realidad está limitada por latencia de memoria; memoria remota; mala localidad entre chiplets.

Solución: pinnear y bindear memoria; mover los datos más calientes a layouts amigables con caché; medir con perf + stats NUMA.

Listas de comprobación / plan paso a paso para despliegues amigables con chiplets

Plan paso a paso: admisión de un nuevo nodo Ryzen/EPYC

  1. Inventaria la topología: registra lscpu, conteo de nodos NUMA, conteo de cores/threads.
  2. Valida la población de memoria: usa dmidecode; confirma velocidad esperada y canales balanceados.
  3. Baseline de comportamiento NUMA: captura numactl --hardware matriz de distancias y tamaños de memoria por nodo.
  4. Baseline de comportamiento de frecuencias: mide bajo carga con turbostat y registra rangos “normales”.
  5. Valida enlaces PCIe: revisa velocidad/ancho negociado de NIC y NVMe con lspci -vv.
  6. Confirma localidad de dispositivos: registra nodo NUMA de dispositivos vía sysfs para NICs y NVMe principales.
  7. Define estrategia de IRQ: decide irqbalance vs afinidad manual; documéntalo y pruébalo.
  8. Define colocación de cargas: decide qué servicios requieren pinning y cuáles pueden flotar.
  9. Establece una prueba: ejecuta una prueba de toque de memoria pinneda o de ancho de banda por nodo y guarda resultados.
  10. Despliega en producción gradualmente: canary con cargas representativas; vigila p99 y NUMA misses.

Checklist: cuando un host por chiplets tiene latencia inexplicada

  • ¿Tenemos nodos NUMA inesperados o tamaños de memoria por nodo desiguales?
  • ¿Están las IRQ concentradas en un pequeño conjunto de CPUs?
  • ¿La NIC/NVMe está en un nodo NUMA distinto al de los hilos más ocupados?
  • ¿El enlace PCIe se entrenó a menor velocidad?
  • ¿Suben numa_miss/numa_foreign durante el incidente?
  • ¿El scheduler puede migrar el servicio entre nodos?
  • ¿Cambió firmware o BIOS (perfil de energía, intercalado de memoria, SMT)?

Checklist: diseñando para rendimiento predecible

  • Shardea por nodo NUMA cuando el estado sea grande y el acceso frecuente.
  • Mantén las IRQ locales al cómputo que maneja paquetes y completaciones de I/O.
  • Evita locks globales que forcen tráfico de coherencia cross-die.
  • Prefiere concurrencia acotada sobre “usar todos los núcleos” cuando p99 importe.
  • Haz benchmarks con pinning activado y desactivado para ver cuán sensible eres a la topología.

Preguntas frecuentes

1) ¿Los chiplets siempre son más rápidos que las CPUs monolíticas?

No. Los chiplets suelen ganar en precio/rendimiento y escalabilidad. Los diseños monolíticos pueden ganar en latencia uniforme y en ciertos patrones de compartición cache-coherente.
Elige según el comportamiento de la carga, no por adjetivos de marketing.

2) ¿Cuál es la diferencia operativa más grande con CPUs por chiplets?

La topología pasa a ser una característica de rendimiento. NUMA y la conciencia de dominios de caché importan en lugares donde antes te la habías podido saltar.

3) ¿Por qué AMD separó cómputo y E/S en dies distintos?

Porque es económicamente y técnicamente sensato: los núcleos de CPU se benefician de nodos de vanguardia; la E/S se beneficia de nodos maduros y comportamiento analógico estable.
Separarlos mejora yields y reduce riesgo por generación.

4) ¿Cuál es el “impuesto chiplet” más común en sistemas reales?

Acceso remoto a memoria y rebotes de líneas de caché cross-die. Ambos aparecen como latencia en cola, no necesariamente como una caída promedio.

5) ¿Debería deshabilitar SMT en Ryzen/EPYC por latencia?

A veces. SMT puede mejorar throughput pero empeorar latencia en cola cuando la contención es alta o ya eres sensible a topología.
Mide con carga similar a producción; no lo apliques por costumbre.

6) ¿El balanceo NUMA automático es bueno o malo?

Bueno para hosts de propósito general. Arriesgado para servicios cuidadosamente pinnados y sensibles a latencia porque puede migrar páginas de manera que cree jitter.
Si haces pinning explícito, considera deshabilitarlo para esos hosts o servicios—pero mide primero.

7) ¿Por qué dos sistemas “idénticos” Ryzen benchmarkean diferente?

Razones comunes: distinta población de memoria (canales), perfiles de energía BIOS distintos, acoplamientos fabric/memoria diferentes,
problemas de negociación de enlace PCIe y diferentes estados de scheduler/afinidad de IRQ.

8) ¿Cómo afectan los chiplets a cargas de almacenamiento específicamente?

Los stacks de almacenamiento mezclan CPU, memoria y PCIe. Si tu NVMe y las interrupciones de NIC aterrizan lejos de los hilos que hacen compresión/checksums,
pagas latencia extra y sobrecarga de coherencia. Alinea localidad de dispositivos, afinidad de IRQ y colocación de workers.

9) ¿Los chiplets hacen la virtualización más difícil?

No más difícil, pero menos perdonador. Si sobrecomprometes y permites que vCPUs floten entre dominios NUMA, puedes obtener efectos de vecino ruidoso y p99 impredecible.
La colocación de VMs consciente de NUMA y el pinning de CPU ayudan.

10) ¿Qué debo baselinear en cada nueva plataforma por chiplets?

Topología NUMA y distribución de memoria, estado de enlaces PCIe, comportamiento de frecuencias bajo carga y una instantánea de distribución de IRQs.
Si no puedes detectar deriva, no puedes prevenirla.

Conclusión: próximos pasos que realmente reducen el riesgo

Los chiplets de AMD resucitaron a Ryzen al cambiar la ecuación de fabricación: dies de núcleos más pequeños, mejores yields, escalado modular y iteración más rápida.
Esa decisión de negocio se convirtió en una realidad operativa: la topología ahora es parte del rendimiento, no una nota al pie.

Próximos pasos que deberías tomar esta semana, no “algún día”:

  • Elige un servicio sensible a latencia y mide la colocación NUMA hoy: numastat -p, contadores NUMA en /proc/vmstat y /proc/interrupts.
  • Canary una estrategia de pinning: liga CPU + memoria a un nodo, alinea IRQs, compara p99. Mantén el cambio pequeño y medible.
  • Institucionaliza una prueba de admisión de hardware: topología, velocidades de memoria, entrenamiento de enlaces PCIe y una comprobación de frecuencia.
  • Deja de confiar en promedios: los problemas de rendimiento por chiplets suelen ser problemas de cola que se disfrazan con un promedio amable.

Los chiplets no son una trampa. Son un trato: obtienes muchos núcleos a un precio sensato y, a cambio, aceptas tratar la topología como algo real.
Firma el contrato. Tu p99 te lo agradecerá.

← Anterior
PostgreSQL vs CockroachDB: alta disponibilidad sin drama — o con nuevos tipos de dolor
Siguiente →
Límites de potencia y Boost: por qué tu GPU parece tener mente propia

Deja un comentario