Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building Wholly Graal with Truffle!

DZone's Guide to

Building Wholly Graal with Truffle!

Learn how to build Graal using Truffle on both local environments like Linux and MacOS, as well as container environments with Docker.

· Open Source Zone ·
Free Resource

DON’T STRESS! Assess your OSS. Get your free code scanner from FlexeraFlexNet Code Aware scans Java, NuGet, and NPM packages.

Image title

Citation: credits to the feature image go to David Luders and reused under a CC license, the original image can be found on this Flickr page.

Introduction

It has been some time since my previous posts [1][2] on Graal/GraalVM/Truffle. Recently, there has been a general request to write something about “how to build” this awesome thing called Graal. Technically, we will be building HotSpot’s C2 compiler (look for C2 in the glossary list) replacement, called GraalThis binary is different from the GraalVM suite you download from OTN via http://graalvm.org/downloads.

I wasn’t just going to stop at the first couple of posts on this technology. In fact, one of the best ways to learn and get an in-depth idea about how any tech works is to know how to build it.

Getting Started

Building JVMCI for JDK8, Graal, and Truffle is fairly simple, and the instructions are available on the Graal repo. We will be running them on both the local (Linux, MacOS) and container (Docker) environments. To capture the process as code, they have been written in Bash; check it out here.

During the process of writing the scripts and testing them on various environments, there were some issues, but these were soon resolved with the help members of the Graal team thanks, Doug!

Running Scripts

Documentation on how to run the scripts are provided in the README.md on awesome-graal. For each of the build environments, they are merely a single command:

Linux and MacOS

$ ./local-build.sh 

$ RUN_TESTS=false           ./local-build.sh 

$ OUTPUT_DIR=/another/path/ ./local-build.sh


Docker

$ ./docker-build.sh 

$ DEBUG=true                 ./docker-build.sh 

$ RUN_TESTS=false            ./docker-build.sh 

$ OUTPUT_DIR=/another/path/  ./docker-build.sh 


Both the local and Docker scripts pass in the environment variables i.e.  RUN_TESTS and OUTPUT_DIR to the underlying commands. Debugging the Docker container is also possible by setting the DEBUG environment variable.

For a better understanding of how they work, it is best to refer to the local and Docker scripts in the repo.

Build Logs

I have provided build logs for the respective environments in the build/x86_64/linux_macos folder here.

Once the build is completed successfully, the following messages are shown:

[snipped]

>> Creating /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal from /path/to/awesome-graal/build/x86_64/linux/graal-jvmci-8/jdk1.8.0_144/linux-amd64/product
Copying /path/to/awesome-graal/build/x86_64/linux/graal/compiler/mxbuild/dists/graal.jar to /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal/jre/lib/jvmci
Copying /path/to/awesome-graal/build/x86_64/linux/graal/compiler/mxbuild/dists/graal-management.jar to /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal/jre/lib/jvmci
Copying /path/to/awesome-graal/build/x86_64/linux/graal/sdk/mxbuild/dists/graal-sdk.jar to /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal/jre/lib/boot
Copying /path/to/awesome-graal/build/x86_64/linux/graal/truffle/mxbuild/dists/truffle-api.jar to /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal/jre/lib/truffle

>>> All good, now pick your JDK from /path/to/awesome-graal/build/x86_64/linux/jdk8-with-graal :-)

Creating Archive and SHA of the newly JDK8 with Graal & Truffle at /home/graal/jdk8-with-graal
Creating Archive jdk8-with-graal.tar.gz
Creating a sha5 hash from jdk8-with-graal.tar.gz
jdk8-with-graal.tar.gz and jdk8-with-graal.tar.gz.sha256sum.txt have been successfully created in the /home/graal/output folder.


Artifacts

All the Graal and Truffle artifacts are created in the graal/compiler/mxbuild/dists/ folder and copied to the newly built jdk8-with-graal folder. Both of these will be present in the folder where the build.sh script resides:

jdk8-with-graal/jre/lib/jvmci/graal.jar 
jdk8-with-graal/jre/lib/jvmci/graal-management.jar 
jdk8-with-graal/jre/lib/boot/graal-sdk.jar 
jdk8-with-graal/jre/lib/truffle/truffle-api.jar


In short, we started off with vanilla JDK8 (JAVA_HOME) and the build script created an enhanced JDK8 with both Graal and Truffle embedded in it. At the end of a successful build process, the script will create a .tar.gz archive file in the jdk8-with-graal-local folder, alongside this file you will also find the sha5 hash of the archive.

In case of a Docker build, the same folder is called jdk8-with-graal-docker. In addition to the above-mentioned files, it will also contain the build logs.

Running Unit Tests

Running unit tests is a simple command:

mx --java-home /path/to/jdk8 unittest


This step should follow the moment we have a successfully built artifact in the jdk8-with-graal-local folder. The below messages indicate a successful run of the unit tests:

    >>>> Running unit tests...
    Warning: 1049 classes in /home/graal/mx/mxbuild/dists/mx-micro-benchmarks.jar skipped as their class file version is not supported by FindClassesByAnnotatedMethods
    Warning: 401 classes in /home/graal/mx/mxbuild/dists/mx-jacoco-report.jar skipped as their class file version is not supported by FindClassesByAnnotatedMethods
    WARNING: Unsupported class files listed in /home/graal/graal-jvmci-8/mxbuild/unittest/mx-micro-benchmarks.jar.jdk1.8.excludedclasses
    WARNING: Unsupported class files listed in /home/graal/graal-jvmci-8/mxbuild/unittest/mx-jacoco-report.jar.jdk1.8.excludedclasses
    MxJUnitCore
    JUnit version 4.12
    ............................................................................................
    Time: 5.334

    OK (92 tests)


JDK Differences

So, what have we got that’s different from the JDK we started with? If we compare the boot JDK with the final JDK, here are the differences:

JDKversusGraalJDKDiff-02


Combination of diff between $JAVA_HOME  and jdk8-with-graal and meld will give the above:

JDKversusGraalJDKDiff-01


diff -y --suppress-common-lines $JAVA_HOME jdk8-with-graal | less


meld $JAVA_HOME ./jdk8-with-graal


Note: $JAVA_HOME   points to your JDK8 boot JDK


Build Execution Time

The build execution time was captured on both Linux and MacOS and there was a small difference between running tests and not running tests:

Running the build with or without tests on a quad-core, with hyper-threading:

 real 4m4.390s
 user 15m40.900s
 sys 1m20.386s
 ^^^^^^^^^^^^^^^
 user + sys = 17m1.286s (17 minutes 1.286 second)


Similar running the build with and without tests on a dual-core MacOS, with 4GB RAM, SSD drive, differs little:

 real 9m58.106s
 user 18m54.698s 
 sys 2m31.142s
 ^^^^^^^^^^^^^^^ 
 user + sys = 21m25.84s (21 minutes 25.84 seconds)


Disclaimer: these measurements can certainly vary across the different environments and configurations. If you have a more accurate way to benchmark such running processes, please do share back.

Summary

In this post, we saw how we can build Graal and Truffle for JDK8 on both local and container environments.

The next thing we will do is build them on a build farm provided by Adopt OpenJDK. We will be able to run them across multiple platforms and operating systems, including building inside Docker containers. This binary is different from the GraalVM suite you download from OTN. Hopefully, we will be able to cover GraalVM in a future post.

Thanks to Julien Ponge for making his build script available for re-use and the Graal team for the support during the writing of this post.

Try FlexNet Code Aware Today! A free scan tool for developers. Scan Java, NuGet, and NPM packages for open source security and license compliance issues.

Topics:
graal ,tests ,jdk ,docker ,linux ,macos ,bash ,open source ,oss ,open source showdown

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}