[m-users.] A quick guide on getting to 'hello world' with GraalVM
Julian Fondren
jfondren at minimaltype.com
Mon Sep 23 14:36:17 AEST 2019
Hello list,
If you're wanting to make efficient binaries with Mercury, the C
backends are an option, but another is the Java backend with GraalVM for
ahead-of-time compilation to native code.
This is a short guide to get you to 'hello world' with it and Mercury:
1. download GraalVM https://github.com/oracle/graal/releases and extract
it somewhere:
$ cd ~/java/
$ wget
https://github.com/oracle/graal/releases/download/vm-19.2.0.1/graalvm-ce-linux-amd64-19.2.0.1.tar.gz
$ tar zxvf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
$ mv graalvm-ce-19.2.0.1 graal
This results in ~/java/graal/bin/java being an executable you can use
run something with the JVM.
2. install GraalVM's 'native-image' support:
$ ~/java/graal/bin/gu install native-image
Downloading: Component catalog from www.graalvm.org
Processing component archive: Native Image
Downloading: Component native-image: Native Image from github.com
Installing new component: Native Image (org.graalvm.native-image,
version 19.2.0.1)
3. You can now go ahead and compile something to the Java backend
normally. You should probably use GraalVM's java, but I didn't have a
problem using a Fedora openjdk install.
$ mmc -s java --make hello
Making Mercury/int3s/hello.int3
Making Mercury/ints/hello.int
Making Mercury/javas/jmercury/hello.java
Making Java class files
Making hello.jar
This creates two things: a 'hello.jar' that isn't to GraalVM's
standards, and a 'hello' script that includes some necessary
information.
4. Patch hello.jar's MANIFEST.MF to include a Main-Class field
The main class will be in the last line of the 'hello' script:
$ tail -1 hello|awk '{print $3}'
jmercury.hello
You can use whatever zip tools you want, but an easy way is to just
edit the file with a recent vim:
$ vim hello.jar
" zip.vim version v28
" Browsing zipfile /path/to/hello.jar
" Select a file with cursor and press ENTER
META-INF/
META-INF/MANIFEST.MF
jmercury/hello$1.class
jmercury/hello.class
select MANIFEST.MF , hit enter, and this line, and save and exit:
Main-Class: jmercury.hello
5. (optional step) Fail to create an efficient binary.
Getting the CLASSPATH from the 'hello' script again:
$ ~/java/graal/bin/native-image -jar hello.jar -classpath
/usr/local/mercury-rotd-2019-09-17/lib/mercury/lib/java/mer_rt.jar:/usr/local/mercury-rotd-2019-09-17/lib/mercury/lib/java/mer_std.jar
.. quite a bit of output ..
Warning: Image 'hello' is a fallback image that requires a JDK for
execution (use --no-fallback to suppress fallback image generation).
NB. this step will overwrite the 'hello' bash script with a binary.
As 'hello worlds' go, this binary isn't great:
(average of 3 runs)
User time : 0 s, 998359 us
System time : 0 s, 120153 us
Time : 1118.512 ms (372.837 ms/per)
Max RSS : 98.9 MB
Page reclaims : 55649
Page faults : 0
Block inputs : 0
Block outputs : 0
vol ctx switches : 1595
invol ctx switches : 46
nearly 400 ms and 100 MB of RAM.
We get a fallback image at this point because Mercury's Java CLASSPATH
includes some reflection, and GraalVM can't generate native images that
involve reflection unless it's told in advance exactly what kind of
reflection to handle.
6. Create a reflection configuration file
For a real-world application (which may involve your own reflection),
you're probably going to want to run the fallback image with a tracing
agent for a bit, and then manually work on the generated reflection
configuration file. I haven't looked at the Java stuff at all, but I
imagine reflection is used for something like debugging output, which
could mean that it's precisely your rarely-hit error handlers that need
reflection configuration, and which the tracing agent will skip unless
you hit them while tracing. These links might help with that:
https://medium.com/graalvm/introducing-the-tracing-agent-simplifying-graalvm-native-image-configuration-c3b56c486271
https://blog.frankel.ch/configuring-graal-native-aot-reflection/
In this exact case reflection never happens, so an empty configuration
will do:
$ echo '[]' > empty-reflection.json
7. Create an efficient binary
$ ~/java/graal/bin/native-image -jar hello.jar -classpath
/usr/local/mercury-rotd-2019-09-02/lib/mercury/lib/java/mer_rt.jar:/usr/local/mercury-rotd-2019-09-02/lib/mercury/lib/java/mer_std.jar
-H:ReflectionConfigurationFiles=empty-reflection.json
Build on Server(pid: 4532, port: 41379)
[hello:4532] classlist: 513.75 ms
[hello:4532] (cap): 604.46 ms
[hello:4532] setup: 1,074.38 ms
[hello:4532] (typeflow): 5,973.94 ms
[hello:4532] (objects): 4,376.35 ms
[hello:4532] (features): 277.29 ms
[hello:4532] analysis: 11,225.12 ms
[hello:4532] (clinit): 127.28 ms
[hello:4532] universe: 273.23 ms
[hello:4532] (parse): 612.55 ms
[hello:4532] (inline): 1,436.14 ms
[hello:4532] (compile): 20,613.63 ms
[hello:4532] compile: 23,472.91 ms
[hello:4532] image: 532.88 ms
[hello:4532] write: 122.91 ms
[hello:4532] [total]: 37,355.26 ms
37s is quite a bit longer than the half-second that mmc needed to create
hello.jar in the first place, but the performance improvement is pretty
drastic:
(average of 3 runs)
User time : 0 s, 5723 us
System time : 0 s, 10902 us
Time : 16.625 ms (5.542 ms/per)
Max RSS : 7.4 MB
Page reclaims : 859
Page faults : 0
Block inputs : 0
Block outputs : 0
vol ctx switches : 12
invol ctx switches : 0
Cheers.
More information about the users
mailing list