Vous ajoutez « plus de cœurs » à une machine et votre latence p99 s’aggrave. Pas simplement plus lente de façon propre et prévisible — pire dans le style « pourquoi ça grimpe seulement le mardi ».
Ou vous étendez une flotte de runners CI et la moitié des jobs termine vite tandis que l’autre moitié prend un chemin panoramique à travers de la mélasse.
Les CPU hybrides — mélangeant des Performance cores (P-cores) et des Efficiency cores (E-cores) — sont le coupable habituel. Ils ne sont pas mauvais. Ils sont juste différents.
Si vous exploitez des systèmes de production, vous devez les traiter comme du calcul hétérogène, pas comme « un CPU, mais en plus ».
Un modèle mental qui survit au contact de la production
Les P-cores et les E-cores ne sont pas « rapides vs lents » de manière simple et linéaire. Pensez-les comme deux classes de capacité de calcul avec des
performances mono-thread, comportements énergie et thermique et parfois des caractéristiques microarchitecturales différentes.
L’ordonnanceur du système tente de placer les threads sur la « bonne » classe de cœurs. Parfois il a raison. Parfois il se trompe avec confiance.
Voici le modèle adapté à la production :
- P-cores : meilleur débit par thread, préférable pour le travail sensible à la latence et aux branches, typiquement des fréquences plus élevées et des ressources out-of-order plus généreuses. Souvent l’endroit où l’on obtient le meilleur comportement turbo en charge légère.
- E-cores : plus de threads par watt et par mm², généralement des fréquences plus basses, excellents pour le débit en arrière-plan, la concurrence et les tâches « ne me réveillez pas pour ça ». Pas inutiles — simplement pas là où vous voulez que vive votre latence de queue.
-
Des contraintes partagées s’appliquent toujours : caches, bande passante mémoire, interconnexion ring/mesh, limites de puissance du package et throttling thermique.
L’hybride n’enlève pas les goulots d’étranglement ; il en ajoute un nouveau : la sélection de la classe de cœurs.
L’intuition opérationnelle clé : vous ne gérez plus la « utilisation CPU » de manière globale. Vous gérez quel type de CPU vous exploitez.
Un hôte peut être « seulement 35% occupé » et manquer quand même de marge sur les P-cores, parce que la capacité restante est sur les E-cores.
Une vérité sèche : les CPU hybrides rendent les tableaux de bord médiocres encore plus convaincants. Un seul graphe « % CPU » vous dira joyeusement que tout va bien alors que vos threads de requête font la queue derrière une pile d’agents de logs sur les E-cores.
Ce qui change lorsque les cœurs ne sont pas égaux
1) La planification de capacité cesse d’être scalaire
Avec des cœurs homogènes, « 8 cœurs » signifie à peu près 8 copies du même moteur d’exécution. Avec l’hybride, « 16 cœurs » peut signifier
« 8 rapides, 8 plus lents ». Le ratio exact et l’écart dépendent de la génération, des fréquences, des thermiques et du comportement du firmware.
Votre ancienne règle empiriquement utile — requêtes par cœur, jobs de build par cœur, threads GC par cœur — devient une omission dangereuse.
2) Les décisions d’ordonnancement deviennent des décisions de performance
Sur des CPU homogènes, l’ordonnancement affecte surtout l’équité et la localité du cache. Sur des CPU hybrides, l’ordonnanceur est aussi un système de tiering de performance.
Placer un thread critique pour la latence sur un E-core ne « fait pas perdre 10% ». Vous avez changé toute sa distribution de temps de service.
C’est comme ça que vous obtenez un p95 correct et un p99 moche.
3) Le pinning et l’isolation prennent plus de valeur — et deviennent plus dangereux
Le pinning peut vous sauver. Le pinning peut aussi vous enfermer sur les mauvais cœurs pour toujours. La mauvaise version est « on l’a pined sur les CPU 0-7 en 2022 et on n’y est jamais revenu ».
Sur une machine hybride, la numérotation des CPUs peut intercaler les types de cœurs selon le BIOS/firmware/OS.
4) Turbo, thermiques et limites de puissance comptent plus que vous ne le souhaitez
Les designs hybrides sont souvent optimisés pour des charges client en rafales : pics sur les P-cores, tâches d’arrière-plan sur les E-cores, et un budget de puissance qui bouge dynamiquement.
En serveur, la charge soutenue est la norme, pas une surprise. Sous charge soutenue, les « cœurs rapides » peuvent ne pas rester aussi rapides,
et les « cœurs efficaces » peuvent devenir votre baseline en état stable.
5) Le goulot d’étranglement peut être la migration elle-même
Si les threads rebondissent entre classes de cœurs, vous payez en caches froids, en états de fréquence différents et en comptabilité de l’ordonnanceur.
Les migrations changent aussi les compteurs de performance et embrouillent le profiling naïf. Vous pensez mesurer l’appli. Vous mesurez les sautes d’humeur de l’ordonnanceur.
Blague #1 : Les CPU hybrides sont comme les open-spaces — quelqu’un pense toujours que c’est efficace, et quelqu’un d’autre porte toujours des casques à réduction de bruit.
Faits et contexte historique (la version courte et utile)
-
Big.LITTLE précède les PC d’aujourd’hui. Le concept big.LITTLE d’ARM est apparu au début des années 2010 pour mélanger cœurs haute-perf et basse-consommation
dans les SoC mobiles, parce que les téléphones vivent et meurent selon la batterie et les thermiques. -
L’ordonnancement hétérogène est antérieur aux cœurs hybrides. Les centres de données ont longtemps fait face à « tous les CPUs ne sont pas égaux » via
le NUMA, différents bins turbo et des stepping mixtes, mais l’hybride rend la différence explicite et par cœur. - Le pivot hybride d’Intel est arrivé avec Alder Lake. Cette génération a apporté des designs P-core + E-core aux desktops en volume, forçant les ordonnanceurs généraux à devenir sérieux.
-
Windows a rapidement bénéficié d’un mécanisme d’indices matériel. Intel Thread Director fournit des indications sur la « classe » et le comportement des threads,
que Windows utilise activement pour les décisions de placement sur les CPU supportés. -
Linux a suivi une voie plus générale. Plutôt que de s’appuyer sur l’interface d’un seul vendeur, Linux a construit un ordonnancement conscient de la capacité
et du type de cœur qui peut fonctionner sur des designs hétérogènes, mais la qualité dépend de la version du noyau et des détails de la plateforme. -
SMT/Hyper-Threading interagit avec l’hybride de façons non évidentes. Beaucoup de designs hybrides ont SMT sur les P-cores mais pas sur les E-cores.
Donc « 32 threads » peut signifier « 16 cœurs physiques, mais seulement la moitié avec SMT ». -
La numérotation des CPU n’est pas un contrat. Les identifiants CPU logiques peuvent mapper aux types de cœurs de manière variable selon le BIOS, le microcode et le noyau.
Les scripts qui supposent « CPU0..CPU7 sont les rapides » sont souvent à l’origine d’incidents. -
Les limites de puissance peuvent transformer un CPU hybride en un CPU différent. Sous contraintes PL1/PL2, la performance soutenue sur tous les cœurs peut s’aplatir,
réduisant l’écart P vs E pour les jobs de débit tout en gardant des différences nettes pour la latence. -
Les familles d’instances cloud ont déjà fait du « hétérogène » discrètement. Instances burstables, VMs à cœur partagé et comportement de voisin bruyant
ont entraîné de nombreuses équipes à rechercher des artefacts d’ordonnancement ; l’hybride rend ces artefacts possibles même sur du métal nu.
Réalité de l’ordonnanceur : Linux, Windows et le messy middle
Linux : capacité, asymétrie et taxe de version du noyau
Les ordonnanceurs Linux modernes peuvent comprendre que certains CPUs ont plus de « capacité » que d’autres. En pratique, vous vous souciez de :
la version du noyau, le microcode/firmware, et si la plateforme expose clairement la topologie.
Vous essayez de répondre à deux questions opérationnelles :
- L’ordonnanceur préfère-t-il placer les tâches à forte utilisation sur les cœurs à plus haute capacité ?
- Empêche-t-il que des tâches sensibles à la latence soient abandonnées sur des E-cores sous charge ?
La réponse est souvent « en grande partie, sauf si vous exécutez des conteneurs, pinnez des CPUs, utilisez un ancien noyau ou avez une charge que les heuristiques mal classifient ».
Ce n’est pas une plainte ; c’est la réalité. L’ordonnancement est des statistiques appliquées avec des bords tranchants.
Windows : comportement par défaut fort, mais pas magique
Windows sur les systèmes hybrides Intel supportés utilise les indices d’Intel Thread Director pour classifier les threads et les placer en conséquence.
Cela aide pour les charges interactives et mixtes de bureau. Pour des charges de type serveur, vous devez quand même valider.
Des tâches d’arrière-plan peuvent devenir des tâches de premier plan au pire moment. Votre job batch « basse priorité » peut être celui qui tient un lock.
Virtualisation et conteneurs : vous pouvez cacher les types de cœurs, mais pas la physique
Les hyperviseurs peuvent présenter des vCPU sans exposer « ceci est un P-core » à l’invité, selon la configuration.
Cela peut simplifier la compatibilité, mais empêcher l’OS invité de prendre de bonnes décisions de placement.
Les conteneurs sont pires d’une certaine manière : ils encouragent le pinning CPU (« donnez simplement 4 CPU à ce pod ») tout en abstractisant la topologie.
Si votre pinning atterrit sur des E-cores, félicitations pour votre « optimisation de coûts » qui ressemble à une régression.
Une idée paraphrasée de Gene Kim : le travail de fiabilité consiste à rendre les modes de défaillance visibles et récupérables, pas à prétendre qu’ils n’arriveront pas.
L’ordonnancement hybride ajoute de nouveaux modes de défaillance ; votre travail est de les rendre visibles.
Quels workloads préfèrent les P-cores, lesquels supportent les E-cores
Chemins de requête sensibles à la latence : P-cores par défaut
Si un thread impacte votre SLO, traitez-le comme une ressource de première classe. Handlers de requêtes web, workers RPC, threads foreground de base de données,
threads IO de broker de messages, démons de stockage sensibles à la latence de queue — ceux-ci doivent être sur les P-cores quand vous le pouvez.
Pourquoi ? Parce que la performance mono-thread et des fréquences stables comptent plus que le débit agrégé quand vous chassez le p99.
Les E-cores peuvent convenir pour la latence moyenne, puis vous surprendre sur la queue lorsque le système est chargé et la contention augmente.
Débit en arrière-plan : les E-cores sont excellents — jusqu’à un certain point
Compression de logs, scraping de métriques, ETL batch, transcodage vidéo, builds CI, indexation, antivirus (oui, toujours), et les tâches « faisons un rapport hebdomadaire à midi » vont bien sur les E-cores.
Le piège : le travail d’arrière-plan partage souvent des ressources et des verrous avec le travail de premier plan. C’est ainsi qu’un « workload E-core » devient un « incident P-core ».
Si votre tâche de fond détient un mutex nécessaire aux threads de requête, peu importe qu’elle soit « basse priorité ». C’est maintenant un amplificateur de latence.
Stockage et réseau : le goulot se déplace
Les stacks de stockage peuvent être liées au CPU (compression, checksums, chiffrement, erasure coding), liées à la mémoire (copie, page cache), ou IO-bound.
L’hybride affecte les parties liées au CPU et les parties « réveil, gérer l’interruption, faire un petit travail ».
Pour des taux de paquets élevés, du stockage petits-blocs ou beaucoup de TLS, vous voudrez souvent des P-cores pour le hot path et des E-cores pour le reste.
Le vrai gain est l’isolation : éloigner le travail bruyant du chemin déterministe.
Garbage collection et runtimes : ne les laissez pas choisir pour vous
JVM, Go, .NET, Node — les runtimes lancent des threads aides, threads GC, threads JIT. Si ceux-ci atterrissent sur des E-cores tandis que vos threads applicatifs sont sur des P-cores,
vous pouvez toujours avoir des pauses parce que les helpers sont lents. Si les threads applicatifs sont sur des E-cores, vous avez un temps de service lent.
Dans tous les cas, observez le placement des threads et ajustez.
Blague #2 : « Plus de cœurs » est un excellent plan jusqu’à ce que vous réalisiez que la moitié d’entre eux sont des stagiaires — enthousiastes, aidants, et pas la bonne personne pour faire une chirurgie.
Tâches pratiques : commandes, sorties et décisions (12+)
Ce sont les vérifications que j’exécute réellement quand un système hybride sent mauvais. Chaque tâche inclut : une commande, une sortie réaliste,
ce que signifie la sortie, et la décision que vous en tirez.
Tâche 1 : Identifier rapidement le CPU et la topologie hybride
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
Signification : 24 cœurs physiques, 32 CPUs logiques. Ce motif implique souvent du SMT sur certains cœurs (typiquement les P-cores) et pas sur d’autres (souvent les E-cores).
Décision : Ne supposez pas que « 32 threads » sont équivalents. Passez à la détection du type de cœur avant de pinner quoi que ce soit.
Tâche 2 : Mapper les CPUs logiques au type de cœur (P vs E) via 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
Signification : La capacité diffère selon le CPU. Une capacité plus élevée correspond typiquement aux P-cores ; une plus basse aux E-cores. (Les valeurs exactes varient.)
Décision : Construisez un ensemble CPU : CPUs P-core (capacity=1024) pour les workloads sensibles à la latence ; CPUs E-core pour les tâches batch/en arrière-plan.
Tâche 3 : Confirmer les différences de fréquence max par cœur
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.
Signification : Le CPU 0 a un plafond plus élevé que le CPU 8. Cela concorde avec le comportement P vs E.
Décision : Si la latence en queue importe, assurez-vous que le hot path est éligible pour tourner sur des cœurs avec des plafonds plus élevés.
Tâche 4 : Voir comment le noyau étiquette les CPU hybrides/hétérogènes
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
Signification : Le noyau détecte un CPU hybride et le scaling de capacité est activé.
Décision : Si vous ne voyez pas cela sur un hardware connu hybride, suspectez un problème de noyau/BIOS/microcode ; planifiez une mise à jour avant d’accuser l’appli.
Tâche 5 : Vérifier le gouverneur CPU actuel et décider s’il est approprié
cr0x@server:~$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
schedutil
Signification : Le gouverneur est schedutil (valeur par défaut courante). Il réagit aux signaux d’utilisation de l’ordonnanceur.
Décision : Pour des nœuds sensibles à la latence, envisagez performance (ou des profils tuned) si la montée en fréquence provoque des pics — après avoir mesuré la consommation/thermique.
Tâche 6 : Mesurer la pression de la run queue (manquons-nous 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
Signification : La colonne r flashe (run queue). C’est de la contention CPU. Cela ne vous dit pas si la contention est sur les P-cores ou sur les E-cores.
Décision : Si la run queue est élevée pendant les pics de latence, vérifiez si les P-cores sont saturés tandis que les E-cores sont au repos.
Tâche 7 : Surveiller l’utilisation par CPU pour détecter la saturation des 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
Signification : Les CPUs 0–1 sont chauds ; les CPUs 8–9 sont majoritairement inactifs. Si 0–7 sont des P-cores et 8+ des E-cores, vous avez probablement saturé les P-cores.
Décision : Réduisez la contention sur les P-cores : pinner les threads chauds sur les P-cores, pousser le travail d’arrière-plan vers les E-cores, ou diminuer la concurrence sur le chemin critique.
Tâche 8 : Inspecter où un processus est autorisé à tourner (cpuset/affinité)
cr0x@server:~$ pidof nginx
2143
cr0x@server:~$ taskset -pc 2143
pid 2143's current affinity list: 0-31
Signification : Nginx peut tourner n’importe où. C’est acceptable si l’ordonnanceur est intelligent ; c’est risqué si des tâches d’arrière-plan concurrencent sur les P-cores.
Décision : Si vous luttez contre la latence de queue, envisagez de donner à nginx (ou à vos workers de requêtes) une affinité P-core uniquement.
Tâche 9 : Pinner un service sensible à la latence sur les P-cores (exemple)
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
Signification : Le processus principal est contraint aux CPUs 0–7 (supposés P-cores d’après votre mapping de capacité).
Décision : Validez l’amélioration du p99 et assurez-vous de ne pas avoir affamé le service en lui donnant trop peu de CPUs.
Tâche 10 : Pousser les jobs d’arrière-plan vers les E-cores avec CPUAffinity 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
Signification : Le log shipper est enfermé sur les CPUs 8–31 (probablement E-cores + peut-être des SMT siblings selon la topologie).
Décision : C’est une des manœuvres les plus propres en production : protéger le hot path en isolant les voisins bruyants.
Tâche 11 : Vérifier le placement et les migrations par thread
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
Signification : PSR est le CPU sur lequel un thread a tourné en dernier. Si vous voyez des threads rebondir entre les plages CPU P et E, vous risquez de jitter.
Décision : Si les migrations se corrèlent avec des pics de latence, resserrez l’affinité ou réduisez les réveils inter-cœurs (thread pools, work stealing).
Tâche 12 : Identifier le throttling (le tueur silencieux de performance)
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
Signification : Température du package et watts élevés ; Bzy_MHz décroît avec le temps. C’est souvent un comportement thermique ou limite de puissance sous charge soutenue.
Décision : Si la perf se dégrade à mesure que le système chauffe, corrigez le refroidissement, les limites de puissance ou le flux d’air du châssis avant de réécrire le code.
Tâche 13 : Profiler les consommateurs CPU chauds (ne pas deviner)
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
Signification : Vous avez de véritables hotspots CPU. Les problèmes hybrides se présentent souvent comme « soudainement CPU-bound » parce que le thread a atterri sur un E-core ou a été throttlé.
Décision : Si le CPU est réellement le goulot, optimisez. Si le CPU n’est goulot que sur les E-cores, corrigez d’abord le placement.
Tâche 14 : Vérifier les quotas cgroup (les containers peuvent s’auto-saboter)
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
Signification : Quota CPU : 200ms par période de 100ms => effectivement l’équivalent de 2 CPUs, peu importe le nombre de cœurs existants.
Décision : Si les pics de latence coïncident avec du throttling, augmentez le quota ou retirez-le pour le hot path ; sinon vous courrez après des fantômes.
Tâche 15 : Kubernetes : vérifier la politique CPU Manager et les cœurs exclusifs
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"
Signification : Le gestionnaire CPU statique peut allouer des CPUs exclusifs aux pods Guaranteed. Des CPUs système sont réservés (ici 8–15).
Décision : Décidez quels CPUs sont « système » vs « workload ». Sur hybride, réservez les E-cores pour les daemons système quand possible, et attribuez les P-cores aux pods sensibles à la latence.
Tâche 16 : Vérifier l’allocation CPU réelle d’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
Signification : Pod Guaranteed avec request/limit égaux est éligible pour des CPUs exclusifs sous la politique static.
Décision : Confirmez que le cpuset assigné sur le nœud correspond aux P-cores. S’il atterrit sur des E-cores, ajustez topology manager / ensembles CPU réservés.
Playbook de diagnostic rapide
C’est la séquence « j’ai 15 minutes avant que la réunion d’incident ne devienne étrange ». L’objectif n’est pas une compréhension parfaite.
L’objectif est de trouver la classe de goulot : saturation des P-cores, mauvais placement sur E-cores, throttling, ou limites non-CPU.
Premier : décidez si le symptôme est latence, débit ou variance
- Pics de latence (p95/p99) : suspectez un mauvais placement, contention sur les P-cores, throttling ou amplification de locks.
- Baisse de débit : suspectez des limites thermiques/power, des quotas CPU, ou un job d’arrière-plan qui vole des cycles.
- Variance entre jobs identiques : suspectez des différences d’ordonnancement (P vs E), du pinning CPU, ou des voisins bruyants.
Deuxième : vérifiez si les P-cores sont saturés tandis que les E-cores sont inactifs
- Exécutez
mpstat -P ALL 1et cherchez « certains CPUs à fond, d’autres idle ». - Confirmez quels CPUs logiques sont P vs E avec
/sys/devices/system/cpu/*/cpu_capacity.
Si les P-cores sont à fond et les E-cores inactifs : vous avez probablement besoin de corrections de placement ou d’ajustement de la concurrence.
Si tout est à fond : vous êtes peut-être simplement CPU-bound (ou throttlé).
Troisième : vérifier le throttling et le comportement power/thermique
turbostatrésumé : surveillezPkgTmp,PkgWattet la baisse deBzy_MHz.- Recherchez des plafonds de fréquence plus bas que prévu avec
cpupower frequency-info.
Si la performance décline sur plusieurs minutes sous une charge stable : traitez cela comme un problème d’ingénierie refroidissement/puissance en priorité.
Le logiciel ne peut pas contourner une limite PL1 indéfiniment.
Quatrième : vérifier les quotas cgroup et le pinning
- Validez
cpu.max(cgroups v2) oucpu.cfs_quota_us(v1). - Vérifiez l’affinité avec
tasksetpour vos processus chauds.
Les quotas peuvent se faire passer pour de la « bizarrerie hybride ». Le pinning peut vous enfermer dans une « prison E-core ».
Cinquième : profiler brièvement le hot path
perf toppendant 30–60 secondes sur un processus représentatif.- Si vous voyez de la contention de locks ou des hotspots crypto/compression, décidez si le placement P-core ou des changements de code sont nécessaires.
Trois mini-histoires d’entreprise issues des tranchées des CPU hybrides
Mini-histoire 1 : Un incident causé par une fausse hypothèse
Une entreprise a migré une API sensible à la latence depuis d’anciens serveurs homogènes vers de beaux serveurs hybrides. Le déploiement avait l’air sûr :
l’utilisation CPU a baissé, la mémoire était OK, et le premier canari n’avait pas d’erreurs évidentes.
Puis la latence p99 a doublé pendant les pics en semaine. Pas p50. Pas p90. Juste la queue. Le budget d’erreurs a commencé à saigner de cette façon silencieuse qui ruine les tableurs.
L’équipe on-call a supposé que « plus de cœurs » signifiait « plus de marge ». Ils ont augmenté le nombre de workers et la concurrence. Cela a amélioré la moyenne et empiré la queue. Classique.
Ils nourrissaient l’ordonnanceur avec plus de threads runnables, et l’ordonnanceur plaçait certains d’entre eux sur des E-cores sous charge — surtout les threads qui se réveillaient plus tard et obtenaient le traitement « peu importe ce qui est libre ».
La correction fut ennuyeuse et précise : mapper les CPUs logiques P-core, pinner les workers de requêtes sur les P-cores, et cloisonner les services d’arrière-plan sur les E-cores.
Ils ont aussi réduit la sur-provision de workers pour éviter les explosions de run queue. Le p99 est revenu à la normale, et le %CPU a paru « pire » parce que maintenant les bons cœurs travaillaient.
La vraie leçon : si votre modèle de performance est « un cœur est un cœur », l’hybride vous punira. Il ne le fait pas par malveillance. Il le fait de façon consistante.
Mini-histoire 2 : Une optimisation qui a mal tourné
Une autre équipe exécutait un nœud à charge mixte : une base de données, un agent de métriques, un forwarder de logs et un indexeur en arrière-plan.
Ils ont remarqué que la base de données atteignait parfois la contention CPU et ont décidé « d’optimiser » en pinner la base de données sur un ensemble fixe de CPUs.
La demande de changement était propre. Le graphe en staging était vert. L’ingénieur est rentré tôt.
En production, la latence des requêtes s’est dégradée lentement sur la semaine suivante. Pas un effondrement. Une pente. La base de données était pined sur les CPUs 0–11.
Sur cette configuration BIOS particulière, les CPUs 0–7 étaient des P-cores (super), et les CPUs 8–11 étaient des E-cores (moins bien).
Sous charge de lecture intense, les threads foreground de la BD restaient surtout sur les P-cores, mais certains threads background critiques étaient coincés à concourir sur la partie E-core du groupe pined : checkpointers, compaction, et quelques workers de maintenance.
Ils ont créé involontairement un monde CPU en split-brain : certaines parties de la BD tournaient vite ; d’autres tournaient lentement ; les lentes détenaient parfois des locks et retardait les rapides.
L’application l’a perçu comme du jitter aléatoire.
Le rollback a corrigé le problème. L’amélioration finale fut plus nuancée : pinner les workers foreground de la BD sur les P-cores, pinner les agents bruyants sur les E-cores,
et laisser une certaine flexibilité pour que les threads background de la BD utilisent le temps P-core disponible pendant les fenêtres de maintenance. Ils ont aussi ajouté une alerte sur la profondeur de run queue des P-cores
(pas seulement le % total CPU).
La leçon : le pinning est un scalpels. Si vous l’utilisez comme un marteau, il finira par toucher l’os.
Mini-histoire 3 : Une pratique ennuyeuse mais correcte qui a sauvé la mise
Une équipe stockage gérait une flotte de serveurs de build et de caches d’artefacts. Leur workload était en rafales : forte compression et hashing pendant les builds,
puis principalement inactif. Ils ont adopté des CPU hybrides pour des raisons de coût et d’énergie, mais ils ont fait quelque chose d’impopulaire : ils ont validé la topologie et l’ont documentée.
Pour chaque SKU hardware, ils ont enregistré : quels CPUs logiques correspondent à quel type de cœur, les fréquences soutenues typiques sous charge, et le comportement thermique
à l’intérieur du rack. Ils ont aussi maintenu une petite baseline noyau « connue bonne » et n’ont pas laissé les nœuds dériver au hasard.
C’était le genre de travail dont personne ne fait des louanges parce que ça ressemble à de la paperasse.
Quelques mois plus tard, une mise à jour firmware du vendeur a changé l’énumération CPU sur un sous-ensemble de nœuds. Soudain certains agents de build se sont retrouvés pined sur les mauvais CPUs et les builds ont ralenti.
Parce qu’ils avaient un job de validation de topologie dans le CI pour l’image (et un simple check au démarrage), les nœuds se sont marqués « topologie changée »
et ont été vidés automatiquement. Pas d’incident. Juste un ticket et une correction tranquille.
La leçon : les CPU hybrides récompensent l’hygiène opérationnelle. Si vous traitez la topologie comme des données et la validez, vous transformez la « performance mystérieuse » en changement contrôlé.
Erreurs courantes : symptôme → cause racine → correctif
1) Symptom : pics de latence p99 avec « faible % CPU global »
Cause racine : P-cores saturés tandis que les E-cores sont inactifs ; l’ordonnanceur place mal les threads chauds sous charge.
Correctif : Mapper les CPUs P-core (capacity/frequency), pinner les threads critiques pour la latence sur les P-cores, cloisonner les daemons d’arrière-plan sur les E-cores, et réduire l’explosion de threads runnables.
2) Symptom : jobs batch identiques varient énormément en durée
Cause racine : Certains jobs s’exécutent surtout sur des P-cores, d’autres sur des E-cores ; ou des quotas cgroup provoquent un throttling inégal.
Correctif : Pour des batchs orientés débit, acceptez la variance ou planifiez-les explicitement (affinité) sur les E-cores. Si vous avez besoin d’équité, normalisez en pinner sur la même classe de cœurs.
3) Symptom : « Nous avons monté CPU, mais les builds sont plus lents après 10 minutes »
Cause racine : Throttling thermique/power sous charge soutenue ; les attentes turbo étaient basées sur des benchmarks courts.
Correctif : Utilisez turbostat sous charge proche de la production, ajustez refroidissement/limites de puissance, et benchmarquez la performance soutenue — pas seulement les rafales.
4) Symptom : pods Kubernetes Guaranteed ont toujours du jitter
Cause racine : CPUs exclusifs alloués, mais de la mauvaise classe (E-cores) ou partagés avec des CPUs système chargés d’interruptions.
Correctif : Utilisez CPU manager + topology manager intentionnellement. Réservez les E-cores pour les tâches système quand possible ; attribuez les P-cores aux pods latence ; gardez le travail IRQ-intensive hors du cpuset chaud.
5) Symptom : le pinning « améliore la latence moyenne mais empire la queue »
Cause racine : Vous avez pined les threads foreground mais laissé des threads background qui tiennent des locks sur des E-cores, créant un plan de contrôle lent pour un plan de données rapide.
Correctif : Identifiez les threads background critiques (maintenance DB, helpers GC), assurez-vous qu’ils puissent tourner sur des P-cores pendant les pics, ou isolez-les dans des slices P-core dédiés.
6) Symptom : les profils perf ne correspondent pas à la réalité
Cause racine : Les threads migrent entre classes de cœurs ; l’échantillonnage rencontre un comportement CPU différent de celui qui cause la latence visible.
Correctif : Réduisez les migrations (affinité), profilez avec un placement stable, et corrélez les fenêtres de profiling avec les métriques de scheduling et de throttling.
7) Symptom : « CPU est saturé » mais seuls certains cœurs sont chauds
Cause racine : Goulot mono-thread ou contention de lock s’exécutant sur des P-cores ; les E-cores ne peuvent pas aider parce que le goulot est sérialisé.
Correctif : Réduisez la sérialisation (contention de locks), améliorez le parallélisme, ou augmentez le nombre de P-cores par instance. Ne balancez pas des E-cores sur un mutex.
Listes de contrôle / plan étape par étape
Étape par étape : adopter les CPU hybrides sans casser la latence
-
Inventoriez la topologie dès le premier jour. Enregistrez les IDs CPU P-core vs E-core en utilisant les vérifications capacity/frequency.
Traitez cela comme de la configuration, pas du savoir tribal. - Décidez quels workloads obtiennent les P-cores. Tout ce qui est sur le chemin de requête, les threads foreground de BD et les threads IO critiques par défaut.
- Cloisonnez les services d’arrière-plan. Log shippers, agents de métriques, indexeurs, scanners, helpers de build — poussez-les vers les E-cores.
- Validez la performance soutenue. Exécutez un test de charge de 30–60 minutes et surveillez fréquence/température. L’hybride est sensible aux limites de puissance.
- Tuez les dashboards trompeurs. Ajoutez des métriques par cœur ou par classe de cœur : utilisation P-core, utilisation E-core, taux de migrations, taux de throttling.
- Rendez le pinning explicite et revu. Si vous utilisez l’affinité, encodez-la dans les unités systemd ou les configs de l’orchestrateur, et révisez-la lors des changements de noyau/firmware.
- Répétez les modes de défaillance. Que se passe-t-il quand les P-cores saturent ? Dégradez-vous gracieusement, réduisez la concurrence, ou sheddez la charge ?
Checklist opérationnelle : avant d’accuser l’application
- Confirmer que le noyau voit la topologie hybride (dmesg).
- Confirmer le mapping P/E (cpu_capacity ou plafonds de fréquence).
- Vérifier saturation P-core vs inactivité E-core (mpstat).
- Vérifier le throttling (turbostat).
- Vérifier les quotas cgroup (cpu.max).
- Vérifier les affinités (taskset, CPUAffinity systemd, CPU manager kube).
- Ce n’est qu’ensuite que vous profilez le code (perf).
Suggestion de politique : une stratégie CPU par défaut raisonnable
- Tier latence : P-cores uniquement, travail d’arrière-plan minimal, fréquences stables (dans la limite de votre budget d’énergie).
- Tier débit : E-cores préférés, permettre un débordement sur les P-cores hors pics si cela n’affecte pas les SLOs de latence.
- Tier système : Réservez un petit cpuset pour l’OS et les daemons ; de préférence des E-cores si vous en avez assez, mais gardez à l’esprit le comportement IRQ/softirq.
FAQ
1) Les E-cores sont-ils des « cœurs lents » ?
Ils ont une performance mono-thread généralement plus faible comparée aux P-cores. Mais ils peuvent offrir un excellent débit par watt, surtout pour les workloads parallèles.
L’erreur est de supposer « un cœur est un cœur » quand vous faites des calculs de latence.
2) Dois-je désactiver les E-cores dans le BIOS pour des serveurs ?
Parfois, oui — si votre workload est purement sensible à la latence, votre stack logiciel ne peut pas gérer l’hétérogénéité, ou vous avez besoin d’un comportement déterministe rapidement.
Mais c’est un outil brutal. Essayez d’abord l’isolation et le placement ; désactiver les E-cores gaspille de la capacité de débit utile.
3) Pourquoi l’« utilisation CPU » semble correcte alors que la performance est mauvaise ?
Parce que la seule capacité dont vous avez réellement besoin peut être celle des P-cores. Si les P-cores sont saturés et les E-cores inactifs, le % CPU moyen vous mentira.
Mesurez par classe de cœur, pas le total.
4) Le pinning aide-t-il toujours sur les CPU hybrides ?
Non. Le pinning aide quand il empêche les interférences et garantit que le hot path tourne sur les bons cœurs.
Il nuit quand vous pinner sur les mauvais CPUs, affamez des threads helpers critiques, ou empêchez l’ordonnanceur de s’adapter à la charge changeante.
5) Comment trouver quels CPUs logiques sont des P-cores ?
Sur Linux, l’approche la plus pratique est de comparer cpu_capacity (si présent) et les plafonds de fréquence par CPU via cpupower.
Ne vous fiez pas aux patterns de numérotation sans les vérifier sur cet hôte.
6) Les E-cores affectent-ils la performance du stockage ?
Ils peuvent. Les stacks de stockage ont souvent des composants gourmands en CPU (compression, checksums, chiffrement) et du travail piloté par interruption.
Si vos threads de complétion IO atterrissent sur des E-cores, vous pouvez voir une latence accrue même si les disques vont bien.
7) SMT (Hyper-Threading) est-il bon ou mauvais dans les systèmes hybrides ?
Cela dépend du workload. SMT peut augmenter le débit mais ajouter de la contention et du jitter pour les workloads sensibles à la latence.
L’hybride complique cela parce que le SMT peut n’exister que sur les P-cores, changeant la signification de « N CPUs » dans les pinning et quotas.
8) Comment benchmarker des CPU hybrides ?
Benchmarquez avec une concurrence proche de la production, une durée soutenue (pour capturer le throttling), et des mesures séparées pour :
P-core-only, E-core-only, et scheduling mixte. Si vous ne faites que des tests synthétiques courts, vous surestimerez la performance réelle.
9) Ai-je besoin de réglages Kubernetes spéciaux pour les CPU hybrides ?
Si vous exécutez des pods sensibles à la latence, oui : politique CPU manager static, ensembles CPU réservés soigneusement, et validation que les CPUs exclusifs mappent aux P-cores.
Sinon vous pourriez être « Guaranteed » sur le papier et « E-cored » en réalité.
Conclusion : prochaines étapes pratiques
Les CPU hybrides ne sont pas une astuce. Ce sont un compromis honnête : plus de débit par watt et par surface de die, au prix de l’hétérogénéité.
En production, l’hétérogénéité signifie que vous devez être explicite sur le placement et la mesure.
- Mesurez les classes de cœurs (capacity/frequency) et conservez le mapping dans le contrôle de version pour chaque SKU hardware.
- Protégez le hot path : pinner ou contraindre les services critiques en latence aux P-cores ; cloisonner les services d’arrière-plan sur les E-cores.
- Surveillez le throttling sous charge soutenue ; corrigez puissance/refroidissement avant d’optimiser le code.
- Arrêtez de faire confiance au % CPU total ; instrumentez séparément la saturation des P-cores et alertez dessus.
- Revoyez le pinning régulièrement après les changements BIOS, firmware et noyau — la topologie n’est pas immuable.
Faites ces choses et les CPU hybrides deviennent prévisibles. Ignorez-les et vous aurez du whack-a-mole de performance avec de plus jolies fiches techniques.