Java Ahead-of-Time Compiler
Java od verze 9 nabízí (v experimentální formě JEPu, od verze ±13
neexperimentálně) možnost ahead-of-time kompilace. Příslušný nástroj jaotc
(postavený na kompilátoru Graal) je připravený v repozitářích Debianu a Ubuntu
(a nejspíš i v dalších distribucích s JVM 9+).
OpenJDK ve verzi 16 odstranilo jaotc
i Graal JIT. Tento článek je tím pádem
zastaralý.
AOT kompilace má potenciál pomoci zvláště krátkou dobu běžícím aplikacím, které nedají JVM čas se plně zahřát a JITu příležitost vygenerovat efektivní kód. Jednu takovou mám při ruce a shodou náhod generuje i tento blog (a mnoho dalších webů) — asciiblog.
Generování celého webu k47.cz na obyčejné JVM trvá 2550 ms. To budu brát jako výchozí bod pro další měření.
jaotc
může kompilovat ve dvou módech: Jednak jako statickou binárku a pak
jako binárku pro tiered kompilaci. Statická verze nemůže využít nejsilnější
zbraně C2 kompilátoru – profilování, spekulativní optimalizace a deoptimizace – a chová se, jako kdyby šlo o zkompilovné C++. Binárka pro
tiered kompilaci v sobě obsahuje infrastrukturu pro tyto kroky a nabízí tak
to nejlepší z obou světů – na jedné straně rychlejší start a na druhé zároveň
vysoký špičkový výkon.
Nic ale není zadarmo. Asciiblog, který má jako fat jar asi 7 MB (obsahuje celou standardní knihovnu Scaly), po kompilaci do statické binárky zabere 188 MB a do tiered binárky dokonce 263 MB. Je to proto, že kompiluje všechno, co v jaru najde a ne jen to, co nakonec poběží.
Jak rychle tedy program běží s AOT kompilací? Výsledky jsou následující:
JVM | 2550 ms |
jaotc non-tiered | 2150 ms |
jaotc tiered | 2200 ms |
Nějaký rozdíl tam bude, ale v tomto případě ne příliš veliký.
Zajímavý je také pohled na špičkový výkon plně zahřáté JVM:
JVM C2 | 850 ms |
jaotc non-tiered | 1300 ms |
jaotc tiered | 830 ms |
Závěry jsou dva:
- Režie je značná.
- Když se JVM rozjede naplno, dokáže být zatraceně rychlé.
Pozn:
- JEP doporučuje zkompilovat modul
java.base
, ale to v případě asciiblogu nemá skoro žádný dopad na rychlost, protože ze standardní knihovny Javy nepoužívá skoro nic (jen regex a trochu IO). - Obrovská velikost binárky může mít dopad na rychlost, jak ukazuje nástroj BOLT. Přesunutím horkého kódu blízko k sobě se zlepší využití instrukční cache a to vede k nezanedbatelnému zvýšení výkonu.
- Článek jsem původně napsal nejspíš v lednu 2019 a teď může být mírně zastaralý. Doufám, že zastaral a čísla se o něco zlepšila. Teď ale nemám při ruce původní test, abych ho jednoduše zopakoval + slušelo by se do mixu přihodit GraalVM native image.
K tématu:
- Escape analysis.