Truffle
From APIDesign
I have spent last two years designing Truffle A set of APIs to build own language interpreter that gets special treatment by Graal (alternative version of HotSpot VM). As a result a well written interpreter can run faster than generated native code at the end.
Truffle is using sort of AsmJs approach: rather than complicating the JVM (like it was done with invokeDynamic instruction), it creates additional Java APIs that dynamic language vendors may use. The API patterns are then recognized by the enhanced HotSpot compiler to emit more effective code. All of that without modification to the JVM spec.
Truffle Ruby implementation is ten times faster than pure JRuby (which was based on invokeDynamic).
Contents |
Speeding Ruby Up: Ten times!
Ruby was always known to be very slow language. Even when the hype around Rails was on - e.g. around 2006, there was nobody who could make the language fast. The great news is that OracleLabs decided to demonstrate the power of their Truffle framework on Ruby and are working on a fast Ruby implementation. OracleLabs claim that their implementation is ten times faster than the standard Ruby.
I wanted to verify such claim. One thing is being faster in a benchmark, the other thing is to speed up real programs. That is why I decided to write my first Ruby program - the Sieve of Eratosthenes and as following video demonstrates, Truffle based Ruby is really faster:
Is Truffle based Ruby ten times faster? The video shows that standard Ruby can compute about 5000 of prime numbers in 20s on my computer. The Truffle version was able to compute 17000 of primes. For a while I believed that this implies three times speed up. Not bad, but far less than the claim of being ten times faster.
However once, while showing the demo, I forgot to kill the standard Ruby version. After three minutes I noticed that and to my surprise the standard version was still fighting with 15000th prime number - e.g. it takes at least 180s to compute what Truffle Ruby can in 20s. The explanation is easy - computing first thousands of primes is way easier that finding the next thousands ones. The sieve of Eratosthenes algorithm isn't linear. Only comparing the time to compute the same amount of primes makes sense. However such time comparison actually shows ten times speed up!
class Natural def initialize @x = 2 end def next return @x += 1 end end natural = Natural.new class Filter def initialize(number, filter) @number = number @filter = filter end def number @number end def filter @filter end def accept(n) filter = self loop do if (n % filter.number) == 0 return false end filter = filter.filter; break if filter == nil end return true; end end class Primes def initialize(natural) @natural = natural @filter = nil; end def next loop do n = @natural.next if (@filter == nil || @filter.accept(n)) @filter = Filter.new(n, @filter) return n; end end end end primes = Primes.new(natural) puts "Press Ctrl-D to start..." $stdin.read start = Time.now cnt = 0 res = "" puts "Working..." loop do p = primes.next res << "#{p}\n" cnt += 1 if cnt % 1000 == 0 puts res puts "Computed #{cnt} primes in #{Time.now - start} s" res = "" end end
Truffle gives Ruby the speed it always needed.
Get It for Free
When designing new language, one usually starts with an AST interpreter. When the language is ready for use, users find out it is great, but slow. So one starts to design a bytecode to speed things up. That helps, but still the execution is slow.
Truffle vision is different: write your AST interpreter using Truffle nodes API and we make it fast!
In addition to that we also give you a debugger for free! The following picture shows a debugger stopped in middle of simple language (an artificial language used for demo purposes) method. The IDE knows nothing about simple language (that is why syntax coloring is missing), but as it is easy to understand the general Truffle AST, the IDE can still provide enough valuable information in the debugger.
Please note that the name of the method is properly recognized and shown on top of the stack. Variables a and b and their values are properly shown as well.
Designing your own language? Do you want to spend time writing a debugger? If not, use Truffle and you'll get your debugger for free!
Debugger in NetBeans 8.1
NetBeans 8.1 and newer ships with support for debugging of Truffle languages. Here is a promotional video demonstrating how to use such feature, but you can try that too! Just get the most recent build of NetBeans, install the Truffle Debugging Support module and get the sources:
- Download latest daily build of NetBeans - tested on netbeans-trunk-nightly-201510210002-javase.zip downloaded from http://bits.netbeans.org/download/trunk/nightly/2015-10-21_00-02-28/zip/
- Install Truffle Debugging Support: Go to Tools/Plugins/Available Plugins and seek for Truffle, then install.
- Get the latest GraalVM build from the OTN: http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/index.html
Installing Maven Bits and Working with Sources
Assuming your GraalVM is installed in directory $GRAAL_VM, continue by installing essential Truffle binaries into your local Maven repository:
$ $GRAAL_VM/bin/maven_install_graalvm
and then you can work with the sources. First of all obtain them and switch to the correct (known to work at present time) revision:
$ hg clone http://source.apidesign.org/hg/truffledebugdemo/ $ cd truffledebugdemo $ hg up -C GraalVM-0.9
With the sources you can now use the command line or the IDE to work with them:
# compile: $ JAVA_HOME=$GRAAL_VM mvn clean install # execute $ JAVA_HOME=$GRAAL_VM mvn exec:exec factorial(5) = 120
The sample prints out value of factorial for five computed in four different (Java, Ruby, JavaScript and our testing simple language) languages.
Debugging from NetBeans
Make sure NetBeans is running on the GraalVM:
$ /netbeans8.1/bin/netbeans --jdkhome $GRAAL_VM
Open the project sources in the IDE (File/Open Project, select the truffledebugdemo directory). Open MixLanguages.java source file. Put breakpoint to MixLanguages.java line 37 that invokes the global factorial symbol and debug the project (Debug/Debug Project or press Ctrl-F5). Once the breakpoint is hit, you can step-into (F7), you'll be in JavaScript. If you continue stepping in you'll get into simple language and then also into Ruby. Values of local variables will be available. Enjoy: