Añades “más núcleos” a una máquina y tu latencia p99 empeora. No más lenta de forma limpia y predecible, sino peor en el estilo de “¿por qué solo se dispara los martes?”.
O escalas una flota de runners de CI y la mitad de los trabajos terminan rápido mientras la otra mitad toma una ruta escénica por la melaza.
Las CPUs híbridas —mezclando Performance cores (P-cores) y Efficiency cores (E-cores)— suelen ser la causa habitual. No son malas. Simplemente son diferentes.
Si gestionas sistemas en producción, debes tratarlas como cómputo heterogéneo, no como “una CPU, pero con más”.
Un modelo mental que resiste el contacto con producción
P-cores y E-cores no son “rápidos vs lentos” de una forma simple y lineal. Piénsalos como dos clases de capacidad de cómputo con diferente
rendimiento por hilo, comportamiento térmico y de potencia, y a veces características microarquitectónicas.
El scheduler del SO intenta colocar hilos en la clase de núcleo “adecuada”. A veces acierta. A veces se equivoca con seguridad.
Aquí está el modelo apto para producción:
-
P-cores: mayor rendimiento por hilo, mejores para trabajo sensible a la latencia y con muchas ramas, típicamente frecuencias más altas y recursos más robustos
fuera de orden. A menudo son el único lugar donde obtienes el mejor comportamiento turbo con carga ligera. -
E-cores: más hilos por vatio y por mm², normalmente frecuencias más bajas, excelentes para rendimiento en segundo plano, concurrencia y tareas de “no me despiertes para esto”.
No son inútiles—solo no es donde quieres que viva tu latencia de cola. -
Siguen aplicando restricciones compartidas: cachés, ancho de banda de memoria, interconexión ring/mesh, límites de potencia del paquete y estrangulamiento térmico.
Lo híbrido no elimina cuellos de botella; añade uno nuevo: la selección de clase de núcleo.
La idea operativa clave: ya no gestionas “utilización de CPU” de forma genérica. Gestionas qué tipo de CPU estás utilizando.
Un host puede estar “solo 35% ocupado” y aun así no tener margen en P-cores, porque la capacidad restante está en E-cores.
Una verdad seca: las CPUs híbridas hacen que los dashboards deficientes luzcan aún mejor. Un único gráfico de “% CPU” te dirá felizmente que todo está bien mientras
tus hilos de petición esperan detrás de un montón de agentes de logs en E-cores.
Qué cambia cuando los núcleos no son iguales
1) La planificación de capacidad deja de ser escalar
Con núcleos homogéneos, “8 núcleos” significa aproximadamente 8 copias del mismo motor de ejecución. Con híbrido, “16 núcleos” podría significar
“8 algo rápidos, 8 algo más lentos”. La proporción exacta y la brecha dependen de la generación, frecuencias, térmicas y del comportamiento del firmware.
Así que tu vieja regla empírica—peticiones por núcleo, trabajos de build por núcleo, hilos de GC por núcleo—se convierte en una omisión engañosa.
2) Las decisiones de scheduling se convierten en decisiones de rendimiento
En CPUs homogéneas, la planificación afecta sobre todo a la equidad y la localidad de caché. En CPUs híbridas, el scheduler es también un sistema de estratificación de rendimiento.
Poner un hilo crítico para latencia en un E-core no es “perder un 10%”. Cambias toda su distribución de tiempo de servicio.
Así es como obtienes p95 razonable y p99 horrible.
3) El pinning y la aislamiento adquieren más valor—y son más peligrosos
El pinning puede salvarte. El pinning también puede atraparte en los núcleos equivocados para siempre. La versión mala es “lo fijamos a CPU 0-7 en 2022 y nunca lo revisamos”.
En una máquina híbrida, la numeración de CPU puede intercalar tipos de núcleo según BIOS/firmware/SO.
4) Turbo, térmicas y límites de potencia importan más de lo que quisieras
Los diseños híbridos suelen estar ajustados para cargas cliente intermitentes: picos grandes en P-cores, trabajo en segundo plano en E-cores y un presupuesto de potencia que
se mueve dinámicamente. En servidores, la carga sostenida es la norma, no la sorpresa. Bajo carga sostenida, los “núcleos rápidos” pueden no mantenerse tan rápidos,
y los “núcleos eficientes” pueden convertirse en tu línea base de estado constante.
5) El cuello de botella puede ser la propia migración
Si los hilos rebotan entre tipos de núcleo, pagas por cachés frías, distintos estados de frecuencia y la sobrecarga del scheduler.
Las migraciones también cambian los contadores de rendimiento y confunden perfiles ingenuos. Crees que estás midiendo la aplicación. Estás midiendo los altibajos del scheduler.
Broma #1: Las CPUs híbridas son como oficinas de planta abierta—alguien siempre piensa que son eficientes y alguien más siempre usa auriculares con cancelación de ruido.
Hechos y contexto histórico (la versión corta y útil)
-
Big.LITTLE precede a los PCs actuales. El concepto big.LITTLE de ARM apareció a principios de la década de 2010 para mezclar núcleos de alto rendimiento y bajo consumo
en SoC móviles, porque los teléfonos viven y mueren por la batería y las térmicas. -
El scheduling heterogéneo es anterior a los núcleos híbridos. Los centros de datos hace tiempo que lidian con “no todas las CPUs son iguales” mediante
NUMA, distintos turbo bins y steppings mixtos, pero lo híbrido hace la diferencia explícita y por núcleo. - El giro híbrido de Intel llegó con Alder Lake. Esa generación trajo diseños P-core + E-core a escritorios en volumen, obligando a los schedulers de propósito general a ponerse serios.
-
Windows obtuvo pronto una historia de pistas de hardware. Intel Thread Director ofrece orientación sobre la “clase” y el comportamiento del hilo,
que Windows usa agresivamente para decisiones de colocación en CPUs compatibles. -
Linux eligió una ruta más general. En lugar de depender solo de la interfaz de pista de un proveedor, Linux construyó planificación consciente de capacidad
y conciencia de tipos de núcleo que puede funcionar en diseños heterogéneos, pero la calidad depende de la versión del kernel y los detalles de la plataforma. -
SMT/Hyper-Threading interactúa con lo híbrido de formas no obvias. Muchos diseños híbridos tienen SMT en P-cores pero no en E-cores.
Así que “32 hilos” podría significar “16 núcleos físicos, pero solo la mitad tienen SMT”. -
La numeración de CPU no es un contrato. Los IDs lógicos de CPU pueden mapear a tipos de núcleo de formas que varían por BIOS, microcódigo y kernel.
Scripts que asumen “CPU0..CPU7 son los rápidos” son la forma en que nacen los incidentes. -
Los límites de potencia pueden convertir una CPU híbrida en una CPU diferente. Bajo restricciones PL1/PL2, el rendimiento sostenido con todos los núcleos puede aplanarse,
reduciendo la brecha entre P y E para trabajos de rendimiento mientras mantienen diferencias de latencia agudas. -
Las familias de instancias cloud ya hicieron “heterogéneo” en silencio. Instancias burstables, VMs con núcleo compartido y comportamiento de vecinos ruidosos
entrenaron a muchos equipos a buscar artefactos del scheduler; lo híbrido hace esos artefactos posibles incluso en metal desnudo.
Realidad del scheduler: Linux, Windows y el gris intermedio
Linux: capacidad, asimetría y un impuesto por versión de kernel
Los schedulers modernos de Linux pueden entender que algunas CPUs tienen más “capacidad” que otras. En práctica, te importan:
la versión del kernel, el microcódigo/firmware y si la plataforma expone la topología claramente.
Intentas responder dos preguntas operativas:
- ¿Prefiere el scheduler colocar tareas de alta utilización en núcleos de mayor capacidad?
- ¿Evita dejar hilos sensibles a la latencia varados en E-cores bajo carga?
La respuesta suele ser “en su mayoría sí, a menos que ejecutes contenedores, fijes CPUs, uses un kernel antiguo o tengas una carga que las heurísticas clasifiquen mal.”
No es una queja; es solo la realidad. La planificación es estadística aplicada con bordes afilados.
Windows: comportamiento por defecto fuerte, pero no mágico
Windows en sistemas híbridos Intel compatibles usa las pistas de Intel Thread Director para clasificar hilos y colocarlos en consecuencia.
Eso ayuda con cargas interactivas y mixtas de escritorio. En cargas tipo servidor, aún necesitas validar.
Tareas en segundo plano pueden volverse de primer plano en el peor momento. Tu trabajo por lotes “de baja prioridad” podría ser el que sostiene un lock.
Virtualización y contenedores: puedes ocultar los tipos de núcleo, pero no la física
Los hipervisores pueden presentar vCPUs sin exponer “esto es un P-core” al invitado, dependiendo de la configuración.
Eso puede simplificar compatibilidad, pero también puede impedir que el SO invitado haga buenas decisiones de colocación.
Los contenedores son peores en un sentido particular: animan al pinning de CPU (“solo dame 4 CPUs para este pod”) mientras abstraen la topología.
Si tu pinning cae en E-cores, enhorabuena por tu “optimización de costes” que parece una regresión.
Una idea parafraseada de Gene Kim: el trabajo de confiabilidad trata de hacer los modos de fallo obvios y recuperables, no de pretender que no ocurrirán.
La planificación híbrida añade nuevos modos de fallo; tu trabajo es hacerlos visibles.
Qué cargas quieren P-cores y cuáles toleran E-cores
Rutas de petición sensibles a latencia: P-cores por defecto
Si un hilo afecta tu SLO, trátalo como ciudadano de primera clase. Manejadores web de peticiones, workers RPC, hilos de primer plano de bases de datos,
hilos de IO de brokers de mensajes, demonios de almacenamiento sensibles a la latencia de cola—estos pertenecen a P-cores cuando puedas.
¿Por qué? Porque el rendimiento por hilo y frecuencias consistentes importan más que el rendimiento agregado cuando persigues p99.
E-cores pueden estar bien para la latencia media y luego sorprenderte en la cola cuando el sistema está ocupado y la contención crece.
Rendimiento en segundo plano: E-cores son geniales—hasta que dejan de serlo
Compresión de logs, scraping de métricas, ETL por lotes, transcodificación de video, builds de CI, indexación, escaneo antivirus (sí, aún existe),
y tareas tipo “ejecutemos un informe semanal al mediodía” funcionan bien en E-cores.
La trampa: el trabajo en segundo plano a menudo comparte recursos y locks con el trabajo de primer plano. Así es como una “carga de E-core” se convierte en un “incidente de P-core”.
Si tu trabajo en segundo plano retiene un mutex necesario para los hilos de petición, no importa que sea “baja prioridad”. Ahora es un amplificador de latencia.
Almacenamiento y redes: el cuello de botella se mueve
Las pilas de almacenamiento pueden estar limitadas por CPU (compresión, checksums, cifrado, codificación por eliminación), por memoria (copias, page cache) o por IO.
Lo híbrido afecta las partes limitadas por CPU y las partes de “despertar, manejar interrupción, hacer trabajo pequeño”.
Para altas tasas de paquetes, almacenamiento de bloques pequeños o mucho TLS, a menudo quieres P-cores para la ruta caliente y E-cores para todo lo demás.
La ganancia real es el aislamiento: mantener el trabajo ruidoso alejado de la ruta determinista.
Recolección de basura y runtimes: no dejes que ellos decidan por ti
JVM, Go, .NET, Node—los runtimes crean hilos auxiliares, hilos de GC, hilos JIT. Si estos caen en E-cores mientras tus hilos de app están en P-cores,
aún puedes tener pausas porque los auxiliares son lentos. Si los hilos de app caen en E-cores, obtienes tiempo de servicio lento.
En cualquier caso, necesitas observar la colocación de hilos y ajustar.
Broma #2: “Más núcleos” es un gran plan hasta que te das cuenta de que la mitad son pasantes—entusiastas, serviciales y no la persona que quieres haciendo cirugía.
Tareas prácticas: comandos, salidas y decisiones (12+)
Estas son las comprobaciones que realmente ejecuto cuando un sistema híbrido huele mal. Cada tarea incluye: un comando, salida realista,
qué significa la salida y la decisión que tomas a partir de ella.
Task 1: Identificar rápidamente la CPU y la topología híbrida
cr0x@server:~$ lscpu | egrep 'Model name|CPU\(s\)|Thread|Core|Socket|NUMA|Vendor'
Vendor ID: GenuineIntel
Model name: 13th Gen Intel(R) Core(TM) i9-13900K
CPU(s): 32
Thread(s) per core: 2
Core(s) per socket: 24
Socket(s): 1
NUMA node(s): 1
Significado: 24 núcleos físicos, 32 CPUs lógicas. Este patrón suele implicar SMT en algunos núcleos (típicamente P-cores) y no en otros (a menudo E-cores).
Decisión: No asumas que “32 hilos” son equivalentes. Pasa a la detección del tipo de núcleo antes de fijar nada.
Task 2: Mapear CPUs lógicas a tipo de núcleo (P vs E) vía sysfs
cr0x@server:~$ for c in /sys/devices/system/cpu/cpu[0-9]*; do \
n=${c##*cpu}; \
cap=$(cat $c/cpu_capacity 2>/dev/null); \
echo "cpu$n capacity=$cap"; \
done | head
cpu0 capacity=1024
cpu1 capacity=1024
cpu2 capacity=1024
cpu3 capacity=1024
cpu4 capacity=1024
cpu5 capacity=1024
cpu6 capacity=1024
cpu7 capacity=1024
cpu8 capacity=768
cpu9 capacity=768
Significado: La capacidad difiere por CPU. Mayor capacidad típicamente corresponde a P-cores; menor a E-cores. (Los valores exactos varían.)
Decisión: Construye un conjunto de CPUs: CPUs de P-core (capacity=1024) para cargas sensibles a latencia; CPUs de E-core para lotes/segundo plano.
Task 3: Confirmar diferencias de frecuencia máxima por núcleo
cr0x@server:~$ sudo apt-get -y install linux-tools-common linux-tools-generic >/dev/null
cr0x@server:~$ sudo cpupower frequency-info -p | head -n 12
analyzing CPU 0:
current policy: frequency should be within 800 MHz and 5500 MHz.
The governor "schedutil" may decide which speed to use
within this range.
analyzing CPU 8:
current policy: frequency should be within 800 MHz and 4200 MHz.
The governor "schedutil" may decide which speed to use
within this range.
Significado: La CPU 0 tiene un techo más alto que la CPU 8. Esto es consistente con el comportamiento P vs E.
Decisión: Si la latencia de cola importa, asegúrate de que la ruta caliente sea elegible para correr en núcleos con techos más altos.
Task 4: Ver cómo el kernel etiqueta CPUs híbridas/heterogéneas
cr0x@server:~$ dmesg | egrep -i 'hybrid|asym|capacity|intel_pstate|sched' | head
[ 0.412345] x86/cpu: Hybrid CPU detected.
[ 0.512998] sched: CPU capacity scaling enabled
[ 1.103221] intel_pstate: Intel P-state driver initializing
Significado: El kernel detecta una CPU híbrida y la escalación de capacidad está habilitada.
Decisión: Si no ves esto en hardware conocido como híbrido, sospecha problemas de kernel/BIOS/microcódigo; planea una actualización antes de culpar a la app.
Task 5: Comprobar el governor actual y decidir si es apropiado
cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
schedutil
Significado: El governor es schedutil (común por defecto). Reacciona a señales de utilización del scheduler.
Decisión: Para nodos críticos en latencia, considera performance (o perfiles tuned) si la subida de frecuencia causa picos—después de medir potencia/térmicas.
Task 6: Medir la presión de la cola de ejecución (¿estamos hambrientos de CPU?)
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
3 0 0 8123456 123456 3456789 0 0 0 2 910 1820 18 6 75 0 0
9 0 0 8123000 123456 3456800 0 0 0 0 1400 9000 42 12 46 0 0
8 0 0 8122900 123456 3456900 0 0 0 0 1300 8700 44 10 46 0 0
2 0 0 8122800 123456 3457000 0 0 0 0 980 2100 20 6 74 0 0
Significado: La columna r hace picos (cola de ejecución). Eso es contención de CPU. No te dice si la contención está en P-cores o en E-cores.
Decisión: Si la cola de ejecución es alta durante picos de latencia, comprueba si los P-cores están saturados mientras los E-cores están inactivos.
Task 7: Vigilar la utilización por CPU para detectar saturación de P-cores
cr0x@server:~$ mpstat -P ALL 1 2 | egrep 'Average|^[0-9]' | head -n 20
00:00:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
00:00:01 AM 0 72.00 0.00 18.00 0.00 0.00 0.00 0.00 0.00 0.00 10.00
00:00:01 AM 1 70.00 0.00 20.00 0.00 0.00 0.00 0.00 0.00 0.00 10.00
00:00:01 AM 8 18.00 0.00 6.00 0.00 0.00 0.00 0.00 0.00 0.00 76.00
00:00:01 AM 9 20.00 0.00 5.00 0.00 0.00 0.00 0.00 0.00 0.00 75.00
Significado: Las CPUs 0–1 están calientes; las CPUs 8–9 están mayormente inactivas. Si 0–7 son P-cores y 8+ son E-cores, probablemente hayas saturado los P-cores.
Decisión: Reduce la contención de P-cores: fija hilos calientes a P-cores, mueve el trabajo en segundo plano a E-cores o disminuye la concurrencia en la ruta de latencia.
Task 8: Inspeccionar dónde puede ejecutarse un proceso (cpuset/affinity)
cr0x@server:~$ pidof nginx
2143
cr0x@server:~$ taskset -pc 2143
pid 2143's current affinity list: 0-31
Significado: Nginx puede ejecutarse en cualquier CPU. Eso está bien si el scheduler es inteligente; es arriesgado si procesos en segundo plano compiten en P-cores.
Decisión: Si luchas contra la latencia de cola, considera dar a nginx (o a tus workers de petición) una afinidad solo a P-cores.
Task 9: Fijar un servicio sensible a latencia a P-cores (ejemplo)
cr0x@server:~$ sudo systemctl show -p MainPID myapi.service
MainPID=8812
cr0x@server:~$ sudo taskset -pc 0-7 8812
pid 8812's current affinity list: 0-31
pid 8812's new affinity list: 0-7
Significado: El proceso principal está restringido a CPUs 0–7 (suponiendo P-cores basándote en tu mapeo de capacidad).
Decisión: Valida la mejora en p99 y asegúrate de no haber dejado al servicio sin CPU suficiente bajo carga por darle demasiadas pocas CPUs.
Task 10: Enviar trabajos en segundo plano a E-cores usando CPUAffinity de systemd
cr0x@server:~$ sudo systemctl edit logshipper.service
cr0x@server:~$ sudo cat /etc/systemd/system/logshipper.service.d/override.conf
[Service]
CPUAffinity=8-31
Nice=10
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart logshipper.service
cr0x@server:~$ sudo systemctl show -p CPUAffinity logshipper.service
CPUAffinity=8-31
Significado: El log shipper está cercado a CPUs 8–31 (probablemente E-cores + tal vez hermanos SMT según la topología).
Decisión: Este es uno de los movimientos de producción más limpios: protege la ruta caliente aislando a los vecinos ruidosos.
Task 11: Comprobar colocación por hilo y migraciones
cr0x@server:~$ pidof myapi
8812
cr0x@server:~$ ps -L -p 8812 -o pid,tid,psr,comm | head
PID TID PSR COMMAND
8812 8812 2 myapi
8812 8820 4 myapi
8812 8821 6 myapi
8812 8822 1 myapi
Significado: PSR es la CPU en la que un hilo corrió por última vez. Si ves hilos rebotando entre rangos de CPU P y E, puedes obtener jitter.
Decisión: Si las migraciones correlacionan con picos de latencia, ajusta la afinidad o reduce despertares entre núcleos (pools de hilos, work stealing).
Task 12: Identificar throttling (el asesino silencioso del rendimiento)
cr0x@server:~$ sudo apt-get -y install linux-cpupower >/dev/null
cr0x@server:~$ sudo turbostat --quiet --Summary --interval 1 --num_iterations 3 | head -n 12
time cores CPU%c1 CPU%c6 Avg_MHz Busy% Bzy_MHz TSC_MHz PkgTmp PkgWatt
1.00 24 12.34 45.67 2890 48.2 5120 3600 92.0 210.5
2.00 24 10.20 40.10 2710 55.0 4920 3600 95.0 225.0
3.00 24 9.80 35.00 2500 60.1 4580 3600 98.0 230.0
Significado: Temperatura de paquete y vatios altos; Bzy_MHz cae con el tiempo. Eso suele ser comportamiento térmico o de límite de potencia bajo carga sostenida.
Decisión: Si el rendimiento empeora conforme el sistema se calienta, arregla la refrigeración, límites de potencia o el flujo de aire del chasis antes de reescribir código.
Task 13: Perfilar consumidores calientes de CPU (no hagas conjeturas)
cr0x@server:~$ sudo perf top -p 8812 --stdio --sort comm,dso,symbol | head
Samples: 1K of event 'cpu-clock', Event count (approx.): 250000000
Overhead Command Shared Object Symbol
18.20% myapi myapi [.] parse_request
12.50% myapi libc.so.6 [.] __memcmp_avx2_movbe
9.10% myapi myapi [.] serialize_response
6.70% myapi libcrypto.so.3 [.] aes_gcm_encrypt
Significado: Tienes hotspots reales de CPU. Los problemas híbridos a menudo se presentan como “de repente CPU-bound” porque el hilo cayó en un E-core o fue limitado.
Decisión: Si la CPU es genuinamente el cuello de botella, optimiza. Si la CPU es “el cuello de botella” solo en E-cores, arregla la colocación primero.
Task 14: Comprobar cuotas de cgroup (los contenedores pueden autoboicotearse)
cr0x@server:~$ systemctl show -p ControlGroup myapi.service
ControlGroup=/system.slice/myapi.service
cr0x@server:~$ cat /sys/fs/cgroup/system.slice/myapi.service/cpu.max
200000 100000
Significado: Cuota de CPU: 200ms por período de 100ms => efectivamente 2 CPUs de tiempo, independientemente de cuántos núcleos existan.
Decisión: Si los picos de latencia se alinean con el throttling, aumenta la cuota o remuévela para la ruta caliente; de lo contrario estarás persiguiendo fantasmas.
Task 15: Kubernetes: verificar la política del CPU Manager y CPUs exclusivas
cr0x@server:~$ kubectl get node worker-7 -o jsonpath='{.status.nodeInfo.kernelVersion}{"\n"}'
6.5.0-27-generic
cr0x@server:~$ kubectl -n kube-system get cm kubelet-config -o yaml | egrep 'cpuManagerPolicy|reservedSystemCPUs'
cpuManagerPolicy: static
reservedSystemCPUs: "8-15"
Significado: El CPU manager está en política estática y puede asignar CPUs exclusivas a pods Guaranteed. Se reservan CPUs del sistema (aquí 8–15).
Decisión: Decide qué CPUs son “sistema” vs “carga de trabajo”. En híbrido, reserva E-cores para demonios del sistema cuando sea posible y asigna P-cores a pods sensibles a latencia.
Task 16: Verificar la asignación real de CPU para un pod
cr0x@server:~$ kubectl describe pod myapi-7f6d7c9d7f-9k2lq | egrep 'QoS Class|Requests|Limits|cpuset'
QoS Class: Guaranteed
Requests:
cpu: 4
Limits:
cpu: 4
Significado: Pod Guaranteed con request/limit iguales es elegible para CPUs exclusivas bajo política estática.
Decisión: Confirma que el cpuset asignado en el nodo coincida con P-cores. Si cae en E-cores, ajusta el topology manager / conjuntos reservados de CPU.
Guion de diagnóstico rápido
Esta es la secuencia de “tengo 15 minutos antes de que el bridge del incidente se ponga raro”. El objetivo no es comprensión perfecta.
El objetivo es encontrar la clase de cuello de botella: saturación de P-cores, colocación en E-cores, throttling o límites no relacionados con la CPU.
Primero: decide si el síntoma es latencia, rendimiento o variación
- Picos de latencia (p95/p99): sospecha mala colocación, contención en P-cores, throttling o amplificación por locks.
- Caída de rendimiento: sospecha límites térmicos/potencia, cuotas de CPU o un trabajo en segundo plano robando ciclos.
- Variación entre trabajos idénticos: sospecha diferencias de scheduling (P vs E), pinning de CPU o vecinos ruidosos.
Segundo: comprueba si los P-cores están saturados mientras los E-cores están inactivos
- Ejecuta
mpstat -P ALL 1y busca “algunas CPUs al tope, otras inactivas”. - Confirma cuáles CPUs lógicas son P vs E usando
/sys/devices/system/cpu/*/cpu_capacity.
Si los P-cores están al máximo y los E-cores inactivos: probablemente necesitas arreglos de colocación o ajuste de concurrencia.
Si todo está al máximo: puede que simplemente estés limitado por CPU (o por throttling).
Tercero: revisa throttling y comportamiento de potencia/térmicas
turbostatresumen: vigilaPkgTmp,PkgWatty la caída deBzy_MHz.- Busca techos de frecuencia más bajos de lo esperado con
cpupower frequency-info.
Si el rendimiento decae en minutos bajo carga sostenida: trátalo como problema de refrigeración/potencia primero.
El software no puede escapar de un límite PL1 para siempre.
Cuarto: comprueba cuotas de cgroup y pinning
- Valida
cpu.max(cgroups v2) ocpu.cfs_quota_us(v1). - Revisa la afinidad con
tasksetpara tus procesos calientes.
Las cuotas pueden hacerse pasar por “raruras híbridas”. El pinning puede encerrar en una “prisión de E-cores”.
Quinto: perfila brevemente la ruta caliente
perf toppor 30–60 segundos en un proceso representativo.- Si ves contención de locks o hotspots de crypto/compresión, decide si necesitas colocación en P-cores o cambios de código.
Tres micro-historias corporativas desde las trincheras de CPUs híbridos
Micro-historia 1: Un incidente causado por una suposición equivocada
Una empresa migró una API sensible a la latencia de servidores homogéneos a cajas híbridas brillantes. El despliegue pareció seguro:
la utilización de CPU bajó, la memoria estaba bien y el primer canario no mostró errores evidentes.
Entonces la latencia p99 se duplicó durante los picos entre semana. No p50. No p90. Solo la cola. El presupuesto de errores empezó a sangrar de esa manera silenciosa que arruina hojas de cálculo.
El equipo on-call asumió que “más núcleos” significaba “más margen”. Aumentaron los hilos de worker y la concurrencia. Eso mejoró la media y empeoró la cola. Clásico. Estaban alimentando al scheduler con más hilos ejecutables, y el scheduler colocaba algunos de ellos en E-cores bajo carga—especialmente los hilos que despertaban más tarde y recibían el trato de “lo que esté libre”.
La solución fue aburrida y precisa: mapear los CPUs lógicos de P-core, fijar los workers de petición a P-cores y cercar los servicios en segundo plano a E-cores.
También redujeron la sobre-provisión de workers para evitar explosiones en la cola de ejecución. El p99 volvió a la normalidad, y el %CPU pareció “peor” porque ahora los núcleos correctos estaban ocupados.
La lección real: si tu modelo de rendimiento es “un núcleo es un núcleo”, lo híbrido te castigará. No lo hace maliciosamente. Lo hace consistentemente.
Micro-historia 2: Una optimización que salió mal
Otro equipo ejecutaba un nodo de carga mixta: una base de datos, un agente de métricas, un forwarder de logs y un indexador en segundo plano.
Notaron que la base de datos ocasionalmente alcanzaba contención de CPU y decidieron “optimizar” fijando la base de datos a un conjunto fijo de CPUs.
El cambio fue ordenado. El gráfico en staging estaba verde. El ingeniero se fue a casa temprano.
En producción, la latencia de consultas degradó lentamente durante la semana siguiente. No fue un cliff. Fue una pendiente. La base de datos quedó fijada a CPUs 0–11.
En esa configuración de BIOS particular, CPUs 0–7 eran P-cores (genial) y CPUs 8–11 eran E-cores (menos genial).
Bajo carga de solo lectura, los hilos de primer plano de la BD se mantuvieron mayormente en P-cores, pero algunos hilos críticos de fondo quedaron atrapados compitiendo en el lado de E-cores del conjunto fijado: checkpointers, compactación y algunos workers de mantenimiento.
Sin querer crearon un mundo CPU dividido: algunas partes internas de la BD corrían rápido; otras corrían lento; las lentas a veces retenían locks y retrasaban a las rápidas.
La aplicación lo percibió como jitter aleatorio.
El rollback lo arregló. La mejora eventual fue más matizada: fijar los workers de primer plano a P-cores, fijar agentes ruidosos a E-cores y dejar cierta flexibilidad para que los hilos de fondo de la BD usen tiempo sobrante de P-cores durante ventanas de mantenimiento. También añadieron una alerta en la profundidad de la cola de P-cores (no solo %CPU total).
La lección: el pinning es un escalpelo. Si lo usas como un martillo, encontrará hueso.
Micro-historia 3: Una práctica aburrida pero correcta que salvó el día
Un equipo de almacenamiento operaba una flota de servidores de build y cachés de artefactos. Su carga era en picos: compresión y hashing intensos durante builds,
luego mayormente inactivos. Adoptaron CPUs híbridas por razones de costo y energía, pero hicieron algo impopular: validaron la topología y la documentaron.
Para cada SKU de hardware, registraron: qué CPUs lógicas mapear a qué tipo de núcleo, frecuencias sostenidas típicas bajo carga y el comportamiento térmico
dentro del rack. También mantuvieron una pequeña baseline de kernel “conocida buena” y no dejaron que nodos aleatorios divergieran.
Era el tipo de trabajo por el que nadie aplaude porque parece papeleo.
Meses después, una actualización de firmware del proveedor cambió la enumeración de CPU en un subconjunto de nodos. De repente, algunos agentes de build quedaron fijados a las CPUs equivocadas y los builds se ralentizaron.
Debido a que tenían un job de validación de topología en CI para la imagen (y una comprobación de runtime simple en el arranque), los nodos se marcaron como “topology changed”
y fueron drenados automáticamente. No hubo incidente. Solo un ticket y una corrección tranquila.
La lección: las CPUs híbridas recompensan la higiene operativa. Si tratas la topología como datos y la validas, conviertes “rendimiento misterioso” en un cambio controlado.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: p99 con picos mientras el “% CPU general” es bajo
Causa raíz: P-cores saturados mientras E-cores están inactivos; el scheduler coloca hilos calientes incorrectamente bajo carga.
Solución: Mapear CPUs de P-core (capacidad/frecuencia), fijar hilos críticos a P-cores, cercar demonios en segundo plano a E-cores y reducir la explosión de hilos ejecutables.
2) Síntoma: trabajos por lotes idénticos varían salvajemente en tiempo de ejecución
Causa raíz: Algunos trabajos corren mayormente en P-cores, otros en E-cores; o las cuotas de cgroup causan throttling desigual.
Solución: Para lotes de throughput, acepta la variación o prográmalos explícitamente (afinidad) a E-cores. Si necesitas equidad, normaliza fijándolos a la misma clase de núcleo.
3) Síntoma: “Actualizamos CPU, pero los builds se hicieron más lentos después de 10 minutos”
Causa raíz: Throttling térmico/potencia bajo carga sostenida; las expectativas de turbo estaban basadas en benchmarks cortos.
Solución: Usa turbostat bajo carga similar a producción, ajusta refrigeración/límites de potencia y mide rendimiento sostenido—no solo el burst.
4) Síntoma: pods Guaranteed en Kubernetes todavía tienen jitter
Causa raíz: CPUs exclusivas asignadas, pero son la clase equivocada (E-cores) o están compartidas con CPUs del sistema con mucho IRQ.
Solución: Usa CPU manager + topology manager intencionalmente. Reserva E-cores para tareas del sistema cuando sea posible; asigna P-cores a pods de latencia; mantén trabajo IRQ-intenso fuera del cpuset caliente.
5) Síntoma: Fijar mejoró la latencia promedio pero empeoró la cola
Causa raíz: Fijaste hilos de primer plano pero dejaste hilos de fondo que sostienen locks en E-cores, creando un plano de control lento para un plano de datos rápido.
Solución: Identifica hilos críticos de fondo (mantenimiento DB, auxiliares de GC), asegúrate de que puedan ejecutarse en P-cores durante picos, o aíslalos con slices dedicados de P-cores.
6) Síntoma: los perfiles de perf no coinciden con la realidad
Causa raíz: Los hilos migran entre tipos de núcleo; el muestreo captura un comportamiento de CPU distinto al que causa la latencia visible al usuario.
Solución: Reduce migraciones (afinidad), perfila bajo colocación estable y correlaciona las ventanas de perfilado con métricas del scheduler y throttling.
7) Síntoma: “La CPU está al tope” pero solo algunos núcleos están calientes
Causa raíz: Cuello de botella por hilo único o contención de locks corriendo en P-cores; los E-cores no pueden ayudar porque el cuello de botella está serializado.
Solución: Reduce la serialización (contención de locks), mejora el paralelismo o aumenta el número de P-cores por instancia. No intentes resolver un mutex con E-cores.
Listas de verificación / plan paso a paso
Paso a paso: adoptar CPUs híbridas sin destrozar la latencia
-
Inventaria la topología el primer día. Registra IDs de CPU de P-core vs E-core usando comprobaciones de capacidad/frecuencia.
Trátalo como configuración, no como conocimiento tribal. - Decide qué cargas obtienen P-cores. Por defecto: todo en la ruta de petición, hilos de BD en primer plano y hilos IO críticos.
- Cerca los servicios en segundo plano. Log shippers, agentes de métricas, indexadores, escáneres, helpers de build—ponlos en E-cores.
- Valida el rendimiento sostenido. Ejecuta una prueba de carga de 30–60 minutos y observa frecuencia/temperatura. Lo híbrido es sensible a límites de potencia.
- Elimina dashboards engañosos. Añade métricas por núcleo o por clase de núcleo: utilización P-core, utilización E-core, tasa de migraciones, tasa de throttling.
- Haz el pinning explícito y revisado. Si usas afinidad, encódala en unidades systemd o configuraciones del orquestador y revísala en cambios de kernel/firmware.
- Ensaya los modos de fallo. ¿Qué pasa cuando los P-cores se saturan? ¿Sacas carga, reduces concurrencia o degradás gradualmente?
Checklist operativa: antes de culpar a la aplicación
- Confirma que el kernel ve la topología híbrida (dmesg).
- Confirma el mapeo P/E (cpu_capacity o techos de frecuencia).
- Revisa saturación de P-cores vs inactividad de E-cores (mpstat).
- Revisa throttling (turbostat).
- Revisa cuotas de cgroup (cpu.max).
- Revisa afinidades (taskset, CPUAffinity de systemd, CPU manager de kube).
- Solo entonces perfila el código (perf).
Sugerencia de política: una estrategia sensata por defecto
- Tier de latencia: solo P-cores, trabajo en segundo plano mínimo, frecuencias estables (dentro del presupuesto de potencia).
- Tier de rendimiento: preferir E-cores, permitir desbordamiento a P-cores fuera de pico si no perjudica los SLOs de latencia.
- Tier del sistema: reserva un pequeño cpuset para SO y demonios; preferentemente E-cores si tienes suficientes, pero considera comportamiento de IRQ/softirq.
Preguntas frecuentes
1) ¿Son los E-cores “núcleos lentos”?
Tienen menor rendimiento por hilo comparado con P-cores, típicamente. Pero pueden ser excelentes por vatio para throughput, especialmente en cargas paralelas.
El error es asumir “un núcleo es un núcleo” cuando haces cálculos de latencia.
2) ¿Debo desactivar los E-cores en BIOS para servidores?
A veces, sí—si tu carga es puramente sensible a latencia, tu stack no puede manejar heterogeneidad o necesitas comportamiento determinista rápido.
Pero es una herramienta burda. Prueba primero aislamiento y colocación; desactivar E-cores tira capacidad útil de throughput.
3) ¿Por qué “la utilización de CPU” parece bien mientras el rendimiento es malo?
Porque la única capacidad que realmente necesitas puede ser la de P-core. Si los P-cores están saturados y los E-cores inactivos, el %CPU medio te mentirá.
Mide por clase de núcleo, no por total.
4) ¿El pinning siempre ayuda en CPUs híbridas?
No. El pinning ayuda cuando evita interferencias y asegura que la ruta caliente corra en los núcleos correctos.
Daña cuando fijas a CPUs equivocadas, dejas sin CPU a hilos auxiliares críticos o impides que el scheduler se adapte a cambios de carga.
5) ¿Cómo encuentro qué CPUs lógicas son P-cores?
En Linux, el enfoque más práctico es comparar cpu_capacity (si está presente) y techos de frecuencia por CPU vía cpupower.
No confíes en patrones de numeración sin verificarlos en ese host.
6) ¿Los E-cores afectan el rendimiento de almacenamiento?
Pueden hacerlo. Las pilas de almacenamiento a menudo tienen componentes intensivos en CPU (compresión, checksums, cifrado) y trabajo impulsado por interrupciones.
Si tus hilos de finalización de IO caen en E-cores, puedes ver mayor latencia incluso cuando los discos están bien.
7) ¿SMT (Hyper-Threading) es bueno o malo en sistemas híbridos?
Depende de la carga. SMT puede aumentar el throughput pero añadir contención y jitter para cargas sensibles a latencia.
Lo híbrido complica esto porque SMT puede existir solo en P-cores, cambiando el significado de “N CPUs” en pinning y cuotas.
8) ¿Cómo debo benchmarkear CPUs híbridas?
Haz benchmarking con concurrencia similar a producción, duración sostenida (para capturar throttling) y mediciones separadas para:
solo P-cores, solo E-cores y programación mixta. Si solo ejecutas tests sintéticos cortos, sobreestimarás el rendimiento real.
9) ¿Necesito ajustes especiales de Kubernetes para CPUs híbridas?
Si ejecutas pods sensibles a latencia, sí: política static del CPU manager, conjuntos reservados de CPU bien pensados y validación de que las CPUs exclusivas mapearon a P-cores.
De lo contrario podrías ser “Guaranteed” en el papel y “E-cored” en la práctica.
Conclusión: pasos prácticos siguientes
Las CPUs híbridas no son un truco. Son un intercambio honesto: más throughput por vatio y por área de die, a costa de heterogeneidad.
En producción, la heterogeneidad significa que debes ser explícito sobre colocación y medición.
- Mide las clases de núcleo (capacidad/frecuencia) y mantén el mapeo bajo control de versiones para cada SKU de hardware.
- Protege la ruta caliente: fija o restringe servicios críticos a P-cores; cercar servicios en segundo plano a E-cores.
- Vigila el throttling bajo carga sostenida; arregla potencia/refrigeración antes de optimizar código.
- Deja de confiar en el %CPU total; instrumenta la saturación de P-cores por separado y alerta sobre ella.
- Revisa el pinning regularmente tras cambios de BIOS, firmware y kernel—la topología no es inmutable.
Haz esas cosas y las CPUs híbridas se vuelven predecibles. Ignóralas y obtendrás un juego de golpea-la-rata de rendimiento con hojas de especificaciones más bonitas.