Zstd se v jádře Linuxu ptá procesoru na BMI2 pokaždé, když zakládá kontext
Kód zstd zabudovaný v linuxovém jádře se ptá procesoru instrukcí CPUID na podporu BMI2 při zakládání každého kompresního i dekompresního kontextu. Odpověď se přitom za chodu systému změnit nemůže. Tři záplaty poslané 26. srpna 2026 do konference vývojářů jádra si ji zapamatují; v měření uvnitř virtuálního stroje klesl čas dekomprese o 71 procent.

Usama Arif poslal 26. srpna 2026 do konference vývojářů linuxového jádra sérii tří záplat nazvanou zstd: probe the CPU for BMI2 support once, not per context. Popis vady se vejde do dvou vět. Knihovna zstd zabudovaná v jádře si mezi obecnou a zrychlenou cestou vybírá za běhu a instrukci CPUID kvůli tomu pouští pokaždé, když se zakládá kontext pro kompresi nebo dekompresi. Odpověď se přitom za chodu systému změnit nemůže.
BMI2 je sada instrukcí pro práci s jednotlivými bity. Intel ji zavedl s architekturou Haswell, AMD ji má od jádra Excavator a novějších. Zstd v ní má napsané rychlejší varianty některých svých funkcí a při každém startu kontextu se ptá, jestli je smí použít.
Kontext se v jádře zakládá po blocích
Detekce za běhu sama o sobě špatná není. Je to způsob, jak nechat starší procesory běžet na obecném kódu. Vadí, že se opakuje.
Arif v průvodním dopise vypisuje, odkud se do zstd chodí: squashfs zakládá dekompresní kontext pro každý blok, který rozbaluje, a erofs, btrfs, f2fs i kryptografické rozhraní jádra si ho pořizují na každou operaci. Jeden dotaz stojí na x86 dvě serializující instrukce CPUID, tedy takové, u kterých procesor nesmí nic přeskládat ani překrýt s okolím.
Tři záplaty, jednadvacet přidaných řádků
První záplata je úklid. Funkce ZSTD_initStaticCCtx() měla dotaz opsaný ručně a ptala se jen na BMI2, zatímco obě zbývající cesty k založení kontextu jdou přes ZSTD_cpuSupportsBmi2(), která vyžaduje i BMI1. Přísnější test je ten správný: těla funkcí, mezi kterými příznak vybírá, nesou značku TARGET_ATTRIBUTE("lzcnt,bmi,bmi2"), takže v nich překladač smí použít i instrukce BMI1 a LZCNT. Žádný prodávaný procesor x86 podle Arifa BMI2 bez BMI1 neumí, takže je to skrytá nesrovnalost, ne pozorovaná chyba.
Druhá záplata míří na sestavení, kde ten příznak nikdo nečte. Když je DYNAMIC_BMI2 nula, tedy u GCC staršího než jedenáctka, u jiné architektury než x86 nebo u překladu, který má BMI2 zapnuté rovnou pro celý kód, rozhodnou se všechny funkce pro výchozí tělo. CPUID se přesto pouštělo a výsledek se zahodil.
Třetí záplata je vlastní změna. Výsledek se uloží do statické proměnné, jejíž záporná počáteční hodnota znamená „ještě jsem se neptal“.
static int supported = -1;
int s = READ_ONCE(supported);
if (s < 0) {
ZSTD_cpuid_t const cpuid = ZSTD_cpuid();
s = ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid);
WRITE_ONCE(supported, s);
}
return s;
Zámek u toho žádný není a Arif vysvětluje proč: dva dotazy, které se potkají, spočítají z téhož listu CPUID tutéž hodnotu, takže nesynchronizovaný přístup nevadí. Makra READ_ONCE a WRITE_ONCE jsou tam kvůli tomu, aby se na té neškodnosti shodl překladač s hlídačem souběhů KCSAN.
Funkce je označená MEM_STATIC, tedy vkládaná dovnitř volajícího, takže vlastní kopii uložené odpovědi dostane každá překladová jednotka: v modulárním sestavení tři, plus po jedné v každém dekompresoru zavaděče. Podle Arifa je to hrstka celých čísel v segmentu bss a jeden dotaz navíc na každou z nich, což se řešit nevyplatí. Celá série sahá na dva soubory, přidává jednadvacet řádků a tři ubírá.
Sedmdesát jedna procent je změřených ve virtuálním stroji
Arif měřil testem nad rozhraním crypto_acomp se čtyřkilobajtovými bloky, a to v hostu KVM s jediným virtuálním procesorem. Dvanáct startů po devíti kolech, každé kolo 30 000 operací, a z těch 108 kol medián průměrů:
| komprese | dekomprese | |
| bez záplat | 16 756 ns | 3 455 ns |
| se záplatami | 13 646 ns | 1 002 ns |
| rozdíl | −3 110 ns (18,6 %) | −2 452 ns (71,0 %) |
Ten propastný rozdíl u dekomprese je z velké části daň za virtualizaci a Arif to sám píše: CPUID vyvolá bezpodmínečný přechod z hosta do hypervizoru. Na holém železe se nic takového neděje, takže tam bude úspora menší. O kolik, série neuvádí; číslo mimo virtuální stroj v ní není ani jedno.
Symptom byl v konferenci vidět už v červenci
Nhat Pham, jeden ze správců zswapu, odpověděl týž den odpoledne. O zstd sám píše, že v něm odborník není, a posouzení správnosti nechává na Nicku Terrellovi a Herbertu Xu, tedy na správcích zstd a kryptografického rozhraní; oba jsou mezi adresáty série. U Terrellovy adresy na doméně fb.com se ptá, jestli ještě funguje.
K tomu připomíná, že se totéž už jednou ohlásilo, a odkazuje na zprávu z 28. července. V ní Jianyue Wu vedle vlastního tématu, návrhu na zmenšení záznamu v zswapu, vypsal tabulku propustnosti. Zstd v ní přes rozhraní acomp zvládl 740 MB/s při ukládání a 980 MB/s při čtení, zatímco přes zcomp to bylo 1 190 a 1 720 MB/s. Wu to uzavřel větou, že to je jiné téma. Příčinu ta tabulka nepojmenovává, ukazuje jen ten rozdíl, a měsíc se k němu nikdo nevrátil.
Záplaty jsou zatím v recenzním kole a v žádné vývojové větvi nejsou. Kdyby prošly, pozná to hlavně to, co má zstd v úzkém místě: obrazy se squashfs, souborové systémy erofs v kontejnerech a odkládání paměti přes zswap. Zbytek jádra si ničeho nevšimne, protože je to jednadvacet řádků, které si pamatují odpověď, jež se nemění.
Zdroje: průvodní dopis série na lore.kernel.org, druhá a třetí záplata, zpráva na Phoronixu a soubor MAINTAINERS pro určení správců.