[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