La carrera por la velocidad de reloj: por qué «más GHz» dejó de funcionar

¿Te fue útil?

Si alguna vez has comprado CPUs “más rápidas” y has visto que la latencia de producción apenas se mueve, ya conoces el final de la era de los GHz.
Los paneles parecen satisfechos: CPU por debajo del 40%, load average aceptable, y sin embargo las peticiones se acumulan como el equipaje en un aeropuerto tras una nevada.

Esta es la trampa moderna del rendimiento: la frecuencia dejó de ser la perilla fácil y el sistema se volvió complicado de formas que castigan las
suposiciones equivocadas. La buena noticia es que las reglas son aprendibles. La mala noticia es que no puedes ignorarlas esperando que el turbo boost
salve tus objetivos trimestrales.

Por qué «más GHz» dejó de funcionar

La carrera por la velocidad de reloj terminó por la misma razón que la mayoría de las carreras armamentísticas: se volvió demasiado cara y demasiado calurosa.
La escala de frecuencia fue la edad dorada en la que podías recompilar nada, no cambiar arquitectura, y aun así obtener una mejora cada generación.
Esa era se apoyaba en un pacto silencioso: los transistores más pequeños harían los chips más rápidos y más eficientes en energía.
El pacto se rompió.

El muro de la potencia: la física tiene opinión

La potencia dinámica en CMOS se aproxima comúnmente como P ≈ C × V² × f.
Puedes despreciar las constantes, pero no puedes despreciar el cuadrado del voltaje.
Las frecuencias más altas tienden a necesitar mayor voltaje para mantener márgenes de tiempo, y entonces la potencia se dispara.
La potencia se convierte en calor, el calor en throttling, y el throttling convierte tu reluciente “4.0 GHz” en un práctico “3.1 GHz, salvo que el ventilador gane la batalla.”

Ese es el muro de la potencia: no puedes seguir subiendo frecuencia sin romper el presupuesto térmico.
Y en servidores, el presupuesto térmico no es negociable. Un rack es un calefactor de sala del que también dependes para generar ingresos.

El fin del escalado de Dennard

Durante mucho tiempo, el escalado de Dennard hizo que los transistores fueran más pequeños, más rápidos y con menor potencia por área.
Hacia mediados de los 2000, la corriente de fuga y otros efectos arruinaron el sueño.
Los transistores siguieron encogiéndose, pero dejaron de volverse proporcionalmente “más baratos” en vatios.
La industria no dejó de innovar. Simplemente dejó de darte mejoras gratuitas de velocidad para el código existente.

El muro de la memoria: los CPUs corren, la RAM pasea

Incluso si pudieras subir la frecuencia, gran parte del rendimiento en servidores está limitado por la espera.
Espera por memoria. Espera por fallos de caché. Espera por E/S. Espera por bloqueos.
Los núcleos CPU se volvieron lo suficientemente rápidos como para completar instrucciones a un ritmo heroico—hasta que necesitan datos que no están en caché.

La latencia de memoria mejoró, pero no al mismo ritmo que el tiempo de ciclo de la CPU. Así que la latencia medida en ciclos de CPU empeoró.
Un acceso DRAM que antes era “un poco lento” se volvió “una eternidad” en ciclos de núcleo.
Las CPUs modernas combaten esto con cachés más grandes, mejores prefetchers, más ejecución fuera de orden y trucos especulativos.
Eso funciona—a veces. También complican el rendimiento de maneras que hacen que comprar GHz de forma ingenua sea como comprar un coche deportivo para tráfico urbano.

Concurrencia y corrección: la otra pared

Cuando la frecuencia dejó de escalar, el movimiento obvio fue “añadir núcleos.”
Pero “añadir núcleos” solo es gratis si tu carga paraleliza, tu código es seguro para hilos y tus dependencias no serializan todo.
Muchos sistemas reales están limitados por algunos bloqueos muy contendidos, un bucle de eventos monohilo en alguna parte, o una base de datos que acepta tus consultas paralelas y luego las serializa en una página de índice caliente.

Aquí está la traducción operacional: una actualización de CPU no falla porque la CPU sea débil. Falla porque el cuello de botella se movió—o nunca fue la CPU.
Si no mides, optimizarás lo equivocado con confianza.

Una cita que vale pegar en una nota:
Idea parafraseada (Edsger Dijkstra): Si no puedes medirlo, no puedes mejorarlo de forma significativa.

Broma #1: Perseguir GHz en 2026 es como añadir más caballos a un coche atrapado detrás de un tractor—técnicamente impresionante, emocionalmente inútil.

Hechos interesantes y contexto histórico (la versión corta y concreta)

  • Principios de los 2000: Las CPUs de consumo y servidor subieron agresivamente en frecuencia; el marketing giraba en torno a los GHz porque era fácil de entender.
  • Mediados de los 2000: El escalado de Dennard flaqueó; la potencia por fuga aumentó y la frecuencia se volvió térmicamente cara en lugar de “solo ingeniería.”
  • Lección de la era NetBurst: Algunos diseños persiguieron altos relojes con pipelines profundos; parecían geniales en la hoja de especificaciones y menos en trabajo real por ciclo.
  • Multi-core se vuelve dominante: La industria pivoteó de la velocidad de un solo núcleo a diseños multinúcleo como forma pragmática de gastar el presupuesto de transistores.
  • Era Turbo boost: Los chips comenzaron a incrementar la frecuencia oportunista dentro del margen térmico/potencia; el “base clock” pasó a ser un mínimo legal, no una promesa de experiencia práctica.
  • Adopción de Hyper-threading/SMT: El multihilo simultáneo aumentó el rendimiento cuando las unidades de ejecución estaban infrautilizadas, pero no duplicó el rendimiento y a veces empeoró la latencia de cola.
  • La caché se volvió rey: Cachés de último nivel grandes y prefetching más inteligente se volvieron características competitivas clave mientras la latencia de memoria seguía obstinada.
  • NUMA en todas partes: Diseños multi-socket y con chiplets hicieron de la localidad de memoria un tema de rendimiento que puedes activar por accidente con un scheduler o allocator incorrecto.
  • Boom de especialización: Unidades vectoriales, extensiones cripto, instrucciones de compresión y aceleradores (GPUs/NPUs) crecieron porque los núcleos de propósito general alcanzaron rendimientos decrecientes.

Qué sustituyó a los GHz: IPC, cachés, núcleos y especialización

IPC: instrucciones por ciclo es el nuevo juego de estatus

GHz es la velocidad del metrónomo. IPC es cuánta música tocas por latido.
El rendimiento moderno de la CPU es aproximadamente rendimiento ≈ frecuencia × IPC, luego recortado por stalls: fallos de caché, mispredicciones de rama,
burbujas de pipeline y espera por recursos compartidos.

Dos CPUs a la misma frecuencia pueden diferir significativamente en IPC según la microarquitectura, diseño de caché, predicción de ramas
y la mezcla de instrucciones de la carga. Por eso “mismos GHz” no es “misma velocidad”, y por qué “más GHz” a menudo sigue sin ser “más rápido.”

Cachés: el rendimiento que no ves, hasta que lo pierdes

Los hits de caché son la diferencia entre un núcleo que se mantiene ocupado y uno que sueña despierto.
Muchos incidentes de rendimiento en producción se reducen a un aumento en el tamaño del working set: nueva función, nuevo índice, nuevo blob JSON, nueva capa de cifrado,
y de repente los datos calientes ya no caben en caché. Tu uso de CPU puede permanecer moderado mientras el rendimiento colapsa, porque la CPU está esperando en su mayoría.

Núcleos: rendimiento por throughput, no latencia (a menos que tengas suerte)

Añadir núcleos ayuda cuando tu carga tiene trabajo paralelo y no se serializa en un punto compartido.
Es una jugada de throughput: más transacciones por segundo, más peticiones concurrentes, más jobs en background.
Si tu problema es la latencia de una sola petición dominada por un hilo, más núcleos es un placebo.

En términos operativos: escalar con núcleos es correcto para procesamiento por lotes, servicios shardados y endpoints sin estado que escalan horizontalmente.
Es incorrecto cuando un monolito tiene un bloqueo global, cuando un recolector de basura detiene el mundo, o cuando la base de datos es el cuello de botella.

Vectorización y aceleradores: las especializaciones dan aceleraciones reales

Cuando los núcleos de propósito general no pueden hacerse mucho más rápidos sin derretirse, los proveedores invierten en hacer cosas específicas más rápido:
instrucciones SIMD/vectoriales para trabajo data-paralelo, instrucciones criptográficas, compresión y aceleradores separados.
Si tu carga encaja, obtienes grandes ganancias.
Si no encaja, obtienes un chip “rápido” en folletos y “aceptable” en tus métricas.

El scheduler y el gestor de potencia: tu CPU se negocia, no es absoluta

En 2026, la frecuencia de la CPU es un resultado de política. Turbo bins, límites de potencia, margen térmico, c-states, p-states y el scheduler del kernel
deciden a qué clocks funcionas realmente. En un datacenter lleno, puedes tener servidores idénticos produciendo distinto rendimiento
porque su refrigeración o entrega de potencia difiere sutilmente.

Realidades de la carga: hacia dónde va realmente el rendimiento

La latencia suele ser una cadena de pequeñas esperas

Una petición no “usa CPU.” Flujo a través de colas, bloqueos, rutas de kernel, anillos de NIC, cachés de sistema de ficheros, almacenamiento, buffers de base de datos,
y código en espacio de usuario. Tu p99 normalmente no está dominado por el caso medio; está dominado por las pocas peores interacciones:
un page fault importante, una pausa de GC, un límite de cgroup por un vecino ruidoso, un acceso remoto NUMA, o un fallo de almacenamiento que arrastra un hilo a un sleep no interrumpible.

La utilización de CPU es mentirosa cuando la CPU está esperando

Error clásico: “CPU al 30%, así que tenemos margen.” No si ese 30% es un núcleo caliente al máximo y el resto está inactivo.
No si tienes mucho iowait.
No si tienes contención en la run queue.
No si estás bloqueado por memoria.

Almacenamiento y red: los coautores silenciosos del “rendimiento de CPU”

Como ingeniero de almacenamiento lo diré claro: no puedes “mejorar la CPU” para salir de fsyncs lentos, replicación síncrona,
o una carga de lecturas aleatorias en el medio equivocado. Las CPUs no arreglan la latencia de cola provocada por una cola NVMe saturada, y definitivamente
no arreglan un controlador RAID que se está reconstruyendo silenciosamente.

De forma similar, los problemas de red aparecen como “la CPU está bien, pero el throughput baja.” Porque tus hilos están bloqueados en sockets,
el kernel descarta paquetes, o los handshakes TLS están atascados por falta de entropía (sí, aún sucede).

Guía de diagnóstico rápido: encuentra el cuello de botella sin una semana de reuniones

Primero: ¿es tiempo de CPU, espera de CPU o no es CPU en absoluto?

  1. Revisa la run queue y la saturación de CPU: Si uno o más núcleos están pegados, estás limitado por CPU aunque el “CPU% global” parezca bajo.
  2. Revisa iowait y tareas bloqueadas: Si hilos están en sleep no interrumpible, estás esperando E/S (almacenamiento o sistema de ficheros en red).
  3. Revisa la presión de memoria: Fallos mayores y swapping pueden hacer que una “CPU rápida” se sienta lenta.

Segundo: Si estás limitado por CPU, ¿es throughput de instrucciones o stalls por memoria?

  1. Mira señales tipo IPC: ciclos altos con pocas instrucciones retiradas sugieren stalls; fallos de caché altos son el sospechoso usual.
  2. Revisa cambios de contexto y contención de locks: muchos switches pueden significar overhead del scheduler o exceso de threading.
  3. Mira los stacks principales: encuentra a dónde van los ciclos; no adivines.

Tercero: Si estás limitado por E/S, identifica qué cola se está llenando

  1. Latencia de dispositivo block: await/tiempo de servicio alto o colas profundas indican saturación de almacenamiento o problemas del dispositivo.
  2. Sistema de ficheros y writeback: páginas sucias y throttling pueden bloquear escritores; cargas fsync-intensas son culpables comunes.
  3. Red: retransmisiones, descartes o saturación de softirq de CPU pueden imitar “servidores lentos”.

Cuarto: Verifica turbo/throttling y la política de potencia (porque es la realidad)

Cuando el rendimiento “cambia aleatoriamente” entre hosts idénticos, sospecha límites térmicos o de potencia.
Las CPUs modernas son corteses: se protegerán a sí mismas y a tu presupuesto de datacenter reduciendo discretamente su rendimiento.

Tareas prácticas: comandos, qué significa la salida y qué decisión tomar

Estas son las tareas que realmente ejecuto cuando alguien dice “las CPUs nuevas son más lentas” o “necesitamos más GHz.”
Cada tarea incluye: comando, significado de la salida y un punto de decisión. Úsalas como una lista de verificación, no como un ritual.

Tarea 1: Verificar comportamiento real de la frecuencia de CPU (no los relojes de marketing)

cr0x@server:~$ lscpu | egrep 'Model name|CPU\(s\)|Thread|Core|Socket|MHz'
Model name:                           Intel(R) Xeon(R) CPU
CPU(s):                               32
Thread(s) per core:                   2
Core(s) per socket:                   8
Socket(s):                            2
CPU MHz:                              1298.742

Qué significa: “CPU MHz” es una instantánea. Si está baja mientras el equipo está ocupado, puede que estés ahorrando energía, throttled, o bajo una carga que duerme a menudo.

Decisión: Si el rendimiento es malo, confirma las frecuencias activas bajo carga (Tarea 2) y revisa el governor/límites de potencia (Tarea 3/4).

Tarea 2: Vigilar la frecuencia y utilización por núcleo mientras ocurre el problema

cr0x@server:~$ sudo turbostat --quiet --interval 1
     CPU     Avg_MHz   Busy%   Bzy_MHz  TSC_MHz   IRQ  SMI  CPU%c1  CPU%c6  CoreTmp
       -       3120    38.50     4050     2500  12000    0    2.10   40.20      78

Qué significa: Bzy_MHz es la frecuencia efectiva cuando está ocupado; CoreTmp insinúa margen térmico. Si Bzy_MHz está por debajo del turbo esperado mientras Busy% es alto y las temperaturas son elevadas, probablemente estés limitado térmicamente.

Decisión: Si ves Bzy_MHz bajo bajo carga, revisa límites de potencia y refrigeración. No “optimices código” hasta saber que la CPU no se está auto-limitando.

Tarea 3: Revisar el governor de CPU (común en imágenes cloud y portátiles reutilizados como servidores)

cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
powersave

Qué significa: powersave puede estar bien en sistemas intel_pstate modernos, pero en algunas configuraciones limitará la capacidad de respuesta.

Decisión: Si la latencia es sensible, establece una política apropiada (a menudo performance o un perfil ajustado) y vuelve a probar. No sigas a ciegas; mide antes/después.

Tarea 4: Revisar indicadores térmicos y de throttling

cr0x@server:~$ sudo dmesg -T | egrep -i 'thrott|thermal|powercap' | tail -n 5
[Mon Jan  8 10:22:11 2026] CPU0: Package temperature above threshold, cpu clock throttled
[Mon Jan  8 10:22:12 2026] CPU0: Core temperature/speed normal

Qué significa: Mensajes del kernel como este son tu arma humeante: tus “GHz” fueron negociados a la baja.

Decisión: Arregla la refrigeración, el flujo de aire, el montaje del disipador, las curvas de ventilador, los límites de potencia en BIOS, o la densidad del rack. No culpes al compilador.

Tarea 5: Determinar si estás saturado de CPU o simplemente “algo ocupado”

cr0x@server:~$ uptime
 10:28:44 up 41 days,  3:02,  2 users,  load average: 28.14, 27.90, 26.30

Qué significa: El load average cercano o por encima del número de hilos CPU puede indicar saturación, pero también cuenta tareas en sleep no interrumpible (I/O wait).

Decisión: Combina esto con vmstat (Tarea 6) para distinguir presión runnable de I/O bloqueado.

Tarea 6: Vista rápida de la cola runnable, cambios de contexto e iowait

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
12  0      0 812344  55284 932120    0    0    12    38 8200 9100 55 10 33  2  0
14  0      0 801120  55284 932992    0    0    10    22 8300 9500 58  9 31  2  0
 2  6      0 794224  55284 931880    0    0   120  9800 4100 7000 12  6 40 42  0

Qué significa: r son hilos runnable; b está bloqueado. Alto wa y alto b indican stalls por I/O. Alto r con bajo id indica saturación de CPU.

Decisión: Si está bloqueado/centrado en I/O, ve a tareas de almacenamiento/red. Si está centrado en CPU, perfila (Tarea 11/12).

Tarea 7: Identificar si un solo núcleo está pegado (la mentira del “CPU 30%”)

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

01:02:01 PM  CPU   %usr %nice  %sys %iowait  %irq %soft  %steal  %idle
01:02:02 PM  all   18.2  0.0   3.1    0.4    0.0  1.0     0.0   77.3
01:02:02 PM   7   98.5  0.0   1.2    0.0    0.0  0.0     0.0    0.3

Qué significa: CPU 7 está pegada. En general parece bien; a tu latencia no le importa el “todo”.

Decisión: Identifica el hilo/proceso caliente. Considera shardear, eliminar cuellos monohilo, o hacer pinning de forma consciente (no aleatoria).

Tarea 8: Revisar presión de memoria y fallos mayores (la combinación “CPU rápida, fallos de página lentos”)

cr0x@server:~$ sar -B 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

01:04:11 PM  pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s
01:04:12 PM     12.00     84.00   6200.00      0.00  10200.0     0.00     0.00
01:04:13 PM     18.00   1200.00   7100.00    180.00   9800.0   220.00    60.00

Qué significa: Picos en majflt/s indican fallos de página respaldados por disco. Eso destruye la latencia de cola.

Decisión: Añade memoria, reduce el working set, ajusta cachés, o arregla un despliegue que infló el uso de memoria. No compres GHz más altos para “arreglar” el paging.

Tarea 9: Inspeccionar localidad NUMA (la memoria remota es “CPU lenta” disfrazada)

cr0x@server:~$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 128000 MB
node 0 free:  42000 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 128000 MB
node 1 free:  18000 MB

Qué significa: Dos nodos NUMA. Un desequilibrio en memoria libre puede insinuar asignación desigual o pinning.

Decisión: Si un proceso está fijado a CPUs del nodo 1 pero asigna memoria mayoritariamente en nodo 0, espera peor latencia. Usa numastat (tarea siguiente).

Tarea 10: Confirmar si tu proceso paga el “impuesto de memoria remota”

cr0x@server:~$ pidof myservice
24188
cr0x@server:~$ numastat -p 24188 | head -n 8
Per-node process memory usage (in MBs) for PID 24188 (myservice)
         Node 0      Node 1
Huge         0.00       0.00
Heap     18240.12    1024.55
Stack        8.00       2.00
Private  20110.33    1210.77

Qué significa: Mucha asignación en el nodo 0. Si el scheduler ejecuta hilos en CPUs del nodo 1, estás haciendo lecturas remotas.

Decisión: Arregla la afinidad de CPU, usa interleaving intencional, o ejecuta una instancia por socket. Esto a menudo vale más que 200 MHz.

Tarea 11: Identificar los principales consumidores de CPU y si están en user vs kernel

cr0x@server:~$ top -b -n 1 | head -n 15
top - 13:08:21 up 41 days,  3:42,  2 users,  load average: 28.14, 27.90, 26.30
Tasks: 412 total,   6 running, 406 sleeping,   0 stopped,   0 zombie
%Cpu(s): 61.2 us,  9.7 sy,  0.0 ni, 27.9 id,  0.9 wa,  0.0 hi,  0.3 si,  0.0 st
MiB Mem : 257996.0 total,  92124.3 free,  32110.7 used, 133761.0 buff/cache
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
24188 app       20   0 18.2g   6.1g  120m R  395.0   2.4  123:41.33 myservice

Qué significa: El servicio está usando ~4 núcleos de CPU. El tiempo de sistema es no trivial; podría ser red, syscalls, sistema de ficheros o contención.

Decisión: Si sy es alto, inspecciona hotspots del kernel (softirqs, syscalls) y considera offloads o batching. Si us es alto, perfila el espacio usuario.

Tarea 12: Muestra dónde van los ciclos de CPU (perf top)

cr0x@server:~$ sudo perf top -p 24188
  18.40%  myservice  myservice           [.] parse_json_fast
  11.22%  myservice  myservice           [.] sha256_compress
   7.10%  libc.so.6  libc.so.6            [.] __memmove_avx_unaligned_erms
   4.85%  [kernel]   [kernel]             [k] tcp_recvmsg

Qué significa: Las funciones calientes están parseando JSON y haciendo hashing. Eso es trabajo de cómputo; “más GHz” puede ayudar un poco, pero las elecciones de algoritmo y formato de datos pueden ayudar mucho más.

Decisión: Considera reducir la sobrecarga de JSON (formato binario, menos campos), activar crypto acelerada por hardware, o mover hashing a una librería especializada. Mide el impacto en p99.

Tarea 13: Recoger pistas de contadores hardware (fallos de caché, ciclos, instrucciones)

cr0x@server:~$ sudo perf stat -p 24188 -e cycles,instructions,cache-references,cache-misses,branches,branch-misses -- sleep 10
 Performance counter stats for process id '24188':

      21,334,112,901      cycles
      15,002,118,777      instructions              #  0.70  insn per cycle
       2,112,440,918      cache-references
         388,004,112      cache-misses              # 18.37% of all cache refs
       3,122,114,662      branches
          61,110,221      branch-misses             #  1.96% of all branches

      10.003022332 seconds time elapsed

Qué significa: IPC ~0.70 sugiere stalls; la tasa de fallos de caché es alta. No estás “demasiado lento en GHz,” estás esperando memoria.

Decisión: Enfócate en la localidad de datos: reduce pointer-chasing, reduce objetos, mejora batching o reestructura bucles calientes. Considera cachés más grandes o menos hilos haciendo thrash de caché compartida.

Tarea 14: Identificar latencia de E/S y profundidad de cola en dispositivos block

cr0x@server:~$ iostat -x 1 3
Linux 6.5.0 (server) 	01/09/2026 	_x86_64_	(32 CPU)

Device            r/s     w/s   rKB/s   wKB/s  await  aqu-sz  svctm  %util
nvme0n1         120.0  2100.0   8400  98200   18.40   42.10   0.35  92.0

Qué significa: %util cercano al 100 y await/aqu-sz altos significan que la cola del dispositivo está profunda y las peticiones esperan. La CPU parecerá “bien” mientras la app se bloquea.

Decisión: Reduce escrituras síncronas, ajusta el encolamiento, separa cargas ruidosas, o escala el almacenamiento. Si ves esto, deja de debatir la frecuencia de la CPU.

Tarea 15: Confirmar la presión de writeback del sistema de ficheros (común con escrituras en ráfaga)

cr0x@server:~$ grep -E 'Dirty|Writeback' /proc/meminfo
Dirty:             1823456 kB
Writeback:          412800 kB

Qué significa: Dirty/Writeback alto indica muchas flushes pendientes. Si los escritores son throttled, ocurren picos de latencia.

Decisión: Revisa si tu app llama fsync con demasiada frecuencia, si necesitas opciones de montaje distintas, o si deberías mover logs a dispositivos separados.

Tarea 16: Detectar retransmisiones y descartes de red (porque “CPU lenta” a veces es dolor TCP)

cr0x@server:~$ netstat -s | egrep -i 'retransmit|segments retransm|listen|overflow|dropped' | head -n 10
    12345 segments retransmitted
    98 listen queue overflows
    98 listen queue drops

Qué significa: Retransmisiones y desbordes de la cola listen son veneno para la latencia. Tu CPU puede estar inactiva mientras las peticiones tiemporizan y reintentan.

Decisión: Ajusta backlog, arregla pérdida de paquetes, escala frontends, o descarga TLS. No compres relojes más altos para compensar pérdidas de red.

Broma #2: Si tu solución es “añadir 500 MHz,” estás a un paso de culpar al retrogrado de Mercurio por la pérdida de paquetes.

Tres microhistorias corporativas (anonimizadas, técnicamente plausibles y dolorosamente familiares)

Microhistoria 1: El incidente causado por una suposición equivocada (GHz como destino)

Una empresa SaaS de tamaño medio migró una API sensible a la latencia desde servidores antiguos a otros más nuevos. El deck de compras era impecable:
generación más nueva, turbo frequency publicitado más alto, más núcleos, “mejor en todo.” El equipo esperaba una caída en la latencia p95.
En su lugar, la p95 empeoró—a veces mucho—en horas punta.

La primera respuesta fue predecible: culpar al código. Se formó una “war room” de rendimiento y los ingenieros empezaron a proponer micro-optimizaciónes.
Mientras tanto, SRE notó algo extraño: la peor latencia se correlacionaba con un subconjunto de hosts, y esos hosts mostraban temperaturas de entrada ligeramente más altas.
No alarmante, solo “un poco más calientes.”

Ejecutaron turbostat durante pruebas de carga y encontraron que la frecuencia efectiva en carga era consistentemente menor en los hosts calientes.
Las CPUs se mantenían dentro de límites seguros bajando reloj. El número turbo de la hoja de especificaciones solo era alcanzable con suficiente margen térmico,
y la disposición del rack había cambiado—equipos más densos, flujo de aire distinto, mismas suposiciones de refrigeración.

La suposición equivocada no fue “GHz importa.” La suposición equivocada fue “GHz es una constante.” En sistemas modernos es una variable.
Arreglaron el problema físico: mejoraron el flujo de aire, reequilibraron la colocación en racks y ajustaron los power caps en BIOS con cuidado.
Solo entonces las CPUs “más rápidas” se volvieron realmente más rápidas, y solo entonces el perfilado de código fue significativo.

La lección operativa duradera fue: cuando el rendimiento empeora tras una actualización de hardware, trata el entorno como un sospechoso de primera clase.
La frecuencia es política + física, no un número que posees.

Microhistoria 2: La optimización que salió mal (más hilos, menos throughput)

Un equipo de pipeline de datos tenía un servicio de enriquecimiento intensivo en CPU. Veían utilización de CPU al 60% y asumieron que había throughput sin aprovechar.
Alguien aumentó el pool de hilos de 16 a 64. El cambio se desplegó rápido porque “solo tocaba configuración.”
En pruebas sintéticas el throughput mejoró. En producción, sin embargo, apareció un feo pico en p99 y el throughput global cayó en ventanas de alta carga.

Los síntomas eran confusos: la utilización de CPU subió, pero también los context switches. La tasa de fallos de caché aumentó. El servicio empezó a timeoutear llamadas a una dependencia downstream,
provocando reintentos. Los reintentos aumentaron la carga, lo que aumentó los timeouts, lo que aumentó los reintentos. Un bucle de retroalimentación clásico, ahora patrocinado por pools de hilos.

El perfilado mostró que las rutas calientes eran intensivas en memoria: parsing, asignaciones de objetos, tablas hash y una caché LRU compartida.
Con 64 hilos, el working set por núcleo no encajaba bien en caché, y la contención en los locks de la caché compartida aumentó.
La CPU no estaba “infrautilizada” al 60%; ya estaba esperando memoria y compitiendo por estructuras compartidas.

La solución no fue “menos hilos” como principio moral; fue “concurrencia dimensionada correctamente.” Se decidieron por un pool más pequeño,
partiaron cachés por trabajador para reducir contención y ajustaron el comportamiento del allocator. El throughput mejoró y la p99 se estabilizó.

La conclusión: más núcleos y más hilos no son una estrategia de rendimiento. Son un multiplicador de lo que sea que tu cuello de botella ya sea.
Multiplica la contención y el thrash de caché lo suficiente y obtendrás un incidente de rendimiento con excelente utilización de CPU.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día (perfilado base y canarios)

Un equipo de plataforma empresarial ejecutaba una carga mixta en una flota: tráfico web, jobs de background y algunos procesos batch “temporalmente permanentes”.
Tenían una regla que irritaba a los desarrolladores: todo cambio significativo de hardware o kernel requería una pool canaria y una captura de rendimiento base.
No un circo de benchmarks de una semana—solo lo suficiente para comparar contadores clave e histogramas de latencia.

Un nuevo despliegue de kernel fue a la pool canaria. En horas, las canarias mostraron un leve aumento en tiempo de sistema y un pequeño incremento en la latencia de cola.
Nada dramático. Exactamente el tipo de cosa que perderías si solo miraras el CPU promedio.
Pero la línea base del equipo incluía contadores perf stat para fallos de caché y cambios de contexto, además de iostat y retransmisiones de red.

Los datos sugirieron un cambio en el comportamiento del scheduler y más trabajo de softirq bajo carga.
Pausaron el despliegue, reprodujeron el problema en staging y lo atribuyeron a una combinación de afinidad de interrupciones de NIC y un nuevo valor por defecto en la gestión de potencia.
La solución fue mundana: ajustar IRQ affinity y aplicar un perfil afinado para la clase de carga.

Porque usaron canarias y líneas base, el “incidente” nunca llegó a los clientes.
Sin rollback de emergencia, sin actualizaciones ejecutivas, sin pizzas a medianoche.
La práctica era aburrida. También era correcta. Esto es lo que parece la fiabilidad cuando la haces a propósito.

Errores comunes (síntomas → causa raíz → solución)

1) Síntoma: La CPU global está baja, pero la latencia p99 es alta

Causa raíz: Un núcleo está pegado, cuello monohilo, o sección serializada (bloqueo global, event loop, pausa de GC).

Solución: Usa mpstat -P ALL para encontrar núcleos calientes, luego perfila ese proceso/hilo. Reduce serialización, shardea trabajo, o mueve trabajo pesado fuera del camino de la petición.

2) Síntoma: “Los servidores nuevos son más lentos” en un subconjunto de hosts

Causa raíz: Throttling térmico, capado de potencia, ajustes BIOS distintos o refrigeración desigual.

Solución: Verifica MHz efectivo en carga con turbostat, revisa dmesg por eventos térmicos, normaliza perfiles BIOS y arregla flujo de aire/densidad del rack.

3) Síntoma: CPU moderada, pero el throughput colapsa durante ráfagas de escritura

Causa raíz: Saturación de colas de almacenamiento, tormentas de fsync, throttling de writeback o contención por reconstrucción RAID.

Solución: Usa iostat -x, revisa Dirty/Writeback, separa dispositivos de logs, agrupa fsyncs o provisiona headroom de IOPS/latencia.

4) Síntoma: Más hilos lo empeoraron

Causa raíz: Contención, overhead de cambios de contexto, thrash de caché o amplificación downstream por reintentos/timeouts.

Solución: Mide cambios de contexto (vmstat), perfila locks, limita concurrencia, particiona estructuras compartidas e implementa backpressure.

5) Síntoma: La CPU sube aleatoriamente en tiempo de sistema

Causa raíz: Saturación de softirq de red, altas tasas de syscall, drops de paquetes que desencadenan retransmisiones, o overhead de la pila de almacenamiento.

Solución: Revisa top sys%, retransmisiones con netstat -s, afinidad de IRQ y considera batching, offloads o reducir syscalls por petición.

6) Síntoma: La latencia empeora tras mover a máquinas multi-socket

Causa raíz: Accesos remotos NUMA por colocación del scheduler, desequilibrio en asignación de memoria o pinning en contenedores.

Solución: Usa numastat -p, alinea CPU y localidad de memoria (una instancia por socket) y evita chatter accidental entre nodos.

7) Síntoma: “Actualizas la CPU” y no ves mejora

Causa raíz: El cuello de botella está en otro sitio: latencia de almacenamiento, red, bloqueos en base de datos, stalls de memoria o serialización.

Solución: Ejecuta la guía de diagnóstico rápido. Demuestra que la CPU es el recurso limitante antes de gastar dinero o reescribir código.

Listas de verificación / plan paso a paso

Lista A: Antes de comprar CPUs (o celebrar “más GHz”)

  1. Define el objetivo: throughput, latencia p95, latencia p99 o coste por petición. Elige una métrica primaria.
  2. Captura una línea base: uso por núcleo, frecuencia efectiva bajo carga, muestra de tasa de fallos de caché, latencia iostat, retransmisiones de red.
  3. Clasifica la carga: intensiva en cómputo, intensiva en memoria, con mucha contención, intensiva en E/S o mixta.
  4. Encuentra la forma de escalado: ¿duplicar instancias duplica throughput? Si sí, scale-out puede superar a scale-up.
  5. Identifica riesgos de cola: pausas de GC, fsync, bloqueos en BD, vecinos ruidosos, throttling. Estos dominan la p99.
  6. Elige hardware según evidencia: más caché para cargas intensas en memoria, potencia sostenida mayor para cómputo, mejor almacenamiento para cargas intensas en E/S.

Lista B: Cuando la latencia empeora tras un refresh de hardware

  1. Confirma throttling: turbostat + mensajes térmicos en dmesg.
  2. Normaliza BIOS y política de potencia: asegúrate de ajustes consistentes en la flota.
  3. Revisa NUMA: localidad y pinning para procesos grandes.
  4. Verifica paridad de kernel y microcode: los desajustes causan deltas confusos.
  5. Compara contadores perf: proxies de IPC y tasas de fallos de caché; no confíes en CPU%.
  6. Solo entonces perfila código: quieres arreglar software en hardware con comportamiento estable.

Lista C: Depuración de rendimiento en producción (relativamente segura)

  1. Empieza por los síntomas: p95/p99, tasas de error, reintentos, longitudes de colas.
  2. Revisa saturación: CPU por núcleo, run queue, tareas bloqueadas.
  3. Revisa memoria: fallos mayores, swapping, kills por OOM, comportamiento del allocator si es visible.
  4. Revisa almacenamiento: await/cola con iostat; dirty/writeback si hay muchas escrituras.
  5. Revisa red: retransmisiones/descartes, desbordes de listen, uso de softirq en CPU.
  6. Perfila brevemente: perf top o perf stat por 10–30 segundos, no una hora.
  7. Haz un cambio: revierte “optimización” arriesgada, limita concurrencia, ajusta política y luego mide de nuevo.

Preguntas frecuentes

1) Si los GHz no importan, ¿por qué las CPUs siguen publicitándolos?

Porque a veces importan y porque es fácil venderlos. La frecuencia aún influye en el rendimiento, pero no es la palanca dominante
en cargas modernas. El rendimiento sostenido depende de límites de potencia, refrigeración, IPC, comportamiento de caché y localidad de memoria.

2) ¿En qué debo fijarme en lugar de GHz al elegir servidores?

Empareja hardware con la carga: tamaño de caché y ancho de banda de memoria para servicios intensos en datos, potencia sostenida y capacidades vectoriales para cómputo,
y latencia/IOPS de almacenamiento para sistemas intensos en escritura. También: topología NUMA, conteo de núcleos versus licencias y frecuencia sostenida real bajo tu carga.

3) ¿Por qué es engañoso el “CPU% global”?

Porque promedia entre núcleos y oculta pinning. Un núcleo pegado puede dominar la latencia mientras otros están inactivos.
Siempre revisa estadísticas por núcleo y la run queue. También revisa iowait y tareas bloqueadas para distinguir espera de trabajo.

4) ¿El turbo boost ayuda en cargas de producción?

Puede ayudar, especialmente en cargas en ráfaga y picos monohilo. Pero el turbo es oportunista: depende del margen térmico/potencia.
Bajo carga sostenida, muchos sistemas se asientan cerca del base o en una frecuencia intermedia. Mide Bzy_MHz bajo carga real.

5) ¿Más núcleos siempre son mejores que relojes más altos?

No. Más núcleos ayudan al throughput si la carga escala y no hay contención. Relojes más altos ayudan al trabajo monohilo o ligeramente paralelo.
La respuesta real es: identifica el cuello de botella primero. Si estás limitado por latencia de memoria, ninguno ayudará tanto como arreglar la localidad.

6) ¿Por qué algunas optimizaciones aumentan los fallos de caché?

Causas comunes: hacer objetos más grandes, añadir campos, aumentar la cardinalidad, cambiar a estructuras con muchos punteros, o aumentar la concurrencia
de modo que los hilos se eyecten mutuamente de sus working sets. Los fallos de caché suelen ser un “impuesto por la estructura de datos”, no un “problema del compilador”.

7) ¿Cómo puede el almacenamiento hacer que la CPU parezca lenta?

Cuando los hilos bloquean en disco (o almacenamiento en red), la CPU está inactiva o esperando y la latencia de las peticiones aumenta.
La gente ve respuestas lentas y asume cómputo como culpable. iostat -x y tareas bloqueadas en vmstat suelen exponer esto rápidamente.

8) ¿Cuál es la forma más rápida de demostrar que estás limitado por CPU?

Busca una cola runnable alta (vmstat r), poco idle, pinning por núcleo y iowait estable y bajo.
Luego toma una muestra corta con perf top para confirmar que los ciclos están en código de usuario y no esperando locks o E/S.

9) ¿Qué es “dark silicon” y por qué debería importarme?

Es la realidad de que no todos los transistores pueden estar activos a velocidad máxima simultáneamente dentro de las limitaciones de potencia/térmicas.
En la práctica: tu CPU tiene capacidades pico que no pueden usarse todas a la vez. Por eso importan el rendimiento sostenido y el encaje de la carga.

10) ¿Puedo “arreglar” esto con límites de contenedores o pinning de CPU?

A veces. El pinning puede mejorar la localidad de caché y reducir jitter del scheduler, pero también puede crear puntos calientes y dolor NUMA.
Los límites pueden prevenir vecinos ruidosos pero inducir throttling si se fijan demasiado bajos. Trátalos como herramientas quirúrgicas: mide antes y después.

Conclusión: pasos prácticos siguientes (qué hacer el lunes por la mañana)

Deja de comprar GHz como si fuera 2003. Compra rendimiento de la misma forma que compras fiabilidad: emparejando el sistema con la carga y verificando el comportamiento bajo carga.
La frecuencia sigue siendo parte de la historia, pero no es la trama principal.

  1. Ejecuta la guía de diagnóstico rápido en tu servicio con peor latencia y clasifica el cuello de botella: CPU, stalls de memoria, almacenamiento o red.
  2. Captura una línea base con un pequeño conjunto de comandos repetibles: uso por núcleo, MHz efectivo, muestra de tasa de fallos de caché, latencia iostat, retransmisiones.
  3. Arregla lo aburrido primero: throttling, localidad NUMA, reintentos desbocados y saturación de colas de E/S. Esto entrega ganancias dramáticas y menos sorpresas.
  4. Solo entonces optimiza código, guiado por perfiles. Si tu ruta caliente es parsing JSON y hashing, “más GHz” es un impuesto; mejores formatos y algoritmos son una inversión.
  5. Haz cambios de rendimiento como los SRE hacen cambios de fiabilidad: canarias, planes de rollback y criterios de aceptación medibles.

La carrera por la velocidad de reloj no terminó porque los ingenieros se vuelvan perezosos. Terminó porque la física envió una factura.
Págala con medición, localidad y diseño de sistemas sensato—no con pensamiento mágico y una hoja de cálculo de compras.

← Anterior
Debian 13: permisos del socket PHP-FPM — la pequeña solución que elimina los 502 (caso nº35)
Siguiente →
VPN Full-Mesh para Tres Oficinas: Cuándo Necesitarlo y Cómo Mantenerlo Gestionable

Deja un comentario