La fin de la course aux GHz : pourquoi « plus de GHz » ne marche plus

Cet article vous a aidé ?

Si vous avez déjà acheté des CPU « plus rapides » et constaté que la latence de production bouge à peine, vous avez déjà rencontré la fin de l’ère des GHz.
Les tableaux de bord ont l’air satisfaits : CPU sous 40 %, load average correct, et pourtant les requêtes s’accumulent comme des bagages d’aéroport après une tempête de neige.

C’est le piège de performance moderne : la fréquence a cessé d’être le réglage facile, et le système est devenu suffisamment complexe pour punir
les mauvaises hypothèses. La bonne nouvelle, c’est que les règles s’apprennent. La mauvaise, c’est que vous ne pouvez pas les ignorer en espérant que le turbo boost
sauvera vos objectifs trimestriels.

Pourquoi « plus de GHz » ne marche plus

La course aux fréquences s’est arrêtée pour la même raison que la plupart des courses aux armements : c’est devenu trop cher et trop chaud.
L’augmentation de fréquence était l’âge d’or où vous pouviez ne rien recompiler, ne changer aucune architecture et obtenir un bon gain à chaque
génération. Cette époque reposait sur une promesse tacite : la réduction des transistors rendrait les puces à la fois plus rapides et plus économes.
La promesse s’est brisée.

Le mur de la puissance : la physique a son mot à dire

La puissance dynamique dans le CMOS est souvent approximée par P ≈ C × V² × f.
On peut ignorer les constantes, mais on ne peut pas ignorer le carré de la tension.
Des fréquences plus élevées exigent généralement une tension plus haute pour garder les marges temporelles, et alors la puissance explose.
La puissance devient chaleur, la chaleur devient throttling, et le « 4.0 GHz » brillant devient un « 3.1 GHz pratique, sauf si le ventilateur gagne ».

Voilà le mur de la puissance : vous ne pouvez pas monter indéfiniment la fréquence sans dépasser le budget thermique.
Et en serveur, le budget thermique n’est pas négociable. Une baie est un radiateur de salle sur lequel repose votre chiffre d’affaires.

L’arrêt du scaling de Dennard

Pendant longtemps, le scaling de Dennard rendait les transistors plus petits, plus rapides et moins consommateurs par surface.
Vers le milieu des années 2000, les courants de fuite et d’autres effets ont ruiné ce rêve.
Les transistors ont continué à rétrécir, mais ils ont cessé d’être proportionnellement « moins coûteux » en watts.
L’industrie n’a pas arrêté d’innover. Elle a juste cessé de vous offrir des accélérations gratuites pour le code existant.

Le mur de la mémoire : les CPU sprinent, la RAM se promène

Même si vous pouviez augmenter la fréquence, beaucoup de la performance serveur est limitée par l’attente.
Attente sur la mémoire. Attente sur les défauts de cache. Attente sur l’I/O. Attente sur les verrous.
Les cœurs CPU sont devenus assez rapides pour terminer des instructions à un rythme héroïque—jusqu’à ce qu’ils aient besoin de données qui ne sont pas en cache.

La latence mémoire s’est améliorée, mais pas au même rythme que le temps de cycle CPU. Ainsi la latence mesurée en cycles CPU s’est détériorée.
Un accès DRAM qui était « un peu lent » est devenu « une éternité » en cycles de cœur.
Les CPU modernes combattent cela avec des caches plus grands, de meilleurs préfetchers, plus d’exécution out-of-order et des astuces spéculatives.
Ça marche—parfois. Mais cela complique aussi la performance au point où acheter des GHz ressemble à acheter une voiture de sport pour la circulation urbaine.

Concurrence et exactitude : l’autre mur

Quand la fréquence a cessé de croître, la solution évidente a été « ajouter des cœurs ».
Mais « ajouter des cœurs » n’est gratuit que si votre charge se parallélise, votre code est thread-safe, et vos dépendances ne serialisent rien.
Beaucoup de systèmes réels sont limités par quelques verrous très contestés, une boucle d’événement mono-thread quelque part, ou une base de données qui accepte poliment
vos requêtes parallèles puis les sérialise sur une page d’index chaude.

Voici la traduction opérationnelle : une mise à niveau CPU échoue rarement parce que le CPU est faible. Elle échoue parce que le goulot d’étranglement a bougé—or n’a jamais été le CPU.
Si vous ne mesurez pas, vous optimiserez la mauvaise chose avec assurance.

Une citation à garder sur un post-it :
Idée paraphrasée (Edsger Dijkstra) : Si vous ne pouvez pas le mesurer, vous ne pouvez pas l’améliorer de manière significative.

Blague n°1 : courir après les GHz en 2026, c’est comme ajouter plus de chevaux à une voiture coincée derrière un tracteur—techniquement impressionnant, émotionnellement inutile.

Faits historiques et contexte intéressant (court et concret)

  • Début des années 2000 : Les CPU grand public et serveurs ont fortement monté en fréquence ; le marketing mettait en avant les GHz parce que c’était facile à comprendre.
  • Milieu des années 2000 : Le scaling de Dennard a faibli ; la puissance de fuite a augmenté et la fréquence est devenue thermiquement coûteuse plutôt que « juste de l’ingénierie ».
  • Leçon de l’ère NetBurst : Certains designs ont poursuivi des horloges élevées avec des pipelines profonds ; ils étaient beaux sur une fiche technique et moins bons en travail réel par cycle.
  • Généralisation du multi‑cœur : L’industrie a pivoté de la vitesse mono‑cœur vers le multi‑cœur comme moyen pragmatique d’utiliser le budget transistor.
  • Ère du turbo boost : Les puces ont commencé à augmenter opportunistiquement leur fréquence dans les limites thermiques/power ; la « base clock » est devenue un minimum légal, pas une promesse d’expérience réelle.
  • Adoption du SMT : Le multithreading simultané a augmenté le débit quand les unités d’exécution étaient sous-utilisées, mais n’a pas doublé les performances et a parfois détérioré la latence tail.
  • Le cache est devenu roi : Les grands caches de dernier niveau et le préfetching intelligent sont devenus des caractéristiques compétitives alors que la latence mémoire restait récalcitrante.
  • NUMA partout : Les designs multi-socket et chiplet ont rendu la localité mémoire critique — un mauvais ordonnanceur ou un mauvais allocateur peut déclencher des problèmes de performance.
  • Boom de la spécialisation : Les unités vectorielles, extensions crypto, instructions de compression, et accélérateurs (GPU/NPUs) ont grandi parce que les cœurs généraux atteignaient des rendements décroissants.

Ce qui a remplacé les GHz : IPC, caches, cœurs et spécialisation

IPC : instructions par cycle est le nouveau jeu de statut

Le GHz est le métronome. L’IPC est la musique que vous jouez à chaque battement.
La performance CPU moderne est approximativement performance ≈ fréquence × IPC, puis réduite par les stalls : défauts de cache, mispredictions de branche, bulles de pipeline, et attente sur des ressources partagées.

Deux CPU à la même fréquence peuvent différer fortement en IPC selon la microarchitecture, la conception du cache, la prédiction de branchement,
et le mix d’instructions de la charge. Voilà pourquoi « même GHz » n’est pas « même vitesse », et pourquoi « plus de GHz » n’est souvent pas « plus rapide ».

Caches : la performance que vous ne voyez pas, jusqu’à ce que vous la perdiez

Les hits de cache font la différence entre un cœur qui reste occupé et un cœur qui rêve.
Beaucoup d’incidents de performance en production se résument à une augmentation de la taille du working set : nouvelle fonctionnalité, nouvel index, nouveau blob JSON, nouvelle couche de chiffrement,
et soudain les données chaudes ne tiennent plus en cache. Votre utilisation CPU peut rester modeste tandis que le débit s’effondre, car le CPU attend majoritairement.

Cœurs : débit, pas latence (sauf si vous avez de la chance)

Ajouter des cœurs aide quand votre charge contient du travail parallèle et ne se sérialise pas sur un point partagé.
C’est un jeu de débit : plus de transactions par seconde, plus de requêtes concurrentes, plus de jobs en arrière-plan.
Si votre problème est la latence d’une requête unique dominée par un seul thread, plus de cœurs est un placebo.

En termes opérationnels : monter en cœurs est la bonne décision pour le traitement par lots, les services sharded, et les endpoints stateless mis à l’échelle horizontalement.
C’est la mauvaise décision lorsqu’un monolithe a un verrou global, quand un ramasse‑miette stop-the-world se déclenche, ou quand la base de données est le goulot.

Vectorisation et accélérateurs : les accélérations spécialisées sont de vraies améliorations

Quand les cœurs généraux ne peuvent pas devenir beaucoup plus rapides sans fondre, les fabricants investissent pour accélérer des tâches spécifiques :
instructions SIMD/vectorielles pour les travaux data‑parallèles, instructions cryptographiques, compression et accélérateurs séparés.
Si votre charge correspond, vous obtenez des gains énormes.
Sinon, vous obtenez une puce « rapide » dans les brochures et « correcte » dans vos métriques.

L’ordonnanceur et le gestionnaire d’énergie : votre CPU se négocie, il n’est pas absolu

En 2026, la fréquence CPU est un résultat de politique. Turbo bins, limites de puissance, marge thermique, c‑states, p‑states, et l’ordonnanceur du noyau
décident à quelles fréquences vous tournez réellement. Dans un datacenter chargé, des serveurs identiques peuvent produire des performances différentes
parce que leur refroidissement ou leur alimentation diffèrent subtilement.

Réalités des charges : où la performance part réellement

La latence est souvent une chaîne de petites attentes

Une requête n’« utilise » pas seulement le CPU. Elle traverse des files, des verrous, des chemins noyau, des anneaux NIC, des caches de système de fichiers, du stockage, des buffers de BDD,
et du code en espace utilisateur. Votre p99 est généralement dominé non par la moyenne ; il est dominé par les quelques pires interactions :
un gros défaut de page, une pause GC, une limite cgroup « voisin bruyant », un accès mémoire NUMA distant, ou un incident de stockage qui plonge un thread en sleep ininterruptible.

L’utilisation CPU ment quand le CPU attend

Erreur classique : « CPU à 30 %, donc on a de la marge. » Pas si ces 30 % correspondent à un cœur chaud saturé et les autres inactifs.
Pas si vous êtes lourdement en iowait.
Pas si vous avez de la contention sur la run queue.
Pas si vous êtes freiné par la mémoire.

Stockage et réseau : les coauteurs silencieux de la « performance CPU »

En tant qu’ingénieur stockage, je le dis clairement : vous ne pouvez pas « upgrader le CPU » pour sortir d’un fsync lent, d’une réplication synchrone,
ou d’une charge de lectures aléatoires sur le mauvais support. Les CPU ne règlent pas la latence tail d’une file NVMe saturée, et ils ne règlent certainement
pas un contrôleur RAID qui reconstruit en silence.

De même, les problèmes réseau se manifestent par « le CPU est correct, mais le débit baisse ». Parce que vos threads sont bloqués sur des sockets,
votre noyau laisse tomber des paquets, ou vos handshakes TLS sont coincés derrière une faim d’entropie (oui, ça arrive encore).

Guide de diagnostic rapide : trouver le goulot sans une semaine de réunions

Première étape : est-ce du temps CPU, du CPU en attente, ou pas du tout le CPU ?

  1. Vérifiez la run queue et la saturation CPU : si un ou plusieurs cœurs sont épinglés, vous êtes CPU-bound même si le « CPU% global » semble faible.
  2. Vérifiez l’iowait et les tâches bloquées : si des threads sont en sleep ininterruptible, vous attendez de l’I/O (stockage ou système de fichiers réseau).
  3. Vérifiez la pression mémoire : défauts majeurs et swapping peuvent faire qu’un « CPU rapide » paraisse lent.

Deuxième étape : si CPU-bound, est-ce le débit d’instructions ou les stalls mémoire ?

  1. Regardez les signaux proches d’IPC : des cycles élevés avec peu d’instructions retraitées suggèrent des stalls ; de hauts taux de cache misses sont le suspect habituel.
  2. Vérifiez les context switches et la contention sur les verrous : de nombreux switches peuvent indiquer un overhead du scheduler ou trop de threading.
  3. Regardez les stacks principales : trouvez où vont les cycles ; ne devinez pas.

Troisième étape : si lié à l’I/O, identifiez quelle file se remplit

  1. Latence des périphériques bloc : un await/service time élevé ou des files profondes indiquent une saturation du stockage ou des problèmes de device.
  2. Système de fichiers et writeback : pages sales et throttling peuvent bloquer les écrivains ; les charges fsync-heavy sont des coupables fréquents.
  3. Réseau : retransmissions, drops ou saturation softirq CPU peuvent mimer des « serveurs lents ».

Quatrième étape : vérifiez le turbo/throttling et la politique d’alimentation (parce que la réalité)

Quand la performance change « aléatoirement » entre des hôtes identiques, suspectez des limites thermiques ou de puissance.
Les CPU modernes sont polis : ils se protègent et protègent votre budget datacenter en se calant discrètement.

Tâches pratiques : commandes, ce que signifie la sortie, et la décision à prendre

Voici les tâches que j’exécute réellement quand quelqu’un dit « les nouveaux CPU sont plus lents » ou « nous avons besoin de plus de GHz ».
Chaque tâche inclut : commande, signification de la sortie, et point de décision. Utilisez-les comme checklist, pas comme rituel.

Task 1: Verify real-time CPU frequency behavior (not marketing clocks)

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

Ce que cela signifie : « CPU MHz » est un instantané. S’il est bas alors que la machine est chargée, vous êtes peut-être en économie d’énergie, en throttling, ou sous une charge qui dort souvent.

Décision : Si la performance est mauvaise, confirmez les fréquences actives sous charge (Task 2) et vérifiez le governor/les limites d’alimentation (Task 3/4).

Task 2: Watch per-core frequency and utilization while the issue happens

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

Ce que cela signifie : Bzy_MHz est la fréquence effective quand le cœur est occupé ; CoreTmp indique la marge thermique. Si Bzy_MHz est en dessous du turbo attendu alors que Busy% est élevé et les températures hautes, vous êtes probablement limité thermiquement.

Décision : Si vous voyez un Bzy_MHz bas sous charge, vérifiez les limites d’alimentation et le refroidissement. N’« optimisez » pas le code avant de savoir que le CPU ne se bride pas lui‑même.

Task 3: Check the CPU governor (common in cloud images and laptops repurposed as servers)

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

Ce que cela signifie : powersave peut convenir sur les systèmes intel_pstate modernes, mais sur certaines configurations il limitera la réactivité.

Décision : Si la latence est critique, définissez une politique appropriée (souvent performance ou un profil tuné) et retestez. Ne faites pas de cargo‑cult ; mesurez avant/après.

Task 4: Check thermal and throttling indicators

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

Ce que cela signifie : Des messages noyau comme ceux-ci sont votre preuve : vos « GHz » ont été renégociés à la baisse.

Décision : Corrigez le refroidissement, le flux d’air, le montage du dissipateur, les courbes de ventilateur, les limites d’alimentation BIOS, ou la densité de baie. Ne blâmez pas le compilateur.

Task 5: Determine if you’re CPU-saturated or just “kind of busy”

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

Ce que cela signifie : Un load average proche ou supérieur au nombre de threads CPU peut indiquer une saturation, mais il compte aussi les tâches en sleep ininterruptible (I/O wait).

Décision : Associez ceci à vmstat (Task 6) pour distinguer la pression exécutable des tâches bloquées I/O.

Task 6: Quick view of runnable queue, context switches, and iowait

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
12  0      0 812344  55284 932120    0    0    12    38 8200 9100 55 10 33  2  0
14  0      0 801120  55284 932992    0    0    10    22 8300 9500 58  9 31  2  0
 2  6      0 794224  55284 931880    0    0   120  9800 4100 7000 12  6 40 42  0

Ce que cela signifie : r est le nombre de threads exécutables ; b est bloqué. Haut wa et haut b indiquent des stalls I/O. Haut r avec faible id indique saturation CPU.

Décision : Si bloqué/I/O‑lourd, dirigez‑vous vers les tâches stockage/réseau. Si CPU‑lourd, profilez (Task 11/12).

Task 7: Identify if a single core is pinned (the “CPU 30%” lie)

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

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

Ce que cela signifie : Le CPU 7 est épinglé. L’ensemble paraît correct ; votre latence ne se soucie pas du « all ».

Décision : Identifiez le thread/processus chaud. Envisagez du sharding, enlever les goulots mono‑thread, ou pinner de façon réfléchie (pas au hasard).

Task 8: Check memory pressure and major faults (the “fast CPU, slow page faults” combo)

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

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

Ce que cela signifie : Des pics de majflt/s signifient de vrais défauts de page sur disque. Cela détruit la latence tail.

Décision : Ajoutez de la mémoire, réduisez le working set, tunez les caches, ou corrigez un déploiement qui a gonflé l’usage mémoire. N’achetez pas des GHz supérieurs pour « résoudre » le paging.

Task 9: Inspect NUMA locality (remote memory is “slow CPU” in disguise)

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

Ce que cela signifie : Deux nœuds NUMA. Un déséquilibre de mémoire libre peut indiquer une allocation ou un pinning inégal.

Décision : Si un process est épinglé aux CPUs du nœud 1 mais alloue principalement sur le nœud 0, attendez‑vous à des lectures distantes plus lentes. Utilisez numastat (task suivante).

Task 10: Confirm if your process is paying the “remote memory tax”

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

Ce que cela signifie : Forte allocation sur le nœud 0. Si le scheduler exécute des threads sur le nœud 1, vous effectuez des lectures distantes.

Décision : Corrigez l’affinité CPU, utilisez l’interleaving intentionnel, ou lancez une instance par socket. Cela vaut souvent plus que 200 MHz.

Task 11: Identify top CPU consumers and whether they’re in user vs kernel

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

Ce que cela signifie : Le service utilise l’équivalent d’environ 4 cœurs. Le temps système est non trivial ; cela peut être le réseau, des syscalls, le système de fichiers, ou de la contention.

Décision : Si sy est élevé, inspectez les hotspots noyau (softirqs, syscalls) et envisagez des offloads ou du batching. Si us est élevé, profilez l’espace utilisateur.

Task 12: Sample where CPU cycles go (perf top)

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

Ce que cela signifie : Les fonctions chaudes parsèment du JSON et hachent. C’est du travail calculatoire ; « plus de GHz » pourrait aider un peu, mais des choix d’algorithme et de format de données peuvent aider beaucoup plus.

Décision : Envisagez de réduire le coût JSON (format binaire, moins de champs), activez l’accélération crypto matérielle, ou déplacez le hachage vers une bibliothèque spécialisée. Mesurez l’impact sur le p99.

Task 13: Collect hardware counter hints (cache misses, cycles, instructions)

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

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

      10.003022332 seconds time elapsed

Ce que cela signifie : IPC ~0.70 suggère des stalls ; le taux de cache miss est élevé. Vous n’êtes pas « trop lent en GHz », vous attendez la mémoire.

Décision : Concentrez‑vous sur la localité des données : réduisez le pointer‑chasing, rétrécissez les objets, améliorez le batching, ou restructurez les boucles chaudes. Envisagez des caches plus grands ou moins de threads qui thrashent des caches partagés.

Task 14: Identify I/O latency and queue depth on block devices

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

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

Ce que cela signifie : %util proche de 100 et un await/aqu-sz élevés signifient que la file du device est profonde et les requêtes attendent. Le CPU semblera « correct » pendant que l’application se bloque.

Décision : Réduisez les écritures synchrones, tunez l’ordonnancement, séparez les charges bruyantes, ou scalez le stockage. Si vous voyez ça, arrêtez le débat sur la fréquence CPU.

Task 15: Confirm filesystem writeback pressure (common with bursty writes)

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

Ce que cela signifie : Dirty/Writeback élevés indiquent beaucoup de flushs en attente. Si les writers sont throttlés, des pics de latence surviennent.

Décision : Vérifiez si votre app appelle fsync trop souvent, si vous avez besoin d’options de montage différentes, ou si vous devriez déplacer les logs sur des devices séparés.

Task 16: Spot network retransmits and drops (because “slow CPU” is sometimes TCP pain)

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

Ce que cela signifie : Retransmissions et dépassements de file d’écoute empoisonnent la latence. Votre CPU peut être inactif pendant que les requêtes expirent et se réessaient.

Décision : Tunez le backlog, corrigez la perte de paquets, scalez les frontends, ou offloadez le TLS. N’achetez pas des fréquences plus élevées pour compenser des pertes réseau.

Blague n°2 : Si votre correction est « ajouter 500 MHz », vous n’êtes plus loin de blâmer la rétrograde de Mercure pour la perte de paquets.

Trois mini-récits d’entreprise (anonymisés, techniquement plausibles et douloureusement familiers)

Mini-récit 1 : L’incident causé par une mauvaise hypothèse (les GHz comme destin)

Une société SaaS de taille moyenne a migré une API sensible à la latence d’anciens serveurs vers des serveurs plus récents. Le dossier achat était propre :
génération plus récente, turbo annoncé plus élevé, plus de cœurs, « meilleur en tout ». L’équipe attendait une baisse de la latence p95.
Au lieu de cela, le p95 s’est aggravé—parfois fortement—pendant les heures de pointe.

La première réaction a été prévisible : blâmer le code. Une « war room » performance s’est formée, et les ingénieurs ont commencé à proposer des micro‑optimisations.
Pendant ce temps, les SRE ont remarqué quelque chose d’étrange : la pire latence corrélait avec un sous‑ensemble d’hôtes, et ces hôtes montraient des températures d’entrée légèrement plus élevées.
Pas alarmant, juste « un peu plus chaud ».

Ils ont exécuté turbostat pendant des tests de charge et ont trouvé que la fréquence occupée effective était systématiquement plus basse sur les hôtes chauds.
Les CPU restaient dans des limites sûres en réduisant l’horloge. Le nombre turbo de la fiche technique n’était atteignable qu’avec suffisamment de marge thermique,
et la disposition des baies avait changé—équipements plus denses, flux d’air différent, mêmes hypothèses de refroidissement.

La mauvaise hypothèse n’était pas « les GHz comptent ». La mauvaise hypothèse était « les GHz sont une constante ». Dans les systèmes modernes, c’est une variable.
Ils ont corrigé le problème physique : amélioré le flux d’air, rééquilibré le placement en baie, et ajusté les power caps dans le BIOS avec soin.
Ce n’est qu’alors que les CPU « plus rapides » sont devenus plus rapides, et ce n’est qu’alors que le profilage du code est devenu significatif.

La leçon durable était opérationnelle : quand la performance régresse après un renouvellement matériel, traitez l’environnement comme un suspect de première classe.
La fréquence est politique + physique, pas un chiffre que vous possédez.

Mini-récit 2 : L’optimisation qui a échoué (plus de threads, moins de débit)

Une équipe pipeline data avait un service d’enrichissement CPU‑intensif. Ils voyaient une utilisation CPU à 60 % et ont supposé qu’ils laissaient du débit sur la table.
Quelqu’un a augmenté le pool de threads workers de 16 à 64. Le changement est parti vite car « ça ne touchait que la configuration ».
Le throughput s’est amélioré dans un test synthétique. En production, cependant, un vilain pic p99 est apparu et le débit global a chuté pendant les fenêtres chargées.

Les symptômes étaient confus : l’utilisation CPU a augmenté, mais aussi les context switches. Le taux de cache miss a augmenté. Le service a commencé à timeout des appels vers une dépendance aval,
entraînant des retries. Les retries ont augmenté la charge, ce qui a augmenté les timeouts, ce qui a augmenté les retries. Une boucle de rétroaction classique, sponsorisée par le pool de threads.

Le profilage a montré que les chemins chauds étaient intensifs mémoire : parsing, allocations d’objets, tables de hachage, et un cache LRU partagé.
Avec 64 threads, le working set par cœur ne tenait plus bien en cache, et la contention sur les verrous du cache partagé a augmenté.
Le CPU n’était pas « sous‑utilisé » à 60 % ; il attendait déjà la mémoire et subissait la contention des structures partagées.

La correction n’a pas été « moins de threads » comme principe moral ; c’était « dimensionner correctement la concurrence ». Ils ont choisi un pool plus petit,
partitionné les caches par worker pour réduire la contention, et tuné le comportement de l’allocateur. Le débit s’est amélioré et le p99 s’est stabilisé.

L’enseignent : plus de cœurs et plus de threads ne sont pas une stratégie de performance. Ce sont des multiplicateurs du goulot d’étranglement existant.
Multipliez la contention sur les verrous et le thrash du cache assez et vous obtenez un incident de performance avec une excellente utilisation CPU.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise (profiling de base et canaris)

Une équipe plateforme d’entreprise exploita un workload mixte sur une flotte : trafic web, jobs en arrière-plan, et quelques processus batch « temporairement permanents ».
Ils avaient une règle qui irritait les développeurs : chaque changement matériel ou noyau significatif nécessitait une pool canary et une capture de baseline performance.
Pas un cirque de benchmarks d’une semaine—juste assez pour comparer quelques compteurs clés et histogrammes de latence.

Un nouveau noyau est allé sur le pool canary. En quelques heures, les canaris montraient un peu plus de temps sys et une légère augmentation de la latence tail.
Rien de dramatique. Exactement le type de chose que vous manqueriez si vous ne surveilliez que le CPU moyen.
Mais la baseline de l’équipe incluait des compteurs perf stat pour les cache misses et les context switches, plus iostat et les retransmits réseau.

Les données suggéraient un changement de comportement d’ordonnancement et une augmentation du travail softirq sous charge.
Ils ont mis en pause le rollout, reproduit le problème en staging, et l’ont lié à une combinaison d’affinité d’interruptions NIC et d’un nouveau défaut dans la gestion d’énergie.
La correction était banale : ajuster l’IRQ affinity et appliquer un profil tuné pour la classe de workload.

Parce qu’ils utilisaient des canaris et des baselines, l’« incident » n’a jamais atteint les clients.
Pas de rollback d’urgence, pas de bilans exécutifs, pas de pizza de minuit.
La pratique était ennuyeuse. Elle était aussi correcte. Voilà à quoi ressemble la fiabilité quand on la fait volontairement.

Erreurs courantes (symptômes → cause racine → correctif)

1) Symptom: Overall CPU is low, but p99 latency is high

Cause racine : Un cœur épinglé, un goulot mono‑thread, ou une section sérialisée (verrou global, boucle d’événement, pause GC).

Correctif : Utilisez mpstat -P ALL pour trouver les cœurs chauds, puis profilez le processus/thread concerné. Réduisez la sérialisation, shardez le travail, ou déplacez le travail lourd hors du chemin de la requête.

2) Symptom: “Newer servers are slower” in a subset of hosts

Cause racine : Throttling thermique, capping de puissance, réglages BIOS différents, ou refroidissement inégal.

Correctif : Vérifiez le MHz occupé effectif avec turbostat, regardez dmesg pour les événements thermiques, normalisez les profils BIOS, et corrigez le flux d’air/la densité en baie.

3) Symptom: CPU is moderate, but throughput collapses during write bursts

Cause racine : Saturation de la file de stockage, fsync storms, throttling writeback, ou contention de reconstruction RAID.

Correctif : Utilisez iostat -x, vérifiez Dirty/Writeback, séparez les devices de logs, batcher les fsync, ou provisionnez du headroom IOPS/latence.

4) Symptom: More threads made it worse

Cause racine : Contention, overhead des context switches, thrash du cache, ou amplification aval via retries/timeouts.

Correctif : Mesurez les context switches (vmstat), profilez les verrous, limitez la concurrence, partitionnez les structures partagées, et implémentez du backpressure.

5) Symptom: CPU “randomly” spikes in sys time

Cause racine : Saturation softirq réseau, taux élevé de syscalls, pertes de paquets déclenchant des retransmits, ou overhead de la pile de stockage.

Correctif : Vérifiez le % système dans top, les retransmits via netstat -s, l’affinité IRQ, et envisagez du batching, des offloads, ou la réduction des syscalls par requête.

6) Symptom: Latency degrades after moving to multi-socket machines

Cause racine : Accès mémoire NUMA distant dus au placement scheduler, déséquilibre d’allocation mémoire, ou pinning de containers.

Correctif : Utilisez numastat -p, alignez CPU et localité mémoire (une instance par socket), et évitez la chatter inter‑nœud accidentelle.

7) Symptom: You “upgrade CPU” and see no improvement

Cause racine : Le goulot est ailleurs : latence stockage, réseau, verrous BD, stalls mémoire, ou sérialisation.

Correctif : Suivez le guide de diagnostic rapide. Prouvez que le CPU est la ressource limitante avant de dépenser ou de réécrire du code.

Checklists / plan étape par étape

Checklist A: Before you buy CPUs (or celebrate “higher GHz”)

  1. Définissez l’objectif : débit, latence p95, latence p99, ou coût par requête. Choisissez une métrique primaire.
  2. Capturez une baseline : usage CPU par cœur, fréquence effective sous charge, échantillon taux de cache miss, latence iostat, retransmits réseau.
  3. Classez la charge : compute‑heavy, memory‑heavy, lock‑heavy, I/O‑heavy, ou mixte.
  4. Trouvez la forme d’échelle : doubler les instances double‑t‑il le débit ? Si oui, scale‑out peut battre le scale‑up.
  5. Identifiez les risques tail : pauses GC, fsync, verrous BD, voisins bruyants, throttling. Ils dominent le p99.
  6. Choisissez le matériel selon les preuves : plus de cache pour mémoire‑heavy, puissance soutenue pour compute‑heavy, meilleur stockage pour I/O‑heavy.

Checklist B: When latency regresses after a hardware refresh

  1. Confirmez le throttling : turbostat + messages thermiques dans dmesg.
  2. Normalisez BIOS et politique d’alimentation : assurez‑vous de réglages cohérents sur la flotte.
  3. Vérifiez le NUMA : localité et pinning pour les gros processus.
  4. Vérifiez la parité noyau/microcode : les mismatches causent des deltas confus.
  5. Comparez les compteurs perf : proxies IPC et taux de cache miss ; ne vous fiez pas au seul CPU%.
  6. Profilage du code seulement ensuite : vous voulez corriger le logiciel sur un comportement matériel stable.

Checklist C: Step-by-step performance debugging in production (safe-ish)

  1. Commencez par les symptômes : p95/p99, taux d’erreur, retries, longueurs de files.
  2. Vérifiez la saturation : CPU par cœur, run queue, tâches bloquées.
  3. Vérifiez la mémoire : défauts majeurs, swapping, OOM kills, comportement de l’allocateur si visible.
  4. Vérifiez le stockage : iostat await/profondeur de file ; dirty/writeback si write‑heavy.
  5. Vérifiez le réseau : retransmits/drops, overflows de listen queue, usage CPU softirq.
  6. Profilez brièvement : perf top ou perf stat pendant 10–30 secondes, pas une heure.
  7. Faites un seul changement : revenez sur les « optimisations » risquées, limitez la concurrence, ajustez la politique, puis mesurez à nouveau.

FAQ

1) If GHz doesn’t matter, why do CPUs still advertise it?

Parce que ça compte parfois, et parce que c’est facile à vendre. La fréquence influence encore la performance, mais ce n’est pas le levier dominant
sur les charges modernes. La performance soutenue dépend des limites de puissance, du refroidissement, de l’IPC, du comportement du cache, et de la localité mémoire.

2) What should I look at instead of GHz when choosing servers?

Adaptez le matériel à la charge : taille de cache et bande passante mémoire pour services data‑heavy, puissance soutenue et capacités vectorielles pour compute,
et latence/IOPS stockage pour systèmes write‑heavy. Pensez aussi topologie NUMA, nombre de cœurs vs licences, et fréquence soutenue réelle sous votre charge.

3) Why is “overall CPU%” misleading?

Parce qu’il fait la moyenne sur les cœurs et masque l’épinglage. Un cœur saturé peut dominer la latence pendant que les autres sont inactifs.
Vérifiez toujours les stats par cœur et la run queue. Vérifiez aussi l’iowait et les tâches bloquées pour distinguer attente et travail effectif.

4) Does turbo boost help production workloads?

Ça peut aider, surtout pour les charges bursty et les pics mono‑thread. Mais le turbo est opportuniste : il dépend de la marge thermique/power.
Sous charge soutenue, beaucoup de systèmes se stabilisent près de la base ou d’une fréquence intermédiaire. Mesurez Bzy_MHz sous charge réelle.

5) Are more cores always better than higher clocks?

Non. Plus de cœurs aident le débit si la charge s’échelonne et ne conteste pas. Des fréquences plus élevées aident le travail mono‑thread ou faiblement parallèle.
La vraie réponse : identifiez d’abord le goulot. Si vous êtes limité par la latence mémoire, ni l’un ni l’autre n’aide autant que corriger la localité.

6) Why do some optimizations increase cache misses?

Causes courantes : rendre les objets plus grands, ajouter des champs, augmenter la cardinalité, passer à des structures pointer‑heavy, ou augmenter la concurrence
si bien que des threads s’évinçent mutuellement des working sets. Les cache misses sont souvent une « taxe de structure de données », pas un problème de compilateur.

7) How can storage make the CPU look slow?

Quand des threads se bloquent sur le disque (ou le stockage réseau), le CPU est inactif ou en attente, et la latence des requêtes augmente.
Les gens voient des réponses lentes et supposent que le calcul est en cause. iostat -x et les tâches bloquées dans vmstat exposent cela rapidement.

8) What’s the fastest way to prove you are CPU-bound?

Cherchez une run queue élevée (vmstat r), peu d’idles, épinglage par cœur, et un iowait stable bas.
Ensuite prenez un court échantillon perf top pour confirmer que les cycles sont dans le code utilisateur plutôt qu’en attente sur des verrous ou de l’I/O.

9) What’s “dark silicon” and why should I care?

C’est la réalité que tous les transistors ne peuvent pas être actifs à pleine vitesse simultanément dans les contraintes puissance/thermique.
Concrètement : votre CPU a des capacités de pic qui ne peuvent pas toutes être utilisées en même temps. Voilà pourquoi la performance soutenue et l’adéquation workload matter.

10) Can I “fix” this with container limits or CPU pinning?

Parfois. Le pinning peut améliorer la localité de cache et réduire le jitter de l’ordonnanceur, mais il peut aussi créer des points chauds et des problèmes NUMA.
Les limites peuvent prévenir les voisins bruyants mais induire du throttling si elles sont trop basses. Traitez‑les comme des outils chirurgicaux : mesurez avant et après.

Conclusion : prochaines étapes pratiques (quoi faire lundi matin)

Arrêtez d’acheter des GHz comme en 2003. Achetez la performance comme vous achetez la fiabilité : en adaptant le système à la charge et en vérifiant le comportement sous charge.
La fréquence fait toujours partie de l’histoire, mais ce n’est pas l’intrigue.

  1. Exécutez le guide de diagnostic rapide sur votre service à pire latence et classez le goulot : CPU, stalls mémoire, stockage ou réseau.
  2. Capturez une baseline avec un petit ensemble de commandes reproductibles : usage par cœur, MHz effectif, échantillon taux de cache miss, latence iostat, retransmits.
  3. Corrigez d’abord les choses ennuyeuses : throttling, localité NUMA, retries incontrôlés, et saturation des files I/O. Elles apportent des gains spectaculaires et moins de surprises.
  4. Optimisez le code ensuite, guidé par des profils. Si votre chemin chaud est parsing JSON et hachage, « plus de GHz » est une taxe ; de meilleurs formats et algorithmes sont un investissement.
  5. Faites les changements de performance comme les SRE font les changements de fiabilité : canaris, plans de rollback, et critères d’acceptation mesurables.

La course à la vitesse d’horloge ne s’est pas arrêtée parce que les ingénieurs se sont lassés. Elle s’est arrêtée parce que la physique a envoyé une facture.
Payez‑la avec de la mesure, de la localité et une conception système sensée—pas avec de l’espoir et un tableau d’achat.

← Précédent
Debian 13 : permissions du socket PHP-FPM — le petit correctif qui tue les 502 (cas n°35)
Suivant →
VPN full-mesh pour trois bureaux : quand en avoir besoin et comment le garder gérable

Laisser un commentaire