Time to experiment with GraalVM!
Having a rudimentary understanding of what the fuss is about, I stopped to consider what I could try out. How can we develop faster? Why, make the IDE faster of course! An IntelliJ taking less memory and running faster? I thought I’d have to upgrade my laptop!
So, I set about running IntelliJ with the GraalVM and then to compile it to a native executable to see (1) If I could; and (2) what the impact would be.
Step 1 – Running IntelliJ on the GraalVM
Having already set up GraalVM on my host Mac, switching IntelliJ over to use it was pretty straight forward. With IntelliJ running, use the “Find Action” command (Help: Find Action…” from the menu), Shift-Cmd-A for me on the keyboard. Enter “Switch Boot JDK”. Configure this to point to your GraalVM home directory.
The first thing you will likely notice is that the menu bar for IntelliJ no longer works! It is time to learn those keyboard shortcuts! Instantly, its faster to run IntelliJ on the GraalVM!! Helpfully, you can still see the names of the editor commands that the menu runs, so you can always use “Find Action” to run it.
If something goes horribly wrong and you can no longer use IntelliJ, then you need to switch back to your old JDK by hand. When you override the default JVM, IntelliJ creates a file to store the path to the JVM you assign. It is a simple matter to delete this file, allowing IntelliJ to return to the default. On my Mac, the path (it will be different for you I’m sure!) was:
Assuming that things went well, the rebooting IntelliJ will result in it using the GraalVM.
So, is it any faster? I can’t say. I can’t be sure I notice a difference in IntelliJ, and I have no performance tests at my disposal to tell me. Losing the main menu bar does force me to learn (and create) more keyboard shortcuts. I’m already in pretty good shape there though, so the speed improvement will be fairly marginal.
Step 2 – Compiling to a native executable
With visions of the IntelliJ splash screen being visible for only a fraction of a second, I set out to compile it to a native executable. Not needing the JVM (or the GraalVM for that matter) could potentially give a noticeable speed boost.
The first task was to find out how to run IntelliJ from a java command. It is fairly easy to start IntelliJ from the command line, but from a java command is something else.
Step 2.1 – IntelliJ Ultimate
I couldn’t find a way to expose the java command that runs IntelliJ Ultimate. I tried all the tricks in the following sections to no avail. I’d be delighted if someone can leave me a tip!
Step 2.2 – IntelliJ CE
I had a look at the github repository to see if the CE edition held out any hope. Surely there would be instructions on how to run it on java. How else could the CI pipeline work? Well, it turns out that in order to run IntelliJ CE from code, you need to run it from IntelliJ. It may sound a bit “chicken and egg”, but if you already have a chicken, then why not?! I didn’t go so far as to work out how a CI pipeline might work – I was more interested in GraalVM after all!
By following the readme, I was able to run CE from within IntelliJ on my Mac. As the host IntelliJ was already running on GraalVM, so was CE.
The next thing is to work out what the java command is. Running “ps -ax | grep java” with only the host IntelliJ running gives a list of the java processes involved with that. By taking those process IDs and excluding them when also running CE, you should be left with the java processes involved with running CE:
ps -ax | grep IntelliJ | grep -v <PID 1> | grep -v <PID 2> ...
Look through these process, and you should see one running the com.intellij.idea.Main class. That java command runs IntelliJ CE. Copy that command and place it into a text editor for safe keeping. Test it out by closing all the IntelliJ(s) you have running, then running that (somewhat large!) command from the terminal. If IntelliJ starts up then you’ve hit gold!
The next step is to compile the java application to a native image. To re-iterate – we’re going to compile it to machine code. No JVM will be needed to run it! Or at least, that was the plan…
Replacing the java command from the previous step with Graal’s “native-image” executable will attempt to build this native image. You will probably need the full path. You will need to remove some of the java arguments though as “native-image” doesn’t recognise them:
- Remove all -X arguments
- Remove the call to “javaagent”s
We should now be able to run the (large) Graal native-image command.
I had two errors, stating that there were problems building the native image, and that it would instead create a “fallback” image. Some of the code in CE prevented the native image compiler from doing its magic, so it reverts to needing the JVM. However, it still created an executable (albeit only 2.3MB).
I was able to run this executable from the command line and sure enough, CE started up. The JVM is still needed though, and I was unable to discern any improvement in speed.
Disappointingly, I can’t say there has been a speed increase. Maybe time will tell and perhaps JetBrains might release their products built to run as native executables! Meanwhile, I still need to consider a new laptop if I want to go faster. I’ll update this article if I find further information.