veilletech.fr
7 sept. Feed du jour
#05 GO Article

Go gagne le SIMD et perd son dernier cgo

Sept instructions par cycle, sur une machine qui en autorise huit.

Michael Stapelberg a supprimé en août la dernière dépendance cgo de Debian Code Search en réimplémentant le codec d'entiers TurboPFor en Go pur. Le paquet expérimental `simd/archsimd`, apparu dans Go 1.26, permet d'écrire de l'AVX512 sans assembleur ni bibliothèque C — et le résultat dépasse la version cgo qu'il remplace.

3 min de lectureavancévidéo 1:21
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. Ce qui l'a rendu possible
  3. La progression, étape par étape
  4. Ce que l'auteur refuse de faire
  5. À retenir

Ce qui se passe

Debian Code Search indexe tout le code source d'origine libre présent dans Debian. Comme tout moteur de recherche, il repose sur un index inversé, donc sur de longues listes d'identifiants de documents qu'il faut décoder vite. Depuis 2019, l'index positionnel tient sur disque — c'est ce qui permet de le loger sur un serveur Hetzner à deux SSD d'1 To — et 78,2 % des requêtes le sollicitent.

Ce décodage passait par TurboPFor, une bibliothèque C, appelée via cgo pendant sept ans. En août 2026, cette dernière dépendance a disparu.

Ce qui l'a rendu possible

Go 1.26, sorti en février 2026, introduit le paquet expérimental simd/archsimd. Trois réserves l'accompagnent, et elles comptent :

Jusque-là, faire du SIMD en Go voulait dire écrire de l'assembleur à la main, le générer avec Avo, ou passer par cgo. Aucune de ces trois voies ne se relit confortablement.

La progression, étape par étape

Étape Résultat
Encodeur Go pur, sans SIMD (commit e920dc7) 76 % de la vitesse du C
+ SIMD et spécialisation par largeur de bits (2-3 commits) dépasse le C
+ popcount positionnel sur le balayage de blocs ×2 supplémentaire

Deux détails de méthode valent d'être volés. D'abord GOAMD64, le niveau de micro-architecture : l'auteur recommande v3 par défaut en 2026 — pour que bits.OnesCount8 compile en POPCNT plutôt qu'en table de correspondance — ce qui exige un Haswell (2013) ou un Zen 1 (2017) au minimum. DCS lui-même compile en v4, qui suppose AVX512, donc Zen 4 ou Zen 5. Poser export GOAMD64=v4 dans le Makefile évite surtout de mesurer les replis lents dans ses propres benchmarks.

Ensuite le PGO, et c'est le passage le plus instructif. Activer la Profile-Guided Optimization a d'abord fait perdre 13 % en moyenne géométrique — un résultat contre-intuitif que l'auteur ne balaie pas. Le coupable n'est pas l'inlining mais l'alignement : Go applique PCALIGNMAX(64, 31) aux boucles chaudes, et ce remplissage déplace les instructions à d'autres adresses. Compiler avec -gcflags=all=-d=alignhot=0 restaure la performance, ce qui identifie la cause sans ambiguïté. C'était de la malchance, pas une règle.

Ce que l'auteur refuse de faire

C'est ce qui rend les chiffres exploitables. À armes égales — les mêmes noyaux AVX512 et le même popcount positionnel rétroportés dans le C — Go redevient ≈1,4× plus lent. L'écart tient à trois choses :

  1. les vérifications de bornes, qu'il ne désactivera pas parce qu'elles protègent ;
  2. les NOP insérés pour les marqueurs d'inlining mid-stack ;
  3. l'absence de ciblage CPU fin : Go connaît GOARCH et GOAMD64, pas « Zen 4 », si bien qu'un XORL CX, CX émis avant chaque POPCNT pour contourner une dépendance de sortie des Intel Sandy Bridge/Skylake pénalise aussi les AMD.

Il refuse également d'ajouter du SIMD partout où ce serait possible : chaque instruction vectorielle rend le code plus difficile à comprendre et à modifier.

À retenir

Le décodage atteint 7 instructions par cycle sur une machine qui plafonne à 8. Si vous traînez une dépendance cgo uniquement pour du calcul vectoriel, la sortie existe désormais — au prix d'une API instable, d'amd64 uniquement, et d'un code plus dense. L'auteur précise avoir mené ce travail avec un agent de code, tout en refusant de « vibe-coder » Debian Code Search : les gains sont mesurés, les commits relus.

Source : Michael Stapelberg