19 puntos por GN⁺ 2025-09-04 | 3 comentarios | Compartir por WhatsApp
  • Normalmente se juzga el límite de rendimiento de un servidor con el % de uso de CPU de herramientas de monitoreo como top, pero en realidad esta métrica no refleja el rendimiento de forma lineal
  • En pruebas con stress-ng en un entorno con Ryzen 9 5900X, cuando el uso marcaba 50% la carga de trabajo real llegaba a 60~100%, mostrando una gran brecha con la métrica
  • Las principales causas son el hyper-threading y el turbo boost, ya que el uso compartido de recursos entre núcleos lógicos y los cambios en la velocidad de reloj distorsionan la métrica
  • Por eso, en lugar de usar solo el uso de CPU, es más preciso comparar un benchmark de la carga de trabajo realmente procesable con el throughput actual
  • Si se interpreta el uso de CPU de manera lineal, se pueden producir grandes errores al estimar el rendimiento, por lo que al planificar sistemas se necesita un enfoque basado en benchmarks

Desajuste entre la cifra de uso de CPU del servidor y el throughput real

  • Al operar un servidor, mucha gente quiere saber si está cerca de su uso máximo
  • Por lo general, se toma como referencia el valor más alto entre uso de red, memoria y CPU mediante herramientas de monitoreo como top
  • Pero en la práctica surge el problema de que la cifra de uso de CPU y la cantidad de trabajo que puede procesarse no aumentan de forma lineal

Entorno y método de prueba

  • Experimento basado en Ubuntu Desktop + Ryzen 9 5900X (12 núcleos/24 hilos)
  • Precision Boost Overdrive (Turbo) activado
  • Simulación de distintas cargas con stress-ng (1~24 workers, 1~100% de uso)
  • Métricas medidas: uso de CPU reportado por el sistema y volumen real de cómputo (Bogo ops)

Resumen de resultados

  • Carga general de CPU: con 50% de uso, throughput real de 60~65%
  • Operaciones enteras de 64 bits: con 50% de uso, throughput real de 65~85%
  • Operaciones matriciales (Matrix math): con 50% de uso, throughput real de 80~100%
    • En la práctica, aunque los workers adicionales no contribuyan al rendimiento, el uso de CPU sí aumenta

Análisis de causas

  • Hyper-threading

    • Estructura de 12 núcleos físicos + 12 núcleos lógicos
    • Hasta 12 workers se asignan de forma óptima a los núcleos físicos, pero al superar ese número el uso compartido de núcleos lógicos degrada el rendimiento
    • En especial, en operaciones SIMD (operaciones matriciales) no hay recursos compartidos disponibles, así que no puede mejorar el rendimiento
  • Turbo boost

    • Con poca carga: 4.9GHz → con carga total: 4.3GHz, una caída de reloj del 15%
    • Esto distorsiona la fórmula de cálculo del uso de CPU (= busy cycles / total cycles)
      • Al reducirse el denominador (ciclos totales), el aumento del uso se sobreestima frente a la carga de trabajo real

Implicaciones

  • El uso de CPU no es una métrica absoluta de rendimiento
  • Al dimensionar capacidad de servidores y predecir rendimiento:
    • 1. Medir el throughput máximo con benchmarks
    • 2. Monitorear el throughput en tiempo real
    • 3. Comparar ambos valores para determinar si se está cerca del límite de rendimiento
  • Como la variación es grande según la arquitectura de CPU (AMD vs Intel), la eficiencia del hyper-threading y la forma en que actúa el turbo, se necesita un análisis por procesador

Conclusión

  • El uso de CPU es simplemente la proporción de ciclos ocupados, y no refleja con precisión el rendimiento real de procesamiento
  • Incluso con un “50% de uso”, si se aprovecha eficientemente, el sistema ya podría estar en 80~100% de su rendimiento máximo
  • Por lo tanto, el monitoreo de rendimiento y la planificación del sistema deben centrarse en el throughput de trabajo basado en benchmarks en lugar del uso de CPU

3 comentarios

 
ifmkl 2025-09-07

En entornos reales de configuración de HPC, por lo general se desactiva el hyper-threading y se configura el clúster de esa manera.

 
GN⁺ 2025-09-04
Comentarios en Hacker News
  • No creo que la utilización de CPU sea una mentira en el sentido de que mide una magnitud claramente definida, pero cuando la gente intenta extrapolarla para construir modelos de capacidad, se encuentra con que la realidad y lo esperado no coinciden.
    Hyperthreading (SMT) y Turbo (escalado de reloj) son solo algunas de las muchas variables que introducen no linealidad, y también hay recursos compartidos entre núcleos, como el ancho de banda de memoria, la capacidad de interconexión y la caché del procesador, que se van “agotando” a medida que aumenta la carga.
    Incluso a nivel de software, por ejemplo fenómenos como los spinlocks pueden tener un impacto no lineal sobre la utilización.
    La mayoría de las métricas de utilización de CPU hacen promedios largos, de varios segundos hasta 1 minuto, pero las cosas importantes para el rendimiento de servidores sensibles a la latencia ocurren en decenas o cientos de milisegundos.
    Por eso, una utilización promediada en varios segundos no puede distinguir entre patrones en ráfaga y patrones suaves.
    Pero el enfoque propuesto, es decir, “hacer benchmark de cuánto trabajo puede hacer un servidor antes de que aparezcan errores o latencias inaceptables”, también es inherentemente inestable.
    Cuando intentas encontrar el punto en el que un servidor empieza a volverse inestable, las mediciones se vuelven muy ruidosas, y desde la teoría de colas, cerca del punto crítico todo el ruido se amplifica.
    Además, el propio concepto de “cuánto trabajo está haciendo ahora el servidor” suele estar definido de forma inestable (¿RPS?; cada request tiene un costo distinto, y el IPC también cambia según el momento).
    Al final, los intervalos de confianza que salen de un enfoque de pruebas de carga no son muy distintos de construir un modelo empírico a partir de métricas de utilización. La premisa es medir correctamente la utilización.

    • Si sabes usar perf o ftrace, puedes obtener métricas del procesador muy detalladas en periodos cortos y ver directamente causas como stalls de CPU por cache miss o accesos a memoria, efectos del scheduler, etc.
      Pero la mayoría de la gente, incluso si recibe métricas como IPC o tasa de aciertos de caché, no sabe qué hacer con ellas.
      Al final, lo que de verdad le importa a la mayoría es la latencia y la utilización.
      Hablando a grandes rasgos, en la mayoría de las cargas de trabajo no hay grandes problemas de latencia hasta que la utilización de CPU supera el 80%.
      Pero por encima de esa utilización, empieza a afectar seriamente la latencia de la carga de trabajo.
      Cuánto afecta a la latencia solo se sabe midiéndolo directamente en tu propia carga de trabajo.
      Qué tan sensible eres a la latencia también depende de la organización y del objetivo, y a veces optimizar el throughput puede ser más importante.
      Si te importan tanto la latencia como el throughput, entonces mide ambos y decide tú mismo el trade-off adecuado.

    • Creo que uno de los puntos clave es precisamente que la definición de “cantidad de trabajo” es inestable.
      Por ejemplo, no es lo mismo un servicio expuesto al público que atiende requests de usuarios reales, que una carga de trabajo de entrenamiento de IA que procesa con calma datos acumulados en backend.
      Mi enfoque es que, en el entorno moderno de CPUs multinúcleo con hyperthreading donde las ráfagas son inevitables, si la utilización de CPU está en 60% ya considero que es un servidor “muy cargado”.
      Si está por encima de 60% durante una parte importante del día, considero apropiado dividir la carga (hablando principalmente de servicios que responden a requests de usuarios).
      Antes, este tipo de criterio solía llevar a pensar mucho en autoscaling en la nube.
      Hoy en día incluso puedes usar servidores de más de 100 núcleos por alrededor de 30 mil dólares, así que la situación se ha vuelto más compleja.
      Hoy, yo me inclinaría por un enfoque híbrido: sobreaprovisionar un poco el hardware de servidores reales y escalar según sea necesario con servicios en la nube (o una nube interna basada en Kubernetes).
      StackOverflow, en sus primeros tiempos, operaba un tráfico enorme de forma eficiente con racks dedicados y uplinks de 10Gbps, y hoy esto es aún más fácil de hacer.
      En resumen, para mí, si la carga de CPU se mantiene en 65% durante más de 30 minutos, ya lo considero equivalente a un uso 100% efectivo y concluyo que hace falta escalar pronto.

    • En una keynote reciente de IEEE Hot Interconnects también se mencionó un caso de ajuste de latencia en Ultra Ethernet.
      A escalas de 2 o 5 segundos puede parecer plano, pero si miras en escala de 100ms se ve claramente el fenómeno de frame bursts.
      Es decir, si la ventana de medición del profiling no coincide con la carga de trabajo real, puedes terminar con un false negative y sacar conclusiones equivocadas, empeorando el problema.

    • Estoy totalmente de acuerdo con lo que se mencionó.
      Debido a que la utilización de CPU no es lineal, el propio porcentaje se aleja de la realidad.
      O sea, la afirmación es que lo que es mentira es la utilización de CPU medida solo como %.

    • Si dos cargas de trabajo marcan ambas 100% de uso de CPU, pero una consume mucha más energía y eleva muchísimo más la temperatura del CPU, surge la duda de si en realidad esa carga no estará usando más recursos de transistores.

  • Aunque la utilización de CPU no sea una métrica perfecta, en la práctica me ha servido bastante.
    Incluso en experiencia sencilla de trabajo de SRE, para tareas CPU-bound combiné teoría de colas con métricas de utilización de CPU para dimensionar servidores antes de eventos grandes, y aun usando un %CPU recomendado de forma mucho más conservadora que enfoques más “tradicionales”, el resultado fue mucho más costo-eficiente.
    La clave es que, aunque una métrica sea algo imprecisa, si sirve en el campo vale la pena usarla sin sobrepreocuparse.
    Aun así, la razón por la que en producción siempre mantuvimos la utilización de CPU por debajo de 40% era para asegurar algo de headroom ante situaciones diversas.
    Me parece una lástima que al autor le falte una base lógica sólida para el argumento de “evitar alta utilización desde la teoría de colas”.

    • Creo que incluso una métrica algo floja basta si se usa apropiadamente en la práctica.
      Por ejemplo, ya sea que simplemente uses el promedio/máximo de métricas percentile por host, o que calcules percentiles al agregar histogramas por host, en mi experiencia el cambio entre ambos no hace gran diferencia en la operación real.
      Hay gente que se preocupa demasiado por si algo es matemáticamente riguroso o no, pero en operación real muchas veces eso no tiene gran impacto.

    • 40% me parece en realidad una utilización bastante relajada, con mucho margen.

    • Creo que viendo CPU% junto con loadavg se puede entender bastante bien el estado del sistema.
      Si loadavg está alto pero CPU% está bajo, puede que esté bloqueado por red o I/O, o esperando por syscalls, etc.
      En esos casos, si solo miras CPU% puedes perder de vista dónde está el sufrimiento real.

    • Siento que ya había escuchado exactamente esta misma historia.
      Me llama la atención que lo que menciona el autor se viene repitiendo desde hace décadas en libros de teoría de colas, y aun así lo escriba como si acabara de descubrirlo.

  • Esto me recordó al post de Brendan Gregg "CPU Utilization is Wrong".
    El punto central de ese blog es que la utilización de CPU solo mide la “situación” de que el CPU está ocupado, e incluso considera busy al CPU cuando está esperando.
    Y el IPC es la métrica para entender cuánto trabajo útil real hay escondido dentro de ese estado busy.

    • Me pregunto por qué las personas llamadas Brendan parecen interesarse tanto en el problema de la utilización de CPU.
      Si existe otro Brendan, espero que pueda explicarlo.
  • No creo que haya que contar el rendimiento que aporta el hyperthreading como si fuera el doble.
    En la práctica real, incluso aprovechándolo bien, muchas veces solo aporta entre 15% y 30% extra de rendimiento. En cambio, la latencia sí puede duplicarse.
    También hay que considerar obligatoriamente la bajada de reloj cuando sube la utilización de los cores, así que siempre hay que tener cuidado con la no linealidad en el mundo real.
    Incluso solo con la información que entrega el OS, si calculas el efecto del hyperthreading y la caída de reloj, puedes estimar una utilización mucho más precisa.
    Más allá de eso, tampoco me parece tan difícil modelar fenómenos como límites de caché/ancho de banda de memoria o stalls de pipeline que terminan degradando el rendimiento.

    • Un factor que complica aún más la situación es que la eficiencia del hyperthreading varía muchísimo según la arquitectura del CPU y la carga de trabajo.
      Por ejemplo, las implementaciones de AMD (sobre todo Zen reciente) tienden a ofrecer un rendimiento mucho más independiente que Intel (asumiendo que no haya cuello de botella de ancho de banda de memoria).

    • Si la aplicación está limitada por memoria, es más fácil ver mejor scaling con hyperthreading.
      En un proyecto de renderer que llevé antes, como era memory-bound, vimos una mejora de rendimiento de 60% a 70% solo con hyperthreading.

    • Hace tiempo corrí un benchmark simple con POV-Ray en un i7-3770K (4C/8T).
      De 1 hilo a 2 hilos fue exactamente el doble, de 2 a 4 también el doble, y de 4 a 8 apenas subió 15%.
      Supongo que con un benchmark raro que repita artificialmente cache misses podrías sacarle casi el doble al SMT, pero dudo de qué tan realista sería.
      PD: estoy pensando en volver a correr esa prueba con POV-Ray. Ha pasado tanto tiempo que me da nostalgia.

  • Parece que el autor notó que el rendimiento no escala linealmente según el % de utilización de CPU y, como resultado, concluyó que el % de utilización de CPU en sí mismo es una “mentira”.
    Incluso sin hyperthreading ni throttling de reloj, y aun en casos como Apple silicon donde parecería haber menos variables, no sale un scaling perfectamente proporcional.
    En cuanto empiezas a usar varios núcleos a la vez, los cuellos de botella de recursos fuera del CPU, como el overhead de mover datos, empiezan a causar problemas frecuentemente y se ve una situación parecida.

    • Apple silicon también baja bastante el reloj, especialmente en modelos sin ventilador (refrigeración pasiva).
  • La terminología de cores que usa el autor es confusa y no estándar.
    Se refiere al 5900X como un sistema de 24 cores, pero en realidad la estructura es de 12 núcleos físicos con 24 hilos de hyperthreading.
    Los 12 son cores físicos y los otros 12 son hilos que van montados sobre cada uno de esos cores.
    Aunque haya 2 sets de instruction pipeline, comparten las functional units internas.

    • Hace algunos años, tratando de explicarle hyperthreading a mi hermano menor, una analogía que se me quedó fue decir que era como un rollo de papel higiénico de dos capas.
      No puedes separar los 24 como si fueran independientes, pero sí es como usar de forma más útil un conjunto de 12 duplicándolo.

    • Tras recibir feedback, corregí la descripción a 12 cores / 24 threads.
      Pero sí me confundía que mi OS mostrara la utilización como si fueran 24 cores.

    • Sería interesante si Intel sacara cores definidos por software.
      Sería como el opuesto lógico del hyperthreading: una estructura en la que dos o más cores comparten recursos y se convierten en “un core grande”.
      Vean el siguiente enlace de patente.
      https://patents.google.com/patent/EP4579444A1/en

    • Si un par SMT ejecuta el mismo tipo de carga de trabajo, el efecto SMT cae por la contención de recursos internos y unidades de ejecución.
      Si las cargas son completamente distintas, el boost puede ser incluso mayor.
      Ahora además, en CPUs modernas, entran variables como P-cores, E-cores, turbo/no turbo, y la situación se vuelve más compleja.
      Había un estudio que mostraba que agregar SMT mejoraba más el rendimiento por watt que agregar turbo, y me pareció muy interesante.

  • Es un tema con el que conecto muchísimo.
    Una vez, hace años, el CPU de un servidor llegó a 60% y cuando intenté explicarle a mi manager que ya no quedaba margen, me miró con cara rara.
    En ese momento me habría encantado tener justo esta explicación.

    • Si además le explicas teoría de colas, el efecto es total.
      Por debajo de 60%, el retraso por colas es prácticamente despreciable.
      Al pasar de 70%, la latencia empieza a sentirse fuerte, y a partir de 80% casi se duplica.
      En mi experiencia real, apuntábamos a 65% en tiempo P95, y eso coincidía casi exactamente con el criterio teórico.
      En resumen, la regla práctica es “60% es el límite de uso, desde 80% la latencia se dispara”.

    • Pero eso puede cambiar completamente según la carga de trabajo.
      Especialmente ahora que estamos en una era de CPUs de servidor con 32 cores, lo veo aún más así.

  • Muchas veces la utilización de CPU no funciona como uno esperaría.
    En general, con este tipo de artículo yo habría esperado una discusión sobre cómo se calcula Utilization en Linux/Windows, pero en la práctica también hay muchos casos en que el CPU está ocioso o bajando reloj por un cuello de botella en RAM.
    En realidad, la utilización de CPU solo mide cuánto asigna el OS hilos a cada core, ya sea Windows o Linux.
    Pero aunque ese hilo esté esperando al 100% dentro de memcpy, igual cuenta como utilización.
    La ventaja del hyperthreading es que, si un hilo está atascado en la unidad AVX/vectorial y otro está atascado en algo simple como memcpy/RAM, puedes elevar el uso de distintas unidades y mejorar tanto el rendimiento total como la utilización.
    En conclusión, CPU Utilization lleva mucho tiempo siendo un tema difícil de entender de forma intuitiva, y siguen apareciendo nuevas perspectivas una y otra vez.
    Aun así, siempre es un tema interesante.

  • La verdadera “mentira” es creer que un core con hyperthreading funciona igual que un core real.
    Después de más de 20 años usándolo, uno termina olvidando su naturaleza original y vuelve a darse cuenta una y otra vez de por qué las mediciones de rendimiento salen raras.
    Otra cosa es que, en el fondo, un procesador solo está “ejecutando” (100%) o “esperando” (0%).
    El hecho mismo de asignarle un % intermedio no es más que un promedio sobre una cierta unidad de tiempo.

  • Recuerdo haber tenido una conversación así antes.
    Manager: como el CPU utilization está al 100%, ¿no deberíamos cambiar el servidor a una instancia más grande?
    Yo: “Pero, ¿el CPU realmente está haciendo trabajo útil ahora mismo?”
    Al final, como el busy waiting también cuenta como CPU utilization, hay casos donde el número sube aunque no tenga nada que ver con trabajo útil real.

 
jjjajh 2025-09-04

Es la expresión correcta.