Thread Director : pourquoi le CPU conseille désormais le système d’exploitation

Cet article vous a aidé ?

Rien ne ressemble autant à « l’informatique moderne » qu’une station de travail 64 cœurs qui saccade quand on lance un appel vidéo, ou un serveur de build qui prend aléatoirement deux fois plus de temps le mardi. Vous regardez la charge moyenne : tout va bien. Vous regardez l’utilisation CPU : tout va bien. Et pourtant la latence tail explose, l’audio crépite, ou la base de données décide que le 99e percentile est un choix de vie.

Si vous exécutez sur des CPU hybrides (cœurs rapides + cœurs efficaces), un changement discret est au centre de beaucoup de plaintes « c’était prévisible avant » : le CPU conseille désormais activement le système d’exploitation sur l’endroit où vos threads devraient s’exécuter. Bienvenue dans le domaine de Thread Director — où l’ordonnancement cesse d’être uniquement un problème de politique OS et devient une négociation CPU + OS.

Ce qui a changé : de l’ordonnancement OS à l’intention fournie par le CPU

Pendant des décennies, nous avons considéré l’ordonnancement CPU comme un problème du système d’exploitation. Le noyau voyait les threads exécutables, mesurait combien de temps ils tournaient, appliquait des heuristiques d’équité et les plaçait sur des cœurs selon la topologie et la politique. Le matériel restait généralement dans son rôle : exécuter des instructions, générer des interruptions et exposer des compteurs.

Les architectures CPU hybrides ont rompu cette séparation nette. Quand tous les cœurs ne sont pas égaux, « un CPU est un CPU » devient un mensonge que l’ordonnanceur ne peut plus se permettre. Vous pouvez toujours ordonnancer de façon équitable, mais vous le ferez à prix élevé — gaspillant de l’énergie sur des P-cores pour du travail en arrière-plan, ou privant de travail sensible à la latence sur des E-cores. Le résultat ressemble à une « variance de performance aléatoire », parce que c’en est une.

Thread Director (nom d’Intel ; le concept est plus large) est le CPU admettant l’évidence : il a une meilleure visibilité en temps réel sur ce qu’un thread fait à cet instant. Pas « ce thread a utilisé 70 % du CPU sur 10 ms », mais « ce thread exécute principalement des instructions retraites, provoque beaucoup de défauts de cache, est riche en branches, vectorisé, bloqué ou se réveille fréquemment ». Le CPU peut classifier ce comportement en continu et envoyer des recommandations — des indices, pas des ordres — à l’ordonnanceur de l’OS.

C’est le changement idéologique : l’ordonnancement n’est plus seulement un moteur de politiques opérant sur des métriques grossières. C’est une politique plus de la télémétrie quasi temps réel fournie par le silicium.

Une citation à garder pour vos revues de conception, attribuée à Werner Vogels : « Everything fails, all the time. » Si vous ne basez pas vos hypothèses d’ordonnancement sur ce principe, vous basez vos choix sur l’espoir.

Les CPU hybrides en clair (et pourquoi votre modèle mental est obsolète)

Hybride signifie au moins deux classes de cœurs :

  • Cœurs de performance (P-cores) : performances mono‑thread supérieures, plafonds de fréquence généralement plus élevés, plus grosse machine out‑of‑order, consommation d’énergie plus importante.
  • Cœurs d’efficacité (E-cores) : plus petits, faible consommation, souvent excellents en débit par watt, mais pic de performance mono‑thread plus bas et parfois traits microarchitecturaux différents.

Le concept d’hybride n’est pas nouveau. Les SoC mobiles utilisent le big.LITTLE depuis des années. Ce qui est nouveau, c’est que l’hybride apparaît massivement sur postes de travail, ordinateurs portables et même dans certains flux serveur où l’on supposait « je peux épingler et oublier ». Cette hypothèse devient désormais un ticket d’incident récurrent.

L’ordonnanceur doit décider : quels threads méritent des P-cores, lesquels peuvent vivre sur des E-cores, et quand les migrer. La migration a un coût : chaleur du cache, état du prédicteur de branches, et parfois comportement de fréquence. Mais laisser un thread « dans le mauvais quartier » a aussi un coût : latence, débit ou autonomie.

Voici où ça se complique en production :

  • La plupart des applications ne déclarent pas d’intention. Elles ne disent pas au système « ceci est un thread sensible à la latence », ou « ceci est un travail en arrière-plan », ou « ceci est un job limité par la bande passante mémoire qui ne bénéficie pas des P-cores ».
  • Les ordonnanceurs infèrent l’intention depuis le comportement. Le comportement change rapidement : un thread worker HTTP peut être inactif, puis parser TLS, puis toucher la base de données, puis compresser une réponse.
  • Le matériel voit le comportement plus tôt et avec une granularité plus fine que l’OS.

Thread Director existe parce que l’OS était prié de prendre des décisions rapides avec des lunettes floues.

Petite blague n°1 : Épingler des threads sur des CPU hybrides, c’est comme réserver une table au restaurant sans vérifier quelle salle contient la cuisine.

Ce que fait réellement Thread Director

À haut niveau, Thread Director est un système de télémétrie et de classification hardware qui :

  1. Observe le comportement par thread via des compteurs de performance et des signaux microarchitecturaux.
  2. Classe les threads en catégories liées à « combien ils gagnent à aller sur des P-cores » et « à quel point ils sont sensibles à la latence ».
  3. Communique ces classifications à l’ordonnanceur OS via une interface définie.
  4. Permet à l’OS de placer les threads sur des cœurs appropriés avec une précision meilleure que l’heuristique seule.

Ce que ce n’est pas

  • Ce n’est pas un interrupteur magique « tout accélère ». Si votre charge est limitée par la mémoire, le P-core pourrait simplement attendre plus vite.
  • Ce n’est pas un remplacement de la planification de capacité. Si vous saturiez la machine, vous la saturerez toujours — juste avec des décisions plus coûteuses.
  • Ce n’est pas une excuse pour arrêter de mesurer. C’est une raison pour mesurer différemment.

L’impact opérationnel réel

L’impact majeur est la variance. L’hybride sans bon ordonnancement produit une variance désagréable : latences incohérentes, temps de build irréguliers, temps de requête fluctuants. Thread Director vise à réduire cela en améliorant les décisions de placement face à l’évolution du comportement des threads.

Mais il change aussi l’endroit où vous déboguez. « L’ordonnanceur OS est stupide » devient « l’ordonnanceur OS suit des indices hardware qui peuvent être mal appliqués à ma charge, mes réglages d’énergie, ma couche de virtualisation ou ma stratégie d’épinglage ». Le graphe des responsabilités s’élargit. Vos runbooks doivent suivre.

Faits & historique : comment en sommes-nous arrivés là

Quelques points de contexte concrets qui expliquent pourquoi nous en sommes là et pourquoi ça ne disparaîtra pas :

  1. Les cœurs asymétriques ne sont pas nouveaux sur mobile. Les architectures de type big.LITTLE ont normalisé « des cœurs différents pour des tâches différentes » bien avant que les desktops ne s’en préoccupent.
  2. La mise à l’échelle de fréquence est devenue la norme. Le DVFS a transformé la « vitesse CPU » en une cible mobile, et l’ordonnancement a dû en tenir compte.
  3. Le comportement Turbo a rendu la performance par cœur non uniforme. Même des cœurs « identiques » ne se comportent pas de la même façon quand les limites de puissance/thermiques interviennent.
  4. Le SMT a compliqué la signification d’un cœur. L’Hyper-Threading (et équivalents) a créé des CPU logiques partageant des ressources d’exécution, rendant les décisions de placement plus importantes.
  5. Le NUMA nous a déjà appris que la topologie compte. Les serveurs ont vécu avec « tous les CPU ne sont pas égaux » pour la localité mémoire ; l’hybride apporte ce raisonnement aux machines grand public.
  6. Les atténuations de sécurité ont changé les profils de performance. Les mitigations de spéculation ont rendu certains patterns riches en syscalls plus coûteux, influençant quels cœurs sont « meilleurs » pour quels threads.
  7. L’énergie est devenue une contrainte première. Les budgets d’énergie pour laptops et datacenters ont transformé « le plus rapide » en « assez rapide par watt ».
  8. Les ordonnanceurs opèrent historiquement sur des tranches de temps grossières. L’OS voit des états exécutables et des ticks de comptabilité ; le CPU voit des stalls et le mix d’instructions à chaque instant.
  9. La virtualisation et les conteneurs ont caché la topologie aux applications. Une fois que vous empilez hyperviseurs, cgroups et pinning, la vue de l’ordonnanceur peut être déformée à moins d’une configuration soigneuse.

Modes de défaillance que vous verrez en production

Thread Director répond à de vrais problèmes, mais il introduit un nouvel ensemble de modes de défaillance — principalement causés par des humains avec des opinions tranchées et des mesures faibles.

1) Pics de latence corrélés à du travail « en arrière-plan »

Exemple classique : votre service est majoritairement inactif, puis une tâche de sauvegarde ou de compression de logs démarre. Soudain la latence tail augmente. Sur du hardware hybride, cela peut arriver quand l’ordonnanceur malclasse des rafales ou quand vos threads sensibles à la latence se retrouvent entassés sur des E-cores pendant que des P-cores sont occupés par du travail de débit.

Thread Director peut aider, mais seulement si l’OS l’utilise efficacement et que vos politiques ne lui font pas obstacle.

2) Incidents « l’épinglage a empiré les choses »

L’épinglage est tentant : « je vais simplement mettre la base de données sur les cœurs rapides ». Mais épingler sur un CPU hybride verrouille souvent le système dans un arrangement sous-optimal dès que la charge change. Vous pouvez aussi épingler accidentellement des threads critiques sur des E-cores — parce que votre hypothèse « CPU 0-7 » venait d’un autre SKU.

3) La politique d’énergie sabote l’ordonnancement

Les plans Windows « Balanced » vs « High performance », les governors Linux, les réglages BIOS et les démons fournis par les vendeurs peuvent tous pencher le terrain. L’ordonnanceur peut être brillant et pourtant perdre si la plateforme bride le boost des P-cores ou met les cœurs en parking agressif.

4) La virtualisation masque la nature hybride

Dans une VM, l’OS invité peut ne pas voir les vraies classes de cœurs. Votre hyperviseur peut planifier des vCPU sur des E-cores en période de contention. Vous debuggez alors une latence applicative qui est en réalité un « vCPU posé sur le mauvais silicium ».

5) Lacunes d’observabilité : vous ne voyez pas ce que le CPU « a conseillé »

Beaucoup d’équipes ont des dashboards pour l’utilisation CPU, la charge et la file d’exécution. Moins savent répondre : « Quels threads sont placés sur des E-cores, et pourquoi ? » Quand vous ne pouvez pas voir la classification ou les motifs de placement, vos réglages deviennent de la superstition.

Playbook de diagnostic rapide

Ceci est l’ordre qui fait gagner du temps quand quelqu’un vous signale « une machine CPU hybride est lente et étrange ». Ne soyez pas créatif en premier lieu. Collectez d’abord des preuves.

Première étape : confirmer la topologie et si l’OS la voit correctement

  • Identifier les types de cœurs, le statut SMT et la numérotation CPU.
  • Vérifier si la charge est confinée accidentellement (cgroups, cpuset, limites de conteneur, taskset).
  • Vérifier si l’ordonnanceur de l’OS supporte la conscience hybride (version du noyau, build OS).

Deuxième étape : décider s’il s’agit d’un problème de saturation CPU ou d’un problème d’ordonnancement/placement

  • Regarder la pression de la file d’exécution, les changements de contexte, les migrations et l’utilisation par CPU.
  • Chercher des motifs « certains CPU saturés, d’autres inactifs » qui crient affinité / contraintes cpuset.
  • Vérifier le comportement de fréquence : les P-cores boostent-ils ? les E-cores font-ils le gros du travail ?

Troisième étape : isoler le symptôme à une classe de threads

  • Identifier les principaux coupables par temps CPU et par réveils.
  • Vérifier si les threads sensibles à la latence atterrissent sur des E-cores pendant les pics.
  • Si vous êtes dans des conteneurs/VM, valider la planification hôte et le pinning avant de toucher aux flags applicatifs.

Puis : changer une chose à la fois

  • Retirer l’épinglage manuel avant d’ajouter plus d’épinglage.
  • Préférer les mécanismes QoS / priorité supportés par l’OS plutôt que l’affinité stricte, sauf si vous avez une raison mesurée.
  • Si vous devez épingler, épinglez par type de cœur intentionnellement, pas par « numéros CPU trouvés sur un blog ».

Tâches pratiques : commandes, sorties, et la décision à prendre

L’objectif de ces tâches n’est pas de mémoriser des commandes. C’est de construire un workflow qui sépare « le CPU est occupé » de « le CPU est mal placé ». Chaque tâche inclut : une commande, un exemple du type de sortie que vous verrez, ce que cela signifie, et ce que vous faites ensuite.

Task 1: Confirm hybrid topology and CPU numbering

cr0x@server:~$ lscpu -e=CPU,CORE,SOCKET,NODE,ONLINE,MAXMHZ,MINMHZ
CPU CORE SOCKET NODE ONLINE MAXMHZ MINMHZ
0   0    0      0    yes    5200.0  800.0
1   0    0      0    yes    5200.0  800.0
2   1    0      0    yes    5200.0  800.0
3   1    0      0    yes    5200.0  800.0
8   8    0      0    yes    3800.0  800.0
9   8    0      0    yes    3800.0  800.0
10  9    0      0    yes    3800.0  800.0
11  9    0      0    yes    3800.0  800.0

Ce que cela signifie : Vous cherchez des groupes de CPUs avec des plafonds MAXMHZ différents ; c’est souvent un indice fort des P-cores vs E-cores (pas parfait, mais utile). La numérotation CPU peut ne pas être groupée proprement.

Décision : Construisez une carte explicite du « groupe rapide » vs « groupe lent » pour cet hôte ; n’assumez pas que CPU0..N sont les P-cores.

Task 2: Inspect cache and topology details

cr0x@server:~$ lscpu | sed -n '1,30p'
Architecture:            x86_64
CPU(s):                  24
Thread(s) per core:      2
Core(s) per socket:      16
Socket(s):               1
L1d cache:               512 KiB (16 instances)
L1i cache:               512 KiB (16 instances)
L2 cache:                20 MiB (10 instances)
L3 cache:                30 MiB (1 instance)
NUMA node(s):            1

Ce que cela signifie : Les caches partagés comptent pour les coûts de migration. Si des E-cores partagent un cluster L2, déplacer un thread dans/ hors de ce cluster peut changer la performance.

Décision : Si votre charge est sensible au cache, évitez un churn d’affinité agressif. Préférez un placement stable et moins de migrations.

Task 3: Check kernel and scheduler baseline

cr0x@server:~$ uname -r
6.5.0-21-generic

Ce que cela signifie : Le support d’ordonnancement hybride dépend fortement de la génération du noyau et des backports fournisseurs.

Décision : Si vous êtes sur un noyau ancien et que vous traquez des bizarreries hybrides, mettre à niveau n’est pas « un plus ». C’est la première tentative de correctif réelle.

Task 4: Verify CPU frequency governor and policy

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

Ce que cela signifie : schedutil couple les décisions de fréquence aux signaux d’utilisation de l’ordonnanceur. D’autres governors peuvent être plus agressifs ou plus conservateurs.

Décision : Si vous voyez powersave sur une machine sensible à la latence, corrigez la politique avant de toucher au tuning applicatif.

Task 5: Observe actual frequencies under load (turbostat)

cr0x@server:~$ sudo turbostat --Summary --quiet --interval 1 --num_iterations 3
Avg_MHz  Busy%  Bzy_MHz  TSC_MHz  PkgTmp  PkgWatt
  812     6.12    4172    3000      52     12.40
 1190    18.55    4388    3000      58     21.10
  945     9.80    4021    3000      55     14.80

Ce que cela signifie : Bzy_MHz est la fréquence effective en charge. Si elle ne monte jamais, vous pourriez être limité par la puissance, la thermique ou une mauvaise configuration BIOS.

Décision : Si le boost est bridé, cessez de blâmer l’ordonnancement tant que vous n’avez pas corrigé les contraintes de la plateforme.

Task 6: Identify per-CPU imbalance (some cores pegged, others idle)

cr0x@server:~$ mpstat -P ALL 1 2
Linux 6.5.0-21-generic (server)  01/10/2026  _x86_64_  (24 CPU)

12:00:01 AM  CPU   %usr %nice %sys %iowait %irq %soft %steal %idle
12:00:02 AM  all   38.1  0.0   4.2  0.1     0.0  0.3   0.0    57.3
12:00:02 AM    0   92.0  0.0   3.0  0.0     0.0  0.0   0.0     5.0
12:00:02 AM    8    6.0  0.0   1.0  0.0     0.0  0.0   0.0    93.0

Ce que cela signifie : CPU0 est surchauffé tandis que CPU8 est presque endormi. C’est soit une affinité, des contraintes cpuset, soit un goulot mono‑thread.

Décision : Si vous attendiez du parallélisme, inspectez l’affinité et les cpusets avant de modifier le code.

Task 7: Check run queue pressure and context switching

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
 1  0      0 521312  64288 882112    0    0     1     3  812 1200 12  3 85  0
 8  0      0 519040  64288 881920    0    0     0     0 1050 9800 62  6 32  0

Ce que cela signifie : r passant à 8 signifie beaucoup de threads exécutables. cs qui augmente vite suggère des changements de contexte intensifs ; sur hybride, cela signifie souvent des migrations et de la contention.

Décision : Si les threads exécutables dépassent la capacité CPU effective disponible, arrêtez de chasser le « placement » et commencez à chercher saturation ou contention de verrous.

Task 8: See scheduler migrations and balance behavior (perf sched)

cr0x@server:~$ sudo perf sched record -- sleep 5
[ perf sched record: Woken up 7 times to write data ]
[ perf sched record: Captured and wrote 2.113 MB perf.data (23619 samples) ]
cr0x@server:~$ sudo perf sched latency --sort=max | sed -n '1,12p'
    Task                  |   Runtime ms  | Switches | Avg delay ms | Max delay ms
  nginx:worker-01         |      310.422  |     2381 |       0.122  |       7.843
  backup:compress         |      882.001  |     1140 |       0.410  |      21.554

Ce que cela signifie : Un délai maximal élevé pour des threads sensibles à la latence indique des retards d’ordonnancement (attentes dans la file d’exécution). Si les mauvais délais coïncident avec des tâches de débit, vous avez des problèmes de priorisation et de placement.

Décision : Envisagez des ajustements de priorité/QoS ou isolez les tâches de fond bruyantes sur des E-cores plutôt que d’épingler tout ce qui est « important » sur des P-cores.

Task 9: Check current process/thread affinity

cr0x@server:~$ pidof nginx
2140
cr0x@server:~$ taskset -cp 2140
pid 2140's current affinity list: 0-7

Ce que cela signifie : Nginx est confiné aux CPUs 0-7. Si 0-7 ne sont pas tous des P-cores sur ce système, vous l’avez peut‑être accidentellement placé sur un ensemble mixte ou lent.

Décision : Retirez l’affinité globale sauf si vous pouvez prouver que cela aide. Si vous devez contraindre, le faites en connaissance de cause des classes de cœurs.

Task 10: Inspect cgroup CPU constraints (common in containers)

cr0x@server:~$ cat /sys/fs/cgroup/cpuset.cpus.effective
0-11
cr0x@server:~$ cat /sys/fs/cgroup/cpu.max
80000 100000

Ce que cela signifie : cpu.max suggère un quota (80% d’un CPU dans cet exemple fois la période), et les cpusets limitent les CPUs disponibles. L’hybride rend le concept de « CPU effectif » délicat : 4 E-cores ne valent pas 4 P-cores pour la latence.

Décision : Pour des SLOs de latence, préférez épingler les workloads sur des P-cores connus via des cpusets plutôt que de compter uniquement sur des quotas.

Task 11: Check IRQ distribution (interrupts can steal your best cores)

cr0x@server:~$ cat /proc/interrupts | sed -n '1,8p'
           CPU0       CPU1       CPU2       CPU3
  24:    812340          0          0          0  IR-PCI-MSI 524288-edge  eth0-TxRx-0
  25:         0     792110          0          0  IR-PCI-MSI 524289-edge  eth0-TxRx-1

Ce que cela signifie : Si toutes les interruptions à haut débit atterrissent sur CPU0 et que CPU0 est un P-core, vous gaspillez peut‑être votre meilleur cœur sur du travail IRQ.

Décision : Envisagez d’ajuster l’affinité IRQ afin que les threads applicatifs sensibles à la latence obtiennent des P-cores propres.

Task 12: Observe per-thread wakeups and CPU placement (top + ps)

cr0x@server:~$ top -H -p 2140 -b -n 1 | sed -n '1,20p'
top - 00:00:10 up 10 days,  2:14,  1 user,  load average: 3.12, 2.98, 2.70
Threads:  18 total,   2 running,  16 sleeping,   0 stopped,   0 zombie
%Cpu(s):  35.0 us,  4.0 sy,  0.0 ni, 61.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   2145 www-data  20   0  125352  11420   5120 R  62.3   0.2   1:22.10 nginx: worker
   2146 www-data  20   0  125352  11420   5120 R  58.9   0.2   1:18.44 nginx: worker
cr0x@server:~$ ps -L -o pid,tid,psr,cls,rtprio,pri,ni,comm -p 2140 | sed -n '1,8p'
  PID   TID PSR CLS RTPRIO PRI  NI COMMAND
 2140  2140   0  TS      -  19   0 nginx
 2140  2145   2  TS      -  19   0 nginx
 2140  2146   3  TS      -  19   0 nginx

Ce que cela signifie : PSR montre sur quel CPU le thread a été exécuté pour la dernière fois. Si vos workers sautent entre P- et E-cores rapidement pendant les pics de latence, vous le verrez ici au fil du temps.

Décision : Si les sauts corrèlent avec une mauvaise latence tail, visez un placement stable : corrigez les workloads concurrents, ajustez les priorités, ou utilisez des cpusets ciblés.

Task 13: Check whether the process is being throttled (cgroup CPU stats)

cr0x@server:~$ cat /sys/fs/cgroup/cpu.stat
usage_usec 823412341
user_usec  792112000
system_usec 31200341
nr_periods  12490
nr_throttled 340
throttled_usec 129003210

Ce que cela signifie : Si nr_throttled et throttled_usec montent pendant les incidents, votre « problème d’ordonnancement » est en fait un problème de quota.

Décision : Augmentez le quota, déplacez la charge, ou isolez-la sur des cœurs dédiés. Ne micro‑réglez pas le comportement de Thread Director quand vous refusez littéralement du temps CPU.

Task 14: Validate cpuset vs “what you thought was pinned” (systemd)

cr0x@server:~$ systemctl show nginx --property=AllowedCPUs --property=CPUQuota
AllowedCPUs=0-7
CPUQuota=80%

Ce que cela signifie : systemd peut imposer des contraintes sans que personne ne s’en souvienne. Combinez cela avec une topologie hybride et vous obtenez des expériences de performance accidentelles.

Décision : Alignez la politique CPU de l’unité service avec votre intention : soit retirez les contraintes, soit définissez‑les explicitement par classe de cœurs.

Task 15: Spot lock contention masquerading as “E-core slowness”

cr0x@server:~$ sudo perf top -p 2140 --stdio --delay 2 | sed -n '1,18p'
Samples: 1K of event 'cycles', 4000 Hz, Event count (approx.): 250000000
Overhead  Shared Object        Symbol
  18.22%  nginx               ngx_http_process_request_line
  11.40%  libc.so.6           __pthread_mutex_lock
   9.10%  nginx               ngx_http_upstream_get_round_robin_peer

Ce que cela signifie : Si beaucoup de temps est passé dans des mutex, déplacer des threads sur des P-cores ne corrigera pas la contention sous-jacente. Cela pourrait même la rendre plus bruyante.

Décision : Traitez la contention comme une cause racine séparée : corrigez le lock, réduisez l’état partagé ou scalez horizontalement. Ne renforcez pas l’épinglage.

Task 16: Verify virtualization layer CPU pinning (host-side)

cr0x@server:~$ virsh vcpupin appvm
VCPU: CPU Affinity
----------------------------------
0: 0-23
1: 0-23
2: 0-23
3: 0-23

Ce que cela signifie : La VM est autorisée à s’exécuter sur n’importe quel CPU hôte. En période de contention, elle peut atterrir sur des E-cores, et votre OS invité jure que tout va bien.

Décision : Si la VM héberge des services sensibles à la latence, épinglez les vCPUs sur des P-cores au niveau de l’hyperviseur, pas seulement à l’intérieur de l’invité.

Petite blague n°2 : Si vous ne pouvez pas reproduire le problème, ne vous inquiétez pas — la production se fera un plaisir de le reproduire pour vous à 2 h du matin.

Trois mini-histoires d’entreprise depuis les tranchées de l’ordonnancement

Mini-histoire n°1 : L’incident causé par une mauvaise hypothèse

Une entreprise SaaS de taille moyenne a déployé de nouvelles stations de travail développeur qui servaient aussi de runners CI ad hoc. CPU hybrides, beaucoup de RAM, « ça devrait être plus rapide ». En une semaine, la pipeline de build commença à montrer des jobs aléatoirement lents : certains finissaient en dix minutes, d’autres en vingt‑cinq, même commit, même image de conteneur.

La première hypothèse était familière : « Docker vole du CPU ». L’équipe a resserré les quotas CPU dans les cgroups pour « rendre ça équitable ». La variance s’est aggravée. Les temps de build tail ont explosé, et les ingénieurs ont commencé à relancer des jobs jusqu’à ce qu’ils aient de la chance — une forme coûteuse d’ingénierie de fiabilité.

Le vrai problème était plus subtil : leur service runner avait une unité systemd avec AllowedCPUs=0-7 héritée d’un guide d’optimisation plus ancien. Sur les machines non hybrides précédentes, CPUs 0-7 représentaient « la moitié de la machine, encore acceptable ». Sur le nouveau SKU hybride, 0-7 incluaient un mélange favorisant largement les cœurs plus lents. Sous des builds en rafale, l’ordonnanceur a fait ce qu’il pouvait, mais le service s’était déjà enfermé dans la mauvaise prairie.

La correction n’a pas été héroïque. Ils ont supprimé la contrainte, mesuré à nouveau, puis réintroduit une politique délibérée : les jobs de fond pouvaient utiliser les E-cores ; les tâches interactives sensibles à la latence obtenaient des P-cores. Le postmortem n’a pas blâmé l’OS. Il a blâmé l’hypothèse que la numérotation CPU est stable entre générations matérielles. À raison.

Mini-histoire n°2 : L’optimisation qui a échoué

Une équipe fintech faisait tourner un service de pricing basse latence avec des budgets p99 stricts. Ils ont lu que « la migration de threads nuit au cache » et ont décidé d’épingler les threads principaux sur des P-cores. Ils ont aussi épinglé les threads de logging et métriques « hors du chemin » sur des E-cores. Sur le tableau blanc, cela semblait propre.

Pendant quelques jours, le p50 s’est amélioré légèrement. Puis le p99 a commencé à grimper lors de l’ouverture des marchés. Le service n’était pas saturé globalement. Pourtant les pires requêtes time‑outtaient. Les ingénieurs ont ajouté plus d’épinglages et plus d’isolation. Les pics ont persisté. Le responsable de l’incident décrivit la situation comme « l’ordonnanceur est hanté », ce qui n’est pas un diagnostic actionnable.

Le problème était que leur service avait un motif en rafale : le thread principal dispatchait du travail à des threads aides pour la cryptographie et la compression. Ces aides n’étaient pas épinglées et étaient fréquemment planifiées sur des E-cores en raison de la pression de placement globale. Quand les workers épinglés sur P-cores attendaient les résultats des aides, le chemin critique s’allongeait. L’acte même d’épingler a réduit la capacité de l’ordonnanceur à co-localiser des threads coopérants sur les meilleurs cœurs.

L’optimisation contre‑productive était la croyance que « les threads critiques sont ceux nommés ‘worker’ ». En réalité, le chemin critique incluait les aides, le temps noyau et des GC occasionnels. La réparation a été d’arrêter le micro‑management par affinité, réactiver la flexibilité de l’ordonnanceur, et adopter plutôt une approche grossière mais correcte : garder la machine libre de voisins bruyants, ajuster les priorités rationnellement, et s’assurer que les P-cores soient disponibles quand le CPU signale le besoin.

Mini-histoire n°3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une société média exploitait une flotte de serveurs d’encodage. Les CPU hybrides ont été intégrés progressivement dans la flotte, ce qui est un vrai test de maturité opérationnelle quand le matériel est mixte. L’équipe avait une politique qui semble ennuyeuse et est donc rare : chaque nouveau type de matériel recevait une empreinte topologique dans la gestion de configuration — comptes de cœurs, SMT, bandes de fréquence max, et un mapping cpuset testé.

Quand un nouveau lot est arrivé, une mise à jour BIOS du fournisseur a changé le comportement d’alimentation et a légèrement modifié les caractéristiques de boost. Aucune panne. Mais leurs dashboards canary ont signalé « variance du temps mur d’encodage +12 % sur les nouveaux nœuds ». Cette alerte ne portait pas sur l’utilisation CPU ; elle portait sur la distribution des temps de job. Encore une fois : observabilité ennuyeuse, correcte.

Parce qu’ils avaient une empreinte, ils ont pu rapidement valider que leur politique « jobs de débit sur E-cores en premier » correspondait toujours à la réalité. Ils ont exécuté turbostat pendant les jobs canary, confirmé que les P-cores ne boostaient pas comme prévu, et ont rollbacké la politique BIOS au lieu de réécrire leur tuning d’ordonnanceur.

Le meilleur : personne n’a plaidé sur des impressions. Ils ont plaidé sur des preuves. La flotte est restée stable, et le rapport d’incident a tenu sur une page — un luxe sous-estimé.

Erreurs courantes : symptômes → cause racine → correctif

Erreur 1 : « Certains cœurs sont inactifs, donc nous avons de la capacité »

Symptômes : L’utilisation CPU globale semble modérée, mais la latence pique ; mpstat montre une charge par CPU inégale.

Cause racine : Affinité ou contraintes cpuset confinent les threads chauds à un sous‑ensemble (souvent incluant des E-cores), laissant d’autres CPUs inutilisés.

Correctif : Auditez taskset, AllowedCPUs de systemd, les cpusets des conteneurs. Retirez d’abord les contraintes ; réintroduisez‑les seulement avec un mapping explicite P/E.

Erreur 2 : « Épingler sur les P-cores améliore toujours la latence »

Symptômes : p50 s’améliore, p99 se dégrade ; la performance varie lors des rafales.

Cause racine : Vous avez épinglé une partie du chemin critique, mais les aides et le travail noyau atterrissent ailleurs. Vous avez aussi augmenté la contention sur l’ensemble épinglé et réduit la flexibilité de l’ordonnanceur.

Correctif : Préférez la priorité/QoS à l’affinité stricte. Si vous devez épingler, épinglez l’ensemble coopérant (et validez avec perf sched latency).

Erreur 3 : « C’est la faute de Thread Director »

Symptômes : Après un rafraîchissement hardware, « ordonnancement bizarre » apparaît ; les équipes blâment le CPU/OS.

Cause racine : Politique d’alimentation, limites thermiques, réglages BIOS ou firmware brident le boost, rendant les P-cores moins « P ».

Correctif : Mesurez les fréquences réelles (turbostat) sous charge représentative. Corrigez les contraintes plateforme avant de chasser le tuning d’ordonnanceur.

Erreur 4 : « Dans la VM tout est identique »

Symptômes : L’OS invité montre une utilisation CPU stable ; la latence applicative fluctue ; la contention hôte corrèle avec les pics.

Cause racine : Les vCPU sont planifiés sur des E-cores ou des CPUs hôtes en contention ; l’invité ne voit pas la topologie hybride.

Correctif : Épinglez ou priorisez les vCPUs au niveau de l’hyperviseur. Traitez l’hybride comme un problème d’ordonnancement côté hôte.

Erreur 5 : « Le quota est OK parce que la moyenne CPU est basse »

Symptômes : Chutes périodiques de latence ; cpu.stat montre du throttling ; les rafales ressemblent à des « hoquets d’ordonnancement ».

Cause racine : Le quota cgroup bride les rafales, particulièrement dommageable pour les threads sensibles à la latence.

Correctif : Augmentez le quota ou retirez‑le ; isolez les workloads bruyants avec des cpusets ; utilisez les métriques de throttling comme indicateurs SLO de première classe.

Erreur 6 : « Les E-cores sont réservés aux tâches inutiles »

Symptômes : Les jobs de débit sont à la traîne ; la puissance système est élevée ; les P-cores sont occupés par des tâches de fond.

Cause racine : La politique force trop de travail sur les P-cores, ignorant que les E-cores peuvent fournir d’excellents débits/watt.

Correctif : Placez intentionnellement le travail de débit prévisible sur les E-cores, en réservant les P-cores pour le travail en rafale/sensible à la latence. Validez avec des distributions de temps de complétion, pas seulement le %CPU.

Listes de vérification / plan pas à pas

Pas à pas : intégrer un hôte hybride dans une flotte de production

  1. Inventaire de la topologie : enregistrez le modèle CPU, comptes de cœurs, SMT, bandes de fréquence max, nœuds NUMA, agencement des caches.
  2. Support OS de base : confirmez le build du noyau/OS et que vous n’êtes pas sur une version d’ordonnanceur « ça marche sur mon laptop ».
  3. Définir une politique d’alimentation volontaire : choisissez un governor/plan qui correspond à la classe de service (latence vs débit vs batterie).
  4. Lancer des canaries avec des charges réelles : un burn CPU synthétique ne reproduira pas le comportement de classification.
  5. Mesurer la variance : suivez p50/p95/p99 pour la latence des requêtes ou le temps de runtime des jobs ; les problèmes hybrides se manifestent par la variance.
  6. Vérifier le throttling : quotas cgroup et limites thermiques doivent être observés, pas supposés.
  7. Ce n’est qu’ensuite que vous considérez l’affinité : traitez l’épinglage comme un outil dernier kilomètre, pas une première réponse.

Checklist : avant d’épingler quoi que ce soit

  • Avez-vous une cartographie P-core/E-core vérifiée pour ce SKU d’hôte spécifique ?
  • Avez‑vous confirmé que la charge n’est pas bridée par un quota ?
  • Avez‑vous mesuré les migrations et le délai de file d’exécution avec perf sched ?
  • Les IRQs atterrissent‑elles sur les cœurs que vous vous apprêtez à « réserver » ?
  • L’épinglage réduira‑t‑il la capacité de l’ordonnanceur à co-localiser des threads coopérants ?

Checklist : si vous exécutez des conteneurs sur des CPU hybrides

  • Préférez les cpusets pour les services critiques : allouez des P-cores connus pour les pods/services sensibles à la latence.
  • Évitez les quotas CPU stricts pour les services rafaleux ; les quotas rendent les « courtes rafales » coûteuses.
  • Exposez la topologie aux décisions d’ordonnancement au bon niveau (hôte d’abord, puis orchestrateur, puis workload).
  • Enregistrez la topologie par nœud dans votre inventaire pour que « CPU 0-7 » ne devienne pas une tradition tribale.

FAQ

Est-ce que Thread Director remplace l’ordonnanceur OS ?

Non. Il fournit des indications (indices pilotés par la télémétrie). L’OS prend toujours la décision finale basée sur la politique, l’équité, les priorités, les cgroups et les contraintes.

Pourquoi l’OS ne peut-il pas simplement s’en sortir tout seul ?

Il le peut — finalement, approximativement. Le CPU voit le comportement fin (stalls, mix d’instructions) plus rapidement que l’OS ne peut l’inférer depuis la comptabilité par tranche de temps. L’hybride rend le « finalement » trop lent et le « approximativement » trop coûteux.

Est-ce un problème uniquement Windows ou Linux ?

C’est un problème d’hybride. Différentes versions d’OS le traitent différemment, mais le défi central — choisir entre des cœurs asymétriques sous un comportement de thread changeant — existe partout.

Devrais-je désactiver les E-cores pour les serveurs ?

Généralement non. Désactiver les E-cores est un instrument brutal qui échange complexité contre silicium gaspillé. Ne le faites que si vous avez une exigence de latence mesurée que vous ne pouvez pas atteindre autrement, et que vous avez épuisé les correctifs d’ordonnancement/politiques raisonnables.

Dois‑je épingler ma base de données sur des P-cores ?

Seulement si vous avez prouvé que les threads critiques sont constamment limités par la latence et que les migrations vous nuisent. Beaucoup de bases de données profitent davantage d’une réduction de contention, d’un placement IRQ stable et d’une politique d’alimentation prévisible que de l’épinglage strict.

Pourquoi les builds varient-ils autant sur des machines hybrides ?

Les builds sont rafaleux et mixtes : compilation (CPU‑intensive), linkage (souvent goulot mono‑thread), compression et attentes I/O. Si des phases clés atterrissent sur des E-cores ou sont bridées par des quotas, le temps mur oscille.

Quel est le signe le plus rapide que c’est un problème de quota/throttling, pas de Thread Director ?

/sys/fs/cgroup/cpu.stat. Si le temps throttled augmente pendant les incidents, vous ne traitez pas un « placement ». Vous traitez un refus de temps CPU.

Comment les interruptions se rapportent-elles à l’ordonnancement hybride ?

Les interruptions peuvent consommer vos meilleurs cœurs et créer du jitter. Si les IRQ NIC campent sur un P-core, vous échangez peut‑être la latence applicative contre le traitement de paquets sans vous en rendre compte.

Quelle est la stratégie par défaut la plus sûre pour des charges mixtes ?

Laissez de l’espace à l’ordonnanceur pour travailler, gardez une politique d’alimentation cohérente, isolez le travail de fond bruyant (souvent sur des E-cores) et mesurez la latence tail et la variance. Utilisez l’affinité de manière chirurgicale, pas émotionnelle.

Conclusion : que faire la semaine prochaine

Thread Director n’est pas le CPU « prenant le contrôle ». C’est le CPU admettant qu’il dispose de meilleures données en temps réel que l’OS, et offrant ces données pour que l’ordonnancement sur des cœurs asymétriques cesse d’être un jeu de devinettes. Le gain n’est pas seulement la vitesse. C’est la prévisibilité — et la prévisibilité garde les pagers au calme.

Étapes pratiques :

  1. Choisissez un hôte hybride et construisez une empreinte topologique : groupes de cœurs, plafonds de fréquence et hotspots d’IRQ.
  2. Ajoutez deux dashboards : variance de jobs/temps d’exécution et throttling CPU. La moyenne CPU est une menteuse ; les distributions sont des adultes.
  3. Auditez votre flotte pour l’affinité cachée : AllowedCPUs systemd, usage de taskset, cpusets de conteneurs.
  4. Quand vous voyez des pics de latence, exécutez le playbook de diagnostic rapide dans l’ordre. Ne faites pas de freestyle.
  5. Si vous devez épingler, faites‑le avec intention : par classe de cœur vérifiée, avec mesure, et avec un plan de rollback.

Le CPU conseille maintenant. Vous n’êtes pas obligé de lui obéir aveuglément — mais vous devez arrêter de prétendre qu’il ne parle pas.

← Précédent
Migration de domaine WordPress sans perte SEO : 301, canonicals, sitemaps et zéro drame
Suivant →
Styles d’impression pour une documentation qui ne vous embarrasse pas

Laisser un commentaire