InfoQ

InfoQ

News

My Bookmarks

Login or Register to enable bookmarks for unlimited time.

The content has been bookmarked!

There was an error bookmarking this content! Please retry.

LLVM and Ruby Roundup: llvmruby, yarv2llvm and regexpllvm, Rubinius

Posted by Werner Schuster on Oct 18, 2008

Sections
Development,
Architecture & Design
Topics
Ruby ,
Domain Specific Languages ,
Performance & Scalability ,
Scripting ,
Runtimes
Tags
Virtual Machines ,
Rubinius ,
Ruby1.9

LLVM contains the letters "VM", but it's actually a framework for building compiler backends. In short, it comes with an instruction set (immediate representation) and a backend which optimizes the code and generates native code for a host of platforms (x86, ARM, ...). One of the real world uses is in Apple's OpenGL JIT.

Llvmruby (llvmruby GitHub repository) is project by Tom Bagby. It provides Ruby bindings to LLVM. Llvmruby is well integrated into Ruby. For instance, this code adds an add instruction (codeblock is an instruction builder).

codeblock.bin_op(Instruction::Add, 41.llvm, 1.llvm)

Llvmruby opens Object and adds llvm to turn them into values LLVM can handle.

After following the instructions in the README (getting and compiling LLVM and compiling llvmruby), it's possible to start experimenting, eg. with irb. Here a sample session (with some snippets of code taken from the samples in the llvmruby project):

# Set up LLVM
>> require 'llvm'
=> true
>> include LLVM
=> Object
>> m = LLVM::Module.new("test_module")
=> ; ModuleID = 'test_module'
# Create a function type - the second argument is the method signature,
# ie. the return type and the types of the arguments
# In this case, there are no return values or arguments
>> type = Type::function(MACHINE_WORD, [])
=> #
>> f = m.get_or_insert_function("test", type)
=>
declare i32 @test()
# Create an LLVMBuilder object which allows to call methods and
# generate instructions
>> builder = f.create_block.builder
=> #
# Create an Add instruction - note how it's possible to pass regular Ruby Fixnums
>> ret = builder.bin_op(Instruction::Add, 41.llvm, 1.llvm)
=> #
>> fcode = builder.return(ret)
=> #
>> ExecutionEngine.get(m);
=> true
# Finally: execute the generated code
>> ExecutionEngine.run_autoconvert(f)
=> 42


For more information on using LLVM, the LLVM Tutorial shows how to implement a JIT for a simple language and more.


Two bigger examples using llvmruby come from Miura Hidek:

  • regexpllvm: turns regular expressions into LLVM code.
  • yarv2llvm: takes Ruby 1.9's opcodes (the 1.9 VM was called YARV before it was made the official Ruby 1.9 VM) and translates them to LLVM. It follows in the footsteps of similar projects, such as _why's Unholy (translates Ruby 1.9 opcodes to Python VM opcodes) or HotRuby (a Javascript interpreter for Ruby 1.9 opcodes). Unlike these projects, llvmruby is tightly integrated with the Ruby 1.9 VM, which offers interesting possibilities. Regexpllvm shows one possible way of speeding up the execution of code, ie. compiling a DSL down to LLVM opcodes. Other systems use this approach, eg. Java's XSLT implementation compiles XSLT stylesheets to JVM bytecode
    Another possibility: compiling Ruby code hotspots. At the moment, if a piece of Ruby code turns out to be a performance bottleneck, the pragmatic solution is to rewrite it in C (the idealist's solution is waiting for the Ruby VM to get a performance boost). With llvmruby, another option is possible: compiling the Ruby code to LLVM, ie. using yarv2llvm as a booster. Whether this provides the necessary performance boost depends on the code, though.


Llvmruby allows to experiment with LLVM without having to touch any C++ and also allows to do so incrementally with irb. A useful property, eg. for contributors to Rubinius (the project plans to use LLVM) to prototype ideas. The Rubinius team has been busy rewriting the VM in C++ and cleaning up some internals. This work is currently happening on the CPP branch of Rubinius in the Git repository, which also contains LLVM as an external library. The C++ branch should soon turn into the master branch. According to some recent Twitters, Rubinius has regained the ability to run a lot of Ruby code with the new C++ VM. Eric Hodel twittered this week

Rubinius' new vm can now run the core specs without crashing


Evan Phoenix recently reported:

Huzzah! IRB works again under the new Rubinius C++ VM!


How would you use LLVM with Ruby?

libjit by Roger Pack Posted
Re: libjit by Paul Brannan Posted
  1. Back to top

    libjit

    by Roger Pack

    There's also libjit + ruby 1.9 [rumble.withoutpenandink.com:4559/]
    Note that libjit is now LGPL 2.1 so that's nice. I'm not sure how the speed compares with LLVM.

    Could someone please port psyco to Ruby for me? <tongue in cheek>
    -=R</tongue>

  2. Back to top

    Re: libjit

    by Paul Brannan

    Ludicrous has been around for over a year now and has the ability to selectively JIT-compile methods on both 1.8 and 1.9 (which reduces risk of a bug in the compiler affecting the entire application). I don't know how the speed compares to an LLVM-based solution either, but I suspect that though LLVM should generate better code, the difference should be minimal, because the bottlenecks are in places like block invocation and method dispatch. Whichever compiler optimizes these better will perform better in real-world applications.

Educational Content

Jesper Boeg on Priming Kanban

In this interview, Jesper Boeg, author of the new InfoQ book – Priming Kanban, discusses the keys to using Kanban effectively, and how to get started if you are currently using other approaches.

New-age Transactional Systems - Not Your Grandpa's OLTP

John Hugg discusses high volume transaction processing applications with high and low frequency profiles, and how VoltDB can be used for that purpose.

Cool Code

Kevlin Henney examines code samples to see what can be learned from them starting from the premise that one won’t write great code unless he knows how to read it.

Collaboration: At the Extremities of Extreme

Jason Ayers share the observations he made watching a team of developers collaborating in real time on the same code base, pushing XP, pair programming and continuous integration to their extremes.

Yesod Web Framework

Michael Snoyman presents Yesod, a web framework written in Haskell and containing a web server, templating, ORM, libraries (templating, gravatar, etc.).

Transactions without Transactions

Richard Kreuter and Kyle Banker on how to avoid classical RDBMS transactional systems by using compensation mechanisms, transactional messaging or transactional procedures.

Attila Szegedi on JVM and GC Performance Tuning at Twitter

Attila Szegedi talks about performance tuning Java and Scala programs at Twitter: how to approach GC problems, the importance of asynchronous I/O, when to use MySQL/Cassandra/Redis, and much more.

10 tips on how to prevent business value risk

One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.