Un entretien de développeur C++ basse latence va plus loin que le C++ moderne. Le poste consiste à recevoir un flux réseau, le décoder, prendre une décision et répondre, dans un budget de quelques microsecondes. Les questions d'entretien portent donc aussi sur la machine : cache, prédiction de branchement, NUMA, ordonnanceur du noyau, carte réseau. Les offres demandent presque toujours Linux, C++17 ou C++20 et souvent du multicast UDP.
Le piège est le profil qui optimise sans mesurer. Il cite lock-free, inline et -O3, mais ne sait pas dire quel percentile il suivait ni avec quel outil. Un candidat expérimenté parle de p99 et de p99,9 plutôt que de moyenne, de cœurs isolés, d'allocations bannies du chemin critique, d'un faux partage repéré avec perf. Il sait aussi quand une file protégée par un mutex suffit.
Prévoyez un exercice sur du code réel : une file à un producteur et un consommateur à relire, ou une structure à réorganiser pour le cache. Le PDF reprend 30 questions réparties sur six axes, avec un cas de 20 minutes et une grille de 1 à 4.
Les outils et notions du C++ à faible latence
C++17/20 et calcul à la compilation
Le langage du poste, avec un usage particulier : templates, constexpr et if constexpr pour faire à la compilation ce qui coûterait à l'exécution, CRTP à la place des fonctions virtuelles sur le chemin critique. Les exceptions et le RTTI y sont souvent évités. Demandez ce que la personne retire du code chaud, et pourquoi.
Cache CPU et disposition mémoire
Une ligne de cache fait 64 octets sur x86-64, et un accès en mémoire centrale coûte de l'ordre de cent fois plus qu'un accès au cache L1. L'organisation des structures (données contiguës, champs chauds regroupés, alignement) pèse souvent plus que l'algorithme. Le faux partage, deux threads qui écrivent dans la même ligne, est une erreur classique.
Atomics et modèle mémoire
std::atomic et les ordres mémoire (relaxed, acquire, release, seq_cst) permettent de partager des données entre threads sans verrou. Mal choisis, ils produisent des bugs qui n'apparaissent qu'en charge ou sur une autre architecture. Ils sont la base des files lock-free à un producteur et un consommateur.
Linux, cœurs isolés et NUMA
Le code critique tourne sur des cœurs réservés (isolcpus, nohz_full, affinité des threads), à l'abri des interruptions et des autres processus. La mémoire est allouée sur le nœud NUMA du cœur qui l'utilise, souvent en huge pages. Le réglage du BIOS et du noyau fait partie du poste ou se fait avec l'équipe système.
Multicast UDP et kernel bypass
Les flux entrants arrivent souvent en multicast UDP, avec des pertes à détecter et à rattraper. Pour gagner le temps passé dans le noyau, on contourne sa pile réseau : Onload ou ef_vi sur les cartes AMD Solarflare, DPDK, AF_XDP. Onload accélère une application socket existante sans changer son code.
Mesure de latence
La latence se mesure par percentiles (p50, p99, p99,9, maximum) et en histogrammes, jamais par une moyenne. Les horodatages viennent du compteur TSC du processeur ou de la carte réseau. Le piège classique est l'omission coordonnée : un banc qui attend chaque réponse avant d'envoyer la requête suivante masque les pires cas.
perf, flame graphs et Compiler Explorer
perf lit les compteurs matériels (défauts de cache, mauvaises prédictions de branchement) et perf c2c repère le faux partage. Les flame graphs montrent où passe le temps, Compiler Explorer affiche l'assembleur produit, Google Benchmark sert aux micro-mesures. Intel VTune complète sur processeurs Intel.
Compilateur et options
GCC ou Clang, -O2 ou -O3, -march adapté à la machine de production, optimisation guidée par profil (PGO) et à l'édition des liens (LTO). Chaque option se valide par une mesure, parce qu'un gain obtenu sur un micro-banc peut disparaître dans l'application complète.
Le développeur C++ basse latence travaille sur un chemin critique court, mesuré en continu, où chaque changement est jugé sur les percentiles de latence. Il écrit peu de code nouveau à la fois et passe beaucoup de temps à mesurer, à lire l'assembleur et à régler la machine. Selon l'équipe, le poste penche vers le réseau (décodeurs de flux, kernel bypass), vers la partie applicative (structures de données, logique de décision) ou vers l'outillage de mesure. Certaines équipes ajoutent un FPGA pour les traitements les plus courts, et le développeur C++ travaille alors avec l'équipe matérielle sur l'interface entre les deux.
Ce que l'entretien doit établir chez un développeur C++ basse latence
- C++ moderne et calcul à la compilation
- Cache, disposition mémoire et branchements
- Atomics, ordres mémoire et lock-free
- Linux, mémoire et ordonnancement
- Réseau bas niveau et kernel bypass
- Mesure de latence et profilage
Les questions qui montrent si le candidat mesure ce qu'il optimise
Chaque question vient avec ce qu'une bonne réponse contient et le signal qui doit vous alerter. Pas besoin d'être technique pour les poser : écoutez si le candidat raconte du vécu.
Question 1 · confirmé
Deux threads incrémentent chacun leur propre compteur, et le programme va six fois moins vite qu'avec un seul thread. Que soupçonnez-vous ?
Une bonne réponseDu faux partage : les deux compteurs sont dans la même ligne de cache de 64 octets, qui fait l'aller-retour entre les cœurs à chaque écriture. La correction consiste à placer chaque compteur sur sa propre ligne (alignas(64) ou std::hardware_destructive_interference_size), ou à garder des compteurs locaux additionnés à la fin. Le candidat le confirme avec perf c2c ou les compteurs de cache.
Signal d'alerte« Il faut un mutex », ou une explication par la contention d'un verrou alors qu'il n'y en a aucun.
Question 2 · senior
Dans une file à un producteur et un consommateur, quels ordres mémoire utilisez-vous sur les index de tête et de queue, et pourquoi ?
Une bonne réponseLe producteur écrit l'élément puis publie le nouvel index avec memory_order_release ; le consommateur lit cet index avec memory_order_acquire avant de lire l'élément, ce qui garantit qu'il voit l'élément complet. Chacun lit son propre index en relaxed. seq_cst fonctionne aussi mais ajoute une barrière inutile sur les écritures en x86. Les deux index sont sur des lignes de cache séparées, et chaque côté garde une copie locale de l'index de l'autre pour limiter les lectures croisées.
Signal d'alerteTout en relaxed « parce que x86 est fortement ordonné », sans voir que le compilateur peut réordonner, ou volatile présenté comme une solution.
Question 3 · confirmé
Votre service affiche une latence moyenne de 4 µs. Le responsable veut savoir si c'est bon. Que mesurez-vous, et comment ?
Une bonne réponseDes percentiles (p50, p99, p99,9, maximum) rangés dans un histogramme, HdrHistogram par exemple, et pas une moyenne. Des horodatages pris au plus près du réseau, idéalement par la carte, sinon avec le TSC (rdtsc ou rdtscp sur un TSC invariant). Un banc qui envoie au rythme réel sans attendre les réponses, pour éviter l'omission coordonnée. Le candidat regarde la queue de la distribution et les pics d'origine système, comme les interruptions ou les défauts de page.
Signal d'alertestd::chrono autour d'une fonction appelée un million de fois en boucle, avec la moyenne comme résultat.
Question 4 · confirmé
Pourquoi évite-t-on new et malloc sur le chemin critique, et par quoi les remplacez-vous ?
Une bonne réponseLe temps d'un malloc est imprévisible : verrous de l'allocateur, fragmentation, appel système pour agrandir le tas, défaut de page à la première écriture. Le candidat préalloue au démarrage : pools d'objets de taille fixe, tampons circulaires, std::pmr avec un monotonic_buffer_resource, conteneurs réservés à l'avance. Il touche la mémoire au démarrage, ou la verrouille avec mlock, pour éviter les défauts de page en cours de route.
Signal d'alerte« new est rapide en C++ moderne », ou un std::string construit pour chaque message.
Question 5 · senior
Entre la carte réseau et votre code, où passe le temps avec une socket UDP classique, et comment le réduisez-vous ?
Une bonne réponseInterruption, traitement par la pile réseau du noyau, copie vers l'espace utilisateur, réveil du thread par l'ordonnanceur. Le candidat commence par une attente active sur la socket (busy polling) depuis un cœur isolé, puis contourne le noyau : Onload, qui accélère une application socket sans modifier son code, ef_vi pour un accès direct aux files des cartes AMD Solarflare, DPDK ou AF_XDP. Il connaît le prix : un cœur occupé à 100 %, du matériel spécifique, une exploitation plus délicate.
Signal d'alerteAgrandir les tampons de réception comme seule réponse, ou parler de TCP_NODELAY pour un flux UDP.
Recevez la fiche d'entretien complète en PDF
La fiche pour mener l'entretien de bout en bout, prête à imprimer ou à partager avec le manager.
- 30 questions sur 6 axes, avec la bonne réponse, le signal d'alerte et la relance
- Le niveau visé pour chaque question
- Une mise en situation de 20 minutes et ce qu'on attend du candidat
- La grille d'évaluation de 1 à 4, axe par axe
C++ basse latence : vos questions de recruteur
Quelles compétences demander à un développeur C++ basse latence ?
Un C++17 ou C++20 maîtrisé jusque dans les détails (templates, constexpr, comportements indéfinis), une compréhension fine du cache et de la disposition mémoire, les atomics et les ordres mémoire, la programmation Linux et réseau (multicast UDP, sockets, affinité des threads). Ajoutez la mesure : percentiles, histogrammes, perf. Le kernel bypass et le FPGA sont des plus selon l'équipe, rarement des prérequis pour un profil confirmé.
Un bon développeur C++ généraliste peut-il passer à la basse latence ?
Oui, s'il a déjà le réflexe de mesurer et une base solide en concurrence. Il lui manque en général la connaissance de la machine : lignes de cache, NUMA, coût d'une interruption, effet d'un défaut de page. Ces notions s'apprennent en quelques mois au contact d'une équipe qui mesure tout. Un généraliste incapable de dire comment il a vérifié un gain de performance aura plus de mal.
Comment distinguer un vrai profil basse latence d'un CV qui en reprend les mots ?
Demandez un chiffre et sa méthode : quelle latence au p99, mesurée à quel endroit, avec quel outil, et ce qui l'a fait baisser. Un profil qui a travaillé sur ces systèmes cite un cas précis, par exemple un faux partage trouvé avec perf c2c ou un pic causé par un défaut de page. Un CV qui aligne lock-free, kernel bypass et SIMD sans mesure associée reste à vérifier par un exercice.
Quel test technique pour un développeur C++ basse latence ?
Une file à un producteur et un consommateur à relire, avec un ordre mémoire faux et deux index sur la même ligne de cache, se traite en 30 à 45 minutes. Vous voyez si la personne trouve les deux défauts et explique comment elle mesurerait le gain. Pour un senior, ajoutez la lecture d'un histogramme de latence avec un pic à expliquer. Un exercice fait en direct et commenté vaut mieux qu'un long devoir à rendre.
Pour structurer vos autres entretiens, consultez aussi nos pages sur les questions d'entretien de recrutement, la méthode de l'entretien structuré et la grille d'évaluation d'entretien.



