Learning
Všechny články
Engineering21. září 2026 7 min

Emulace neplatí za instrukce, platí za paměťový model

Překlad x86 na ARM je snadný, dokud nezačneš dodržovat sliby, které x86 dával mlčky

Kompatibilita se neláme na překladu instrukcí, ale na zárukách pod nimi

Přeložit instrukci x86 na ekvivalent v ARM je řemeslo s konečným počtem případů. Skutečná cena emulace leží jinde: x86 slibuje pořadí zápisů, nezarovnané přístupy a atomicitu přes hranici cacheline, aniž by to kdokoli musel psát do kódu. ARM nic z toho nedává.

Emulátor musí ty sliby dodržet, i když pro ně nemá hardwarovou podporu, a účet za to je řádově vyšší než za samotný překlad.


Total Store Ordering se dá napodobit, ne zadarmo

x86 používá Total Store Ordering: zápisy jsou viditelné v pořadí, v jakém je procesor provedl. ARM má slabé uspořádání a tuhle záruku nedává, protože jí platí za výkon.

FEX to řeší tak, že každý load x86 přeloží na load-acquire a každý store na store-release. Sémanticky to sedí. Prakticky jde o instrukce, které nikdy nebyly navržené k tomu, aby se používaly na každém přístupu do paměti, a na některých platformách jako AmpereOne to stojí přes padesát procent výkonu.

Hardware to postupně dohání. Rozšíření FEAT_LRCPC od ARMv8.3 přidává loady vhodné přesně pro tenhle vzor a dostává se blízko nativnímu výkonu. Apple šel dál a do M1 dal přepínatelný TSO režim, kde záruku poskytne rovnou procesor a emulátor nemusí dělat nic.


Zarovnání, o které se x86 nikdy nestaral

Aplikace pro x86 běžně přistupují do paměti nezarovnaně, protože to tam funguje. ARM u acquire a release instrukcí vyžaduje přirozené zarovnání a na nezarovnaném přístupu vyhodí chybu.

FEX na to reaguje za běhu: přepíše zasažené místo a nahradí optimalizované acquire a release instrukce obyčejnými přístupy s explicitními bariérami DMB. Funguje to a stojí to zhruba polovinu propustnosti. Na Cortex-X4 padá cachovaný zarovnaný load z 11,5 GB/s na 5,7 GB/s, jakmile se přejde na bariéry.

Za povšimnutí stojí ten mechanismus. Emulátor nedokáže dopředu poznat, který přístup bude nezarovnaný, takže optimalizuje a čeká na chybu. Rychlá cesta se opouští až v okamžiku, kdy selže, a to je obecný tvar každé kompatibilní vrstvy: optimistický předpoklad plus záchytný bod.


Split-lock nemá na ARM co nahradit

Nejhorší případ je atomická operace, která přesáhne hranici cacheline. x86 ji zvládne přes takzvaný split-lock, zaplatí latenci kolem 760 nanosekund a atomicitu udrží. ARM pro to nemá nic.

FEX musí sáhnout po signálním handleru z jádra a celou operaci obsloužit mimo rychlou cestu. V paměti typu write-combine, kterou používají buffery viditelné pro GPU, je výsledek až osmsetšestnáctkrát pomalejší. Ve hře Hollow Knight: Silksong to znamenalo méně než jeden snímek za sekundu.

U dedikovaných PCIe GPU je situace podle autorů neřešitelná v rámci dnešního ARM. Navrhované východisko je hardwarové: 128bitová instrukce CASP se sémantikou přes hranici cacheline, nad kterou by se dal split-lock emulovat přes opakování. Qualcomm mezitím v Oryon-3 přidal koherentní cacheline, které řeší nezarovnané atomiky v rámci 64 bajtů.


Co si z toho odnést

Když navrhuješ kompatibilní vrstvu nad čímkoli, sepiš si nejdřív ne to, co původní platforma dělá, ale co mlčky zaručuje. Pořadí operací, chování na hranicích, atomicitu, viditelnost. Právě tyhle nevyslovené záruky jsou to, na čem se kompatibilita prodraží, protože je nikdo nedokumentoval jako rozhraní a přitom na nich stojí existující kód.

Druhá lekce je o tvaru řešení. Tam, kde se drahý případ nedá poznat dopředu, se vyplatí optimistická rychlá cesta plus mechanismus, který ji za běhu degraduje. Platí se za to složitostí a nutností mít záchytný bod, ale alternativa je vzít nejhorší případ jako výchozí a zpomalit všechno.

A nakonec: rozdíl mezi padesáti procenty a osmisetnásobkem je rozdíl mezi daní a nepoužitelností. Padesát procent ustojíš architekturou. Osmisetnásobek musí vyřešit hardware.

Zdroje

Poslech místo čtení — 1 zdroj k načtení.