So there's this shiny new Java virtual machine called GraalVM I've already blogged about last Spring. In the meantime, Graal's managed to make an impact on the Java universe.The holy grail by Erich Ferdinand, published under a CC BY 2.0 license. Most prominently, there's the flagship project called Twitter. They're using GraalVM for some time now. They're running their Scala microservices on Graal.
Graal has also arrived in a more conservative business world. It seems to be particularly attractive to cloud-native applications. Just think about Lambda functions. So it's time to revisit GraalVM. Mind you; it's 2020. Is it time to abandon your good old Java virtual machine and to move to something new?
Let's have a look at the definition coined by my co-author Karine:
Wow. That's quite a chunk to swallow. GraalVM has a lot in store for you.
Let's examine it piece by piece. That'll take a while. This article is a high-level introduction to an eight-part series. Nine parts, if you count our December article on Truffle. And we didn't even start to cover the database bit. It's fascinating, but we're not sure we'd like to propagate programming Java in the database. It doesn't seem a best practice in the age of microservices and cloud-native applications. Nonetheless, it's a powerful tool, so maybe we'll explore it soon.
What is Graal?
First of all, Graal is a research project hosted at the Oracle labs. Since 2012, the development team has published 60+ papers on GraalVM. So the first answer to our question is: GraalVM is simply a remarkably long-running academic project. A successful one, at that.
Did you notice our list of languages didn't include Java? That's not a mistake. Truffle's written in Java, but it's not meant to run Java.
GraalVM as a plug-in replacement to the JVM
Then there's the other part of the GraalVM project. It's the part currently stirring a lot more excitement. GraalVM is a plug-in replacement for the Java virtual machine, running Java, Scala, Kotlin, and all the other languages running on Java bytecode. Since 2019, GraalVM is production-ready on Linux. Version 20.1.0 also claims to support Windows fully. So we can the high claims to the test. We'll do that in the third part of the series.
Ruby is a pleasant surprise, indeed. GraalVM runs our synthetic Ruby benchmark 30% faster than Ruby 2.7.0. Of course, there are two other Ruby implementations out there, and we didn't test them yet. Nonetheless, 30% is a promising start. Plus, we're positive there's headroom for improvements.
From a Java programmer's perspective, things are a bit more down-to-earth. Generally speaking, the performance of the GraalVM is roughly on par with Oracle's HotSpot compiler. Not bad, but not that exciting, either. By the time you're reading this, things may have improved - we're talking about GraalVM 20.1.0. In the long run, we're positive GraalVM is going to run circles around the traditional JVM. But it's not going to happen in the short term. Java is one of the most heavily optimized programming languages, and it's still being optimized, so beating it is a hard call. We believe it's possible because GraalVM is a fresh, new take, which doesn't have to carry the burden of 20+ years of optimization. Currently, the source code of GraalVM is pretty straight-forward - at least compared to the source code of the C++ JVM. At least, that's what we're told, and that's what fuels our optimism.
To be fair, we're impressed that the Angular CLI works flawlessly at all. It requires the entire ecosystem of node.js. GraalVM ships with a working copy of node.js and npm. Even better, it's compatible with ECMAScript 2019. Even if it may be slow today, that's a remarkable achievement. Plus, the project team has declared a bold goal: they want to reach the same peak performance as node.js offers.
Being technicians, we're impressed with all that. Try as we might, we couldn't do that! And we don't suffer from a lack of self-esteem. There's that. But all this technological excellence won't convince your CEO to run your cash-cow application on Graal. If GraalVM is going to be a thing, it has to prove its value.
Nonetheless, GraalVM raised a lot of attention among the media. What are the drivers behind the success of GraalVM?
Drivers: performance and maintainability
Rewriting the JVM compiler in Java opens a new window of opportunity. The bet is that countless Java programmers are going to spend some time with the GraalVM, find some weaknesses, and contribute bug fixes and improvements. The young age of the GraalVM makes that a walk in the park. By contrast, both the V8 engine and the HotSpot compiler suffer from decades of optimizations. We're told it's not easy to improve anything without breaking something else. If you've already worked with a large enterprise application, you know the problem. In the business world, microservices come to the rescue. In the JVM worlds, it's GraalVM. Based on new ideas, it's a fresh take on an old problem. Plus, it has been written with optimization and with being extended in mind.
That's probably the reason why Twitter adopted GraalVM. They're running their production code on Scala. That's a language compiling to the JVM bytecode. Too bad, the bytecode has been developed specifically for Java. Scala introduces new concepts that don't match perfectly to the Java bytecode. Of course, Twitter still uses the same bytecode, but they've tweaked GraalVM with Scala-specific optimizations.
Things are more evident in the case of Ruby and R. These languages aren't JVM languages. Of course, there's the JRuby project compiling to Java bytecode. That's a remarkably successful project. However, the Graal implementation of JRuby tackles the problem from a different angle. It's an interpreter running on the Truffle framework, which is an implementation of the Futumara projection.
Truffe - the Futumara projection come true
We've explained the Futumara projection in much detail in an article dedicated to Truffe. At this point, suffice it to say it's a clever approach to writing a compiler, taking the sting out of writing a compiler. In a nutshell, the idea is once your base language uses an optimizing Just-in-Time compiler, it compiles and optimizes everything. If you write an interpreter, this interpreter is compiled and optimized by the Just-in-Time compiler, too. And if both you and the compiler are clever, your interpreter runs your application every bit as fast as if you'd written a traditional compiler. It's just a lot simpler. Everybody and the grandma can write an interpreter. Writing a good compiler is a piece of art.
The beauty of this approach is that it's both an interpreter and what they call a compiler-compiler. After a warmup phase, Graal compiles Ruby to native machine code that's more or less on par with hand-optimized Assembly code. The downside is you can always fine-tune the Assembly code far beyond anything Graal can do, no matter how much it evolves in the future.
However, in the real world, things look a bit different. Optimizing code - and Assembly code in particular - takes a lot of developer effort. It's more efficient to write an interpreter everybody can understand, maintain, and optimize, and to have it compiled to Assembly code by Truffle and the GraalVM. Both have been written in Java, so chances are many people contribute optimizations to these projects, too.
Oh, and don't confuse the Futumara projection with Futurama. Yoshihiko Futamura is a Japanese scientist who's invented his projection in the early 70s. Roughly fifty years after his scientific groundwork, the idea materializes in the business world.
Update February 04, 2020:
Thomas Würthinger, GraalVM's project lead, reports in an interview in December 2019 that the team is currently installing an advisory board populated by company representatives. On the one hand, this sounds like a bureaucratic process making it difficult for individual developers to provide a pull request. On the other hand, this indicates big companies are interested in improving GraalVM. Maybe this is a good omen, backing our hope GraalVM has more in store for us.
... and carbon footprint
By the way, raw performance is one thing. It's what we used to look at when computers were slow. Now we've run into another barrier. From an economic perspective, energy consumption costs money, and from a more global perspective, it adds to the carbon footprint of your company. That, in turn, has become important to marketing. It's easier to sell you're product if it's climate-friendly.
Write your own programming language!
In the academic world, there's probably another driver to the success of Graal. Truffle enables you to write a new programming language. We're curious where this leads.
For example, dynamic typing has been made famous by Groovy and Ruby. Streams and functional programming become a real thing with the advent of Scala and Groovy. Later, Kotlin and Ceylon picked up the idea, before it finally made its way into Java 8. Compile-time null-safety came to the Java universe with Kotlin and Ceylon. Scala demonstrated how to use the immutability pattern without the pain. That, in turn, enabled Akka to unleash reactive programming and the power of your multi-core CPU.
Academic and experimental programming languages as innovation labs
We don't know much about the early discussions about enums, value types, and autoboxing. Still, by now, you see the pattern: before introducing a game-changer to a language used by millions of developers, it's a good idea to play around with the idea in a less known language. Developers are much more tolerant of breaking changes if they know they're working on the bleeding edge. They feel honored to be able to contribute their ideas and their input to the new language.
Mainstream-languages are a completely different piece of cake. For example, try to get rid of type erasure in Java. We daresay, that's impossible. You know, type erasure is one of the great ideas - and it's been great indeed! - that solved a lot of problems at the time. The problem is it removed a lot of headaches from the language designers. After publishing the feature, it turned out to cause problems in the wild. Most developers won't even notice, but type erasure is painful to framework designers. It'd been better to try this idea in a small language, migrate something like Gson or Jackson to it, and learn about the disadvantages of type erasure. As far as we can see, that's what the Java language designers are doing nowadays.
The ease of implementing a language with Truffle makes playing around with new concepts a lot easier. Truffle cuts the time it takes to write a decent language in half. Plus, Truffle's successful implementation of the Futumara projection gives your pet language a significant performance boost. That, in turn, is a key to convince developers to pick up your language.
Cloud computing, the main driver
And yet, we've still didn't mention the biggest key driver. The unique selling point of the GraalVM is its AOT compiler. After more than two decades, we can finally compile Java to native machine code. Even more important, nowadays we've got a use-case requiring native code. The most important being Amazon Lambda functions (and their siblings offered by other cloud providers).
The exciting bit about Lambda functions is you only pay-per-use. You only pay if your code runs. If nobody calls your service, you don't pay for it. To make this a compelling business case for the cloud provider, they have to shut down your virtual machine when nobody uses it. That, in turn, means your customers often suffer from a cold start delay. According to many slides and conference talks we've seen, that amounts to three seconds for a simple Spring Boot service, give or take a few. Too much in a world dominated by search engines penalizing sluggish web sites. Big webshops report a juice effect on sales if their web page slows down one-tenth of a second. Where does this leave your cold-starting Spring Boot service?
The AOT compiler solves that. Traditionally, Java starts slow because it has to load several thousand classes. However, your simple CRUD application only uses a small fraction of these classes. You don't need the full power of Spring Boot to respond to a GET request. Three lines of code do the trick just as well, as frameworks like Helidon, Micronaut, or Express.js (in the Node.js world) show.
The AOT compiler boils down your code to what's necessary and emits pre-compiled machine code. If you're lucky, that's just the three lines of Helidon code, plus the infrastructure required to support these three lines. But nothing beyond that.
Even better, that code is ready-to-use, without requiring any expensive infrastructure to load and initialize. Add a cloud-native framework like Quarkus or Helidon to the equation, and you end up with Lambda functions responding withing 0.005 seconds, according to some marketing slides we've seen. We'll put this to test in the final part of this series. Stay tuned!
During the last year, a few developers began to embrace GraalVM. For instance, Michiel Borkent has created babashka. It's a Clojure interpreter, compiled as a native image by GraalVM. It integrates seamlessly in your Linux or macOS shell, allowing you to replace the bash commands with Clojure code. Judging by the project's popularity - 1500 GitHub stars in roughly a fourteen months - it's hit a sweet spot.
Being able to compile to native executables also seems to be a thing in the JavaFX community. You don't have to install Java, nor do you have to install JavaFX to run a JavaFX application compiled natively. That takes the sting out of installing such an application on thousands of PC in your company.
GraalVM also seems to fuel a whole new wave of microservice frameworks. For instance, there's Quarkus. We'll cover it in some detail in a dedicated article. In a nutshell, Quarkus is a collection of industry-standard frameworks, plus extensions enabling these frameworks to generate native binaries.