Archive for November, 2009

Making Sense out of Slow Rubygems Startup

Saturday, November 21st, 2009

JRuby is pretty fast these days, in most cases it is faster than MRI. JRuby is especially good at handling long-lasting repeating tasks (on server side). But one thing where JRuby is not blazingly fast is during the startup. Well, actually, JRuby starts up within 0.5 second, which is really nice for the JVM-based implementation. But as soon as rubygems comes into play, the situation gets worse.

So, I spent some time trying to understand why just loading the rubygems package eats up a second or two more. Well, it turned out that rubygems loads almost entire standard library, which is crazy! Sure, this is a bit of exaggeration, but still, let’s see, shall we?

First, fileutils are loaded, 100+ms passed, then rubygems tries to figure out where is the system-level config file, and for that on Windows it uses Win32API library (!!!), which in turn requires FFI (the native interface). Ka-ching, 300+ ms for that. Then, we need to read the configs and stuff, this requires YAML parser, and in JRuby that means loading Yecht, 350+ ms more. Next, JRuby provides some extension of rubygems functionality, like possibility to load gems from the JAR files, and for that we need some classpath magic and the ‘uri’ library. To obtain the JRuby’s classloader, we need to require ‘jruby’, which in turn requires ‘java’, and the java library loads the whole bunch of extra functionality (which we are not using here, btw), that adds up to 400 ms. So, we barely loaded the rubygems library, but already consumed 1200ms of time, or more.

Take a look at the following picture that shows the times to load all those libraries:

Rubygems

As you see, loading rubygems themselves is not that time consuming, most of the time is spent in loading the dependencies. There are some low-hanging fruits here, like lazily loading the ‘uri’ library. I also don’t like that rubygems loads the Win32API and the whole FFI stuff, removing that would also eliminate quite a lot of startup time. Loading the whole bunch of java integration magic in order to only be able to obtain the JRuby classpath also seems to be overkill. All those tweaks, if implemented, might actually cut the rubygems startup time in half. We’ll see.

UPDATE: Wayne Meissner has just tweaked the loading of Win32API, and I adjusted JRuby-specific rubygems tweaks to lazily load the ‘uri’. So, the loading of rubygems is already about 200ms faster than it was yesterday! 8-)

UPDATE#2: Here’s the log of rubygems loading timings in JRuby, in easy to read text format: http://gist.github.com/240322.

How to build latest Ruby on Windows

Monday, November 16th, 2009

So you want to build the latest Ruby on Windows. Maybe, you’re working on some new RubySpec tests or would like to see what’s coming with Ruby 1.9.2. At any rate, building Ruby on Windows is much easier than I originally thought, and you don’t even forced to install Microsoft compilers at all! Good folks over RubyInstaller project made all the hard work for you already, setting up the environment to build with MinGW compiler. So, the receipt is as follows:

  • Clone the RubyInstaller repository: git clone git://github.com/oneclick/rubyinstaller.git
  • In that cloned directory, invoke: rake ruby19 CHECKOUT=1 TRUNK=1

And you’re done! That rake command will fetch the MinGW compiler all the required libraries, it will checkout the latest Ruby source from the subversion repository, then it will configure and build it.

Minimal requirements for you system before you start: Subversion, Ruby 1.8.6 installed and somewhere on your PATH. I recommend the one from RubyInstaller (tested with 1.8.6 p383). That’s about it. The Ruby from RubyInstaller comes with rubygems preinstalled, so obtaining the Rake is as trivial as: gem install rake.

Entire setup would take you a couple of minutes. Then, the build… That would take longer, expect it to run for at least 20-30 minutes. And this is not as fast as 30 seconds recompile of entire JRuby tree. :)

P.S. Big thanks to Luis Lavena for helping out with the debugging the build failures and reporting them to Ruby-core so that they are all now fixed.

Proper way to detect Windows platform in Ruby

Tuesday, November 3rd, 2009

I’ve seen this time and again, the Windows platform detection in Ruby is typically done like this: RUBY_PLATFORM =~ /mswin/. THIS IS WRONG! First, there is also mingw version of Ruby on Windows. So, folks started to use the updated check pattern: RUBY_PLATFORM =~ /mswin|mingw/. THIS IS WRONG TOO! There are other implementations of Ruby, like JRuby and IronRuby. And in JRuby the RUBY_PLATFORM value is “java”, it is platform-independent value, expressing one of the core JRuby properties – it is built on top of Java platform. Plus, every time new implementation comes along, all old checks would be obsolete once again.

Now, the proper way to check the Windows platform, which is surprisingly less-known. Use rbconfig!

require ‘rbconfig’

WINDOZE = Config::CONFIG[‘host_os’] =~ /mswin|mingw/

This will work for x32 and x64 versions of Ruby, for mingw-based Ruby, for IronRuby, and for reasonably fresh JRuby (1.3.1, 1.4, 1.5+) as well. Please, please, update your sources!