Bylo by možná dobré připomenout jeden z důvodů, proč se Go relativně dobře rozšířilo. Je to mj. i díky gorutinám a kanálům, jak jejich podpoře v jazyku, tak i jejich "lehkotonážnost" při použití. Co takto namísto mikrobenchmarků nahodit něco paralelního, kde se dají kanály a gorutiny použít?
Ano, na potřebu "skutečného" benčmárku jsme již také narazili. Hrál si s tím Michal, můj kolega z jiného týmu a patra. Vytvořil web-fmwks-perf-comparision, kde chce testovat reálné scénáře: HTTP, parsování JSONu, přístup do databáze, atd. Zatím je tam to HTTP.
Pomáhal jsem mu to uchodit s native-image
. Bylo dost těžké Go dohnat, ale nakonec se to snad povedlo. Akorát jsem musel nahradit Netty za NanoHTTPD. Zdá se, že v Netty je příliš mnoho abstrakcí a na obyčejném Hello World příkladu to příliš zpomaluje. Po přepsání a znovu využití vláken ta Java verze přeložená native-image
dokázala odpovědět na patnáct tisíc dotazů za sekundu. Asi tak stejně jako Go.
Ale zrovna HTTP server je příklad použití, kde by normální JVM po dosažení optimálního stavu (po pár tisících dotazech) zřejmě fungovala rychleji než native-image
...
Chtěl jsem zkusit ten native-image, rychlý start pro cli programy by byl pěkný.
$ java -version openjdk version "1.8.0_192" OpenJDK Runtime Environment (build 1.8.0_192-20181024121959.buildslave.jdk8u-src-tar--b12) GraalVM 1.0.0-rc9 (build 25.192-b12-jvmci-0.49, mixed mode) $ cat HelloWorld.java public class HelloWorld { public static void main(String[] args) throws Exception { System.out.println("Hello, World"); } } $ javac HelloWorld.java && java HelloWorld Hello, World $ native-image --static -cp . HelloWorld Build on Server(pid: 32471, port: 44227) [helloworld:32471] classlist: 171.66 ms [helloworld:32471] (cap): 103.20 ms [helloworld:32471] setup: 174.61 ms fatal error: com.oracle.svm.core.util.VMError$HostedError: java.nio.charset.UnmappableCharacterException: Input length = 1 at com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:70) at com.oracle.svm.hosted.c.codegen.CSourceCodeWriter.writeFile(CSourceCodeWriter.java:183) at com.oracle.svm.hosted.c.codegen.CSourceCodeWriter.writeFile(CSourceCodeWriter.java:160) ... zkráceno Error: Processing image build request failed
Zdá se, že to ještě má mouchy, ale třeba jsem tomu jen nevěnoval dost času...
Děkuji za vyzkoušení. Je mi líto, že to spadlo. Můžete zadat chybu na https://github.com/oracle/graal/issues a přidat nějaké detaily, protože mně to na Kubuntu 16.04 prošlo...
Bingo! Přeci jenom funguje, tak uvidím jak si povede až zkusím něco reálnějšího.
Třeba ještě dostane java šanci i pro cli nástroje...
Jasně, že hello world není reprezentativní program, ale zaujalo mě několik věcí:
Velikost ~7MB u staticky linkované binárky je dost (ale chápu, že tam je runtime s gc a ostatním příslušenstvím), dynamicky linkované ~6MB je pořád dost. Z GO padají binárky o podobné velikosti. Kompilace do binárky trvá u hello world 20sec - to mi přijde jako hodně, ale zase kompilaci člověk nepouští tak často. Start výsledné binárky je okamžitý, subjketivně rychlejší než klasické jvm.
$ mv ~/Stažené/graalvm-ce-1.0.0-rc9 ~/Sandbox $ export PATH=~/Sandbox/graalvm-ce-1.0.0-rc9/bin:$PATH $ javac HelloWorld.java && java HelloWorld && native-image --static -cp . HelloWorld Hello, World Build on Server(pid: 8989, port: 35763)* [helloworld:8989] classlist: 1,090.04 ms [helloworld:8989] (cap): 1,032.43 ms [helloworld:8989] setup: 2,087.33 ms [helloworld:8989] (typeflow): 4,684.50 ms [helloworld:8989] (objects): 2,183.62 ms [helloworld:8989] (features): 79.43 ms [helloworld:8989] analysis: 7,054.64 ms [helloworld:8989] universe: 323.77 ms [helloworld:8989] (parse): 831.03 ms [helloworld:8989] (inline): 1,367.12 ms [helloworld:8989] (compile): 5,685.21 ms [helloworld:8989] compile: 8,498.63 ms [helloworld:8989] image: 726.43 ms [helloworld:8989] write: 201.11 ms [helloworld:8989] [total]: 20,041.28 ms $ time ./helloworld Hello, World ./helloworld 0,00s user 0,00s system 93% cpu 0,002 total $ ls -lah helloworld -rwxr-xr-x 1 martin martin 7,1M 4. pro 14.51 helloworld $ ldd helloworld není dynamickým spustitelným kódem $ native-image -cp . HelloWorld zsh: correct 'HelloWorld' to 'helloworld' [nyae]? n Build on Server(pid: 8989, port: 35763) [helloworld:8989] classlist: 190.99 ms [helloworld:8989] (cap): 601.78 ms [helloworld:8989] setup: 1,002.38 ms [helloworld:8989] (typeflow): 3,407.67 ms [helloworld:8989] (objects): 1,644.25 ms [helloworld:8989] (features): 69.44 ms [helloworld:8989] analysis: 5,211.27 ms [helloworld:8989] universe: 164.07 ms [helloworld:8989] (parse): 516.41 ms [helloworld:8989] (inline): 577.43 ms [helloworld:8989] (compile): 3,090.78 ms [helloworld:8989] compile: 4,514.93 ms [helloworld:8989] image: 418.64 ms [helloworld:8989] write: 113.15 ms [helloworld:8989] [total]: 11,644.94 ms $ time ./helloworld Hello, World ./helloworld 0,00s user 0,00s system 93% cpu 0,003 total $ ls -lah helloworld -rwxr-xr-x 1 martin martin 6,3M 4. pro 14.59 helloworld $ ldd helloworld linux-vdso.so.1 (0x00007ffc5a7fb000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f7e71422000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f7e7141d000) libz.so.1 => /usr/lib/libz.so.1 (0x00007f7e71206000) librt.so.1 => /usr/lib/librt.so.1 (0x00007f7e711fc000) libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007f7e711c2000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f7e70ffe000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f7e71a56000)
Ano. Lze to. Pokud tomu rozumím, tak se používá třída NodeSourcePosition. Pozice se obvykle vyskytuje v bajtkódu a po naparsování do grafu se přiřadí k jednotlivým vrcholům. Kompilátor ten graf pak různě mění, ale i když nějaké vrcholy zahodí a vytvoří místo nich jiné, tak jim předá vhodnou pozici. Vrcholy, které zbudou v poslední fázi (a generují nativní instrukce), tak stále mají jakýsi vztah k původním pozicím. Tak asi tak. Více jsem to nezkoumal.