Aug
4
A faster Ruby on Windows is possible (benchmarks for 4 implementations inside)
Filed Under .NET, Ruby, Ruby Benchmark Suite | 22 Comments
In yesterday’s post I compared IronRuby 0.9, Ruby 1.8.6 (from the One-Click Installer) and Ruby 1.9.1 (downloaded from the official site) against one another. IronRuby did great, but the discussion in the comment section quickly veered towards what version of the One-Click Ruby Installer should have been used.
I justified my choice of using the “old” One-Click Installer, by the fact that I wasn’t aware of official releases of the new installer. As well as that the old One-Click Installer is the most widely downloaded version. Very few people are familiar with the upcoming version of the project. This point is about to change.
Luis Lavena took over the One-Click Installer project and has been working on the next version (RubyInstaller from now on), the aim of which is to replace the One-Click Installer by building Ruby 1.8 and 1.9 with MinGW and GCC. In theory, this brings performance gains on Windows to the table, and gets rid of having to use Visual C++ 6 (a “ten year old compiler”) to build Ruby and other native gems. The project also strives to be lighter by bundling fewer (unnecessary) gems for Windows users.
There’s no doubt that in the long run, this new project will become the de facto standard for Windows, but the questions on everyone’s mind are, should I bother with it now? How much of a performance boost are we talking about here? 10%? 20%? Let’s find out.
In this follow up article I’m going to compare the performance of Ruby 1.8.6 from the One-Click Installer (mswin32), Ruby 1.8.6 from RubyInstaller (mingw32), Ruby 1.9 (mswin32) downloaded from the Ruby-Lang.com site, and Ruby 1.9 from the RubyInstaller project (mingw32) against one another. I’ll copy and paste part of the setup and disclaimer from yesterday’s post, for those who haven’t read it. Feel free to skip this part if you wish.
Setup
- The benchmarks were run within a virtual machine with 2 GB of DDR3 RAM and a 2.66 GHz Intel Core 2 Duo processor. The operating system adopted was Windows XP SP3 (32 bit) with the .NET Framework 3.5 SP1 installed.
- Here I employed a large subset of the current Ruby Benchmark Suite project. The source code for all of the benchmarks is available within the repository.
- The best time out of five runs is reported for each benchmark. When the results report a Timeout, it means that more than 300 seconds were required for a single iteration and was therefore interrupted. Conversely, N/A means that a test that was compatible for the given implementation was not available or the setup on my machine was lacking the required libraries to execute it (1 test affected).
Disclaimer
- An attempt has been made to improve the quality of the tests. Some of them may be more representative of realistic workloads, but most of them remain micro-benchmarks. They are indicative of how these implementations compare, but cannot be viewed as a guarantee of how they will actually affect your own programs.
- There are lies, damned lies, and statistics.
Benchmark results
The table/image below shows the times for each benchmark, for Ruby 1.8.6 (mswin32), Ruby 1.8.6 (mingw32), Ruby 1.9.1 (mswin32), and Ruby 1.9.1 (mingw32). In the table I used (RI) as shorthand for RubyInstaller to indicate mingw32 versions.

Red values are errors, timeouts and inapplicable tests. Green, bold values indicate better times than what Ruby 1.8.6 (mswin32) delivered. A pale yellow background indicates the best time for a given benchmark. Total time is the run-time for the subset of benchmarks that were successfully executed by all four implementations. Timeouts have been included this time around. Each timeout has been counted as an additional 300 seconds.
The total runtime (including timeouts) is summarized in the chart below:

Conclusion
Wow! Ruby 1.8.6 (mingw32) improves from 3% to 664% (depending on the test), over the current One-Click Installer. The geometric mean of the ratios (read “on average”) tells us that it was about 283% faster. The Ruby 1.9.1 version provided by the RubyInstaller was slower than the mswin32 version in a couple of tests, but faster everywhere else. How much faster? Up to 342% faster, with an average (again calculated through the geometric mean of the ratios) of a 77% increase in speed.
These finds prompt me to ask, what are we waiting for? You know how unresponsive Ruby is on Windows, and how tests take forever to execute? These mingw32-based releases may very well solve this. And incidentally the bar has been raised for IronRuby as well. I formally invite the Ruby on Windows community to embrace these two projects.
Aug
3
Comparing the performance of IronRuby, Ruby 1.8 and Ruby 1.9 on Windows
Filed Under .NET, Ruby, Ruby Benchmark Suite | 19 Comments
In my latest article I discussed the importance of JRuby as a means of introducing Ruby to the Enterprise world. Most of the companies that belong to this ecosystem are Java based, but we cannot forget that a sizable portion of them are Microsoft-centric. Within these companies, Ruby will be far more welcome if a .NET implementation is available. The answer to this need is sufficiently fulfilled by IronRuby (version 0.9 was just released).
IronRuby has been progressing fast lately. First came support for Rails and then, with this release, a great deal of effort has been placed on improving performance. In the past, IronRuby was all but fine-tuned. In fact, it was several times slower than Ruby MRI, as the team worked on improving compatibility with Ruby 1.8 and mostly ignored performance.
In this article I’m going to provide some performance results for IronRuby 0.9 on Windows, which I’m sure will interest readers of this blog as well as of my book. Before revealing all the details, let’s start with the setup and a disclaimer. Please read through it carefully, because the old, trite comments about how “micro-benchmarks are useless” won’t be published. We’ve already been there, folks. Thank you all for your understanding.
Setup
- The benchmarks were run within a virtual machine with 2 GB of DDR3 RAM and a 2.66 GHz Intel Core 2 Duo processor. The operating system adopted was Windows XP SP3 (32 bit) with the .NET Framework 3.5 SP1 installed.
- Here I employed a large subset of the current Ruby Benchmark Suite project. The source code for all of the benchmarks is available within the repository.
- The best time out of five runs is reported for each benchmark. When the results report a Timeout, it means that more than 300 seconds were required for a single iteration and was therefore interrupted. Conversely, N/A means that a test that was compatible for the given implementation was not available (2 tests) or the setup on my machine was lacking the required libraries to execute it (1 test).
- I realize that there is a MinGW One-Click Installer effort that may improve the performance of Ruby on Windows. Here however, I used the regular One-Click Installer as it is the most common one (it’s been downloaded almost 3.5 million times so far). For Ruby 1.9 I used the binary provided by the download page on the official Ruby site.
Disclaimer
- An attempt has been made to improve the quality of the tests. Some of them may be more representative of realistic workloads, but most of them remain micro-benchmarks. They are indicative of how IronRuby compares to MRI (Ruby 1.8) and KRI (Ruby 1.9) performance-wise, but cannot be viewed as a guarantee of how this will actually affect your own programs.
- I didn’t calculate a RubySpec completeness score for IronRuby. That said, IronRuby 0.9 should be a fairly complete implementation of Ruby 1.8.
- There are lies, damned lies, and statistics.
Benchmark results
The table below shows the times for each benchmark, for IronRuby 0.9, Ruby 1.8.6 (2008-08-11 patchlevel 287) and Ruby 1.9.1p0 (2009-01-30 revision 21907):
| Benchmark File | # | Ruby 1.8.6 | IronRuby | Ruby 1.9.1 |
| macro-benchmarks/bm_gzip.rb | 100 | Timeout | IOError | N/A |
| macro-benchmarks/bm_hilbert_matrix.rb | 20 | 1.891 | 0.453 | 0.125 |
| macro-benchmarks/bm_hilbert_matrix.rb | 30 | 7.422 | 1.719 | 0.656 |
| macro-benchmarks/bm_hilbert_matrix.rb | 40 | 21.500 | 4.625 | 2.266 |
| macro-benchmarks/bm_hilbert_matrix.rb | 50 | 56.765 | 10.031 | 5.109 |
| macro-benchmarks/bm_hilbert_matrix.rb | 60 | 111.859 | 18.781 | 11.297 |
| macro-benchmarks/bm_norvig_spelling.rb | 50 | Timeout | 41.313 | 31.453 |
| macro-benchmarks/bm_sudoku.rb | 1 | 43.734 | Timeout | 6.313 |
| micro-benchmarks/bm_app_factorial.rb | 5000 | 1.328 | 0.063 | 0.266 |
| micro-benchmarks/bm_app_fib.rb | 30 | 6.156 | 0.594 | 0.813 |
| micro-benchmarks/bm_app_fib.rb | 35 | 74.125 | 6.922 | 9.344 |
| micro-benchmarks/bm_app_mandelbrot.rb | 1 | 11.953 | 6.922 | 0.641 |
| micro-benchmarks/bm_app_pentomino.rb | 1 | Timeout | 59.938 | 75.859 |
| micro-benchmarks/bm_app_strconcat.rb | 1.5M | 30.469 | 2.141 | 4.813 |
| micro-benchmarks/bm_app_tak.rb | 7 | 5.516 | 0.531 | 0.578 |
| micro-benchmarks/bm_app_tak.rb | 8 | 15.609 | 1.484 | 1.703 |
| micro-benchmarks/bm_app_tak.rb | 9 | 45.843 | 3.953 | 4.531 |
| micro-benchmarks/bm_app_tarai.rb | 3 | 19.985 | 1.844 | 2.156 |
| micro-benchmarks/bm_app_tarai.rb | 4 | 19.796 | 2.219 | 2.656 |
| micro-benchmarks/bm_app_tarai.rb | 5 | 24.235 | 2.688 | 3.063 |
| micro-benchmarks/bm_binary_trees.rb | 1 | Timeout | 53.078 | 37.375 |
| micro-benchmarks/bm_count_multithreaded.rb | 16 | 0.297 | 0.266 | 0.328 |
| micro-benchmarks/bm_count_shared_thread.rb | 16 | 0.250 | 0.188 | 0.203 |
| micro-benchmarks/bm_fannkuch.rb | 8 | 3.625 | 0.344 | 0.563 |
| micro-benchmarks/bm_fannkuch.rb | 10 | Timeout | 40.750 | 65.438 |
| micro-benchmarks/bm_fasta.rb | 1M | 192.937 | 23.703 | 35.234 |
| micro-benchmarks/bm_fractal.rb | 5 | 43.172 | 4.672 | 5.781 |
| micro-benchmarks/bm_gc_array.rb | 1 | 228.672 | 32.031 | 59.828 |
| micro-benchmarks/bm_gc_mb.rb | 500K | 8.109 | 1.109 | 0.469 |
| micro-benchmarks/bm_gc_mb.rb | 1M | 16.172 | 2.391 | 1.016 |
| micro-benchmarks/bm_gc_mb.rb | 3M | 44.953 | 6.906 | 2.938 |
| micro-benchmarks/bm_gc_string.rb | 1 | 47.937 | 25.250 | 11.938 |
| micro-benchmarks/bm_knucleotide.rb | 1 | 9.625 | 2.906 | 2.016 |
| micro-benchmarks/bm_lucas_lehmer.rb | 9689 | 122.672 | 18.125 | 36.250 |
| micro-benchmarks/bm_lucas_lehmer.rb | 9941 | 156.750 | 19.625 | 39.391 |
| micro-benchmarks/bm_lucas_lehmer.rb | 11213 | 179.915 | 28.844 | 61.063 |
| micro-benchmarks/bm_lucas_lehmer.rb | 19937 | Timeout | 159.078 | Timeout |
| micro-benchmarks/bm_mandelbrot.rb | 1 | Timeout | 65.781 | 81.766 |
| micro-benchmarks/bm_mbari_bogus1.rb | 1 | 0.031 | 40.406 | 8.781 |
| micro-benchmarks/bm_mbari_bogus2.rb | 1 | 0.156 | Timeout | N/A |
| micro-benchmarks/bm_mergesort_hongli.rb | 3000 | 25.282 | 3.531 | 6.031 |
| micro-benchmarks/bm_mergesort.rb | 1 | 24.735 | 3.906 | 3.219 |
| micro-benchmarks/bm_meteor_contest.rb | 1 | 147.704 | 19.713 | 19.781 |
| micro-benchmarks/bm_monte_carlo_pi.rb | 10M | 79.406 | 5.109 | 20.672 |
| micro-benchmarks/bm_nbody.rb | 100K | 37.625 | 8.281 | 10.938 |
| micro-benchmarks/bm_nsieve_bits.rb | 8 | 69.656 | 33.156 | 6.531 |
| micro-benchmarks/bm_nsieve.rb | 9 | 58.344 | 5.453 | N/A |
| micro-benchmarks/bm_partial_sums.rb | 2.5M | 93.391 | 10.797 | 26.422 |
| micro-benchmarks/bm_pathname.rb | 100 | Timeout | Timeout | Timeout |
| micro-benchmarks/bm_primes.rb | 3000 | 21.359 | 9.594 | 0.031 |
| micro-benchmarks/bm_primes.rb | 30K | Timeout | Timeout | 0.469 |
| micro-benchmarks/bm_primes.rb | 300K | Timeout | Timeout | 5.281 |
| micro-benchmarks/bm_primes.rb | 3M | Timeout | Timeout | 100.406 |
| micro-benchmarks/bm_quicksort.rb | 1 | 51.046 | 11.594 | 8.703 |
| micro-benchmarks/bm_regex_dna.rb | 20 | 181.172 | 21.188 | 11.938 |
| micro-benchmarks/bm_reverse_compliment.rb | 1 | 61.875 | 48.469 | 138.047 |
| micro-benchmarks/bm_so_ackermann.rb | 7 | 2.234 | 0.563 | 0.484 |
| micro-benchmarks/bm_so_ackermann.rb | 9 | 50.000 | 14.938 | 9.281 |
| micro-benchmarks/bm_so_array.rb | 9000 | 26.328 | 8.984 | 10.781 |
| micro-benchmarks/bm_so_count_words.rb | 100 | Timeout | 60.688 | 42.250 |
| micro-benchmarks/bm_so_exception.rb | 500K | 78.125 | Timeout | 32.672 |
| micro-benchmarks/bm_so_lists_small.rb | 1000 | 13.906 | 4.250 | 3.172 |
| micro-benchmarks/bm_so_lists.rb | 1000 | 64.531 | 22.266 | 16.797 |
| micro-benchmarks/bm_so_matrix.rb | 60 | 8.312 | 2.781 | 2.125 |
| micro-benchmarks/bm_so_object.rb | 500K | 16.375 | 5.313 | 1.672 |
| micro-benchmarks/bm_so_object.rb | 1M | 29.312 | 10.500 | 2.844 |
| micro-benchmarks/bm_so_object.rb | 1.5M | 43.312 | 16.000 | 4.281 |
| micro-benchmarks/bm_so_sieve.rb | 4000 | 241.922 | 37.859 | 35.688 |
| micro-benchmarks/bm_socket_transfer_1mb.rb | 10K | 13.266 | SocketError | 3.359 |
| micro-benchmarks/bm_spectral_norm.rb | 100 | 5.110 | 0.922 | 0.719 |
| micro-benchmarks/bm_sum_file.rb | 100 | Timeout | 20.406 | 23.797 |
| micro-benchmarks/bm_word_anagrams.rb | 1 | 70.828 | 30.188 | 8.125 |
| TOTAL TIME | - | 2933.334 | 607.088 | 664.094 |
Red values are errors, timeouts, inapplicable tests and times that were worse than Ruby 1.8.6. Green, bold values are better times than what Ruby 1.8.6 delivered. A pale yellow background indicates the best time for a given benchmark. Total time is the runtime for the subset of benchmarks that were successfully executed by all three implementations (whose cardinality is 54).
The total runtime is summarized by the chart below:

And let’s compare each of the “macro-benchmarks” on an individual basis:

Conclusions
IronRuby went from being much slower than Ruby MRI to considerably faster across nearly all the tests. That’s major progress for sure, and the team behind the project deserves mad props for it.
One final warning before we get too excited here. IronRuby is not faster than Ruby 1.9.1 at this stage. Don’t let that first chart mislead you. While it’s faster in certain tests, it’s also slower is many others. Currently, it’s situated between Ruby 1.8.6 and Ruby 1.9.1, but much closer to the latter. The reason why this chart is misleading is that it doesn’t take into account any tests that timed out, and several of such timeouts were caused by IronRuby (more than those caused by Ruby 1.9.1). If you were to add, say, 300 seconds to the total, for each timeout for the two implementations, you’d quickly see that Ruby 1.9.1 still has the edge. The second chart that compares macro-benchmarks does a better job at realistically showing how IronRuby sits between Ruby 1.8.6 and Ruby 1.9.1 from a performance standpoint. If you were to plot every single benchmark on a chart, you’d find a similar outcomes for a large percentage of the tests.
Whether it’s faster than Ruby 1.9 or not, now that good performances are staring to show up, it’s easier to see IronRuby delivering on it’s goal of becoming the main implementation choice for those who both develop and deploy on Windows. This, paired with the .NET and possible Visual Studio integration, the great tools available to .NET developers, and the ability to execute Ruby code in the browser client-side thanks to projects like Silverlight/Moonlight and Gestalt, make the project all the more interesting.
What are your thoughts on IronRuby, and how will this dramatic performance gain affect your projects?
Nov
14
Merb, Rails Myths, Language Popularity and other Zenbits
Filed Under .NET, Books, DB2, Django, Merb, Python, Ruby, Ruby Benchmark Suite, Ruby on Rails, Zenbits | 1 Comment
Zenbits are posts which include a variety of interesting subjects that I’d like to talk about briefly, without writing a post for each of them.
Merb: A few days ago Merb 1.0 was released. Congratulations to Ezra Zygmuntowicz on this important milestone, the Merb community and Engine Yard (who finances the project). Merb 1.0 wasn’t even out yet when some people had already started commenting on the fracturing of the Ruby community that this new framework might bring with this, and the impact that this high visibility “competitor” might have on Rails. I believe that having more than one widely adopted web framework will only benefit the Ruby community. Furthermore, it’s important to remember that this is not a zero-sum game. Ruby programmers are perfectly capable of learning two frameworks and using one or the other, depending on the project at hand. This is particularly true if we consider that Merb, for all of its advantages – and disadvantages – when compared to Rails, is not totally different from its forerunner. If you are an expert Rails programmer, you should be able to become proficient in Merb in very little time. To help with this process, the Merb community needs to concentrate on the documentation now, given that the API is finally stable.
Rails Myths: David Heinemeier Hansson began a series of posts about Rails Myths. I like the idea of seeing common myths addressed straight from the horse’s mouth. Over the past two years, Rails has received quite a bit of backslash and old fashion FUD, so it’s important to set the record straight, whether the myths are entirely fabricated or if there is some element of truth to them. Whether you agree with David or not, it’s also nice to hear two sides of the same story. In fact, at the beginning of my book I debunk a few myths, just to set the record straight regarding what some readers may have heard surrounding the framework. It was a fun part to write.
My Book: Speaking of my book, Ruby on Rails for Microsoft Developers, I’m getting closer to the finish line. I’m about to complete Chapter 9 (out of eleven chapters). The initial schedule I was provided with has been extended slightly so that there will be sufficient time to properly review the content and ensure that it’s up to date with the final release of Rails 2.2. Some people wondered what the “Microsoft Developers” part means. Is it for people that work at Microsoft? Is it for .NET programmers? Is it for people who develop on Windows?
The truth is that “Microsoft Developers” is probably just a marketing term that Wrox selected as a catch-all for of the aforementioned categories of programmers. As an author I’m trying to serve all of them well, by providing a guide that sneaks in much of the Rails culture and softens the migration path by using an Operating System, and to a certain extent, tools that they’re already familiar with. In my opinion one of the major obstacles when switching to, or trying, Rails when coming from the Microsoft world, is the culture shock. The documentation and most books assume that you are familiar with *nix systems and tools, and this can be frustrating for those who are forced not only to learn a new language and framework, but also an entirely new set of tools. As it’s targeted at Microsoft developers, the book obviously makes quite a few references and comparisons to the .NET world, where they fit. This is done so that the many .NET programmers amongst the group of so called “Microsoft Developers” will find the book particularly useful. Yet the book remains generic enough so that it can be used by any programmer (particularly Windows users), even those without any knowledge of the Microsoft .NET Framework or ASP.NET.
Python books: While on the subject of books, I wanted to mention that the final version of the Pylons book is available online. Despite the much less fancy UI, the book pretty much does what the Django Book did in the past. And both are available in print as well (The Definitive Guide to Django: Web Development Done Right and The Definitive Guide to Pylons). Pylons is a Python web framework that can be viewed as a Ruby on Rails clone, in a far greater way than Django could ever be considered.
Another thing I want to mention is that I received a copy of Expert Python Programming. I haven’t gotten to far into it yet, but from what I’ve seen so far, things look good. I hope to be able to read it through, over a weekend in the near future and then provide a proper review. Stay tuned.
Language Popularity: If you take a look at the TIOBE Index, you’ll notice a few interesting things: Ruby has dropped two positions since last year, and it’s now the 11th most popular language in the world. This shouldn’t be cause for concern though, as shown by this Ruby graph. Python on the other hand is increasing in popularity and moved from the 7th to the 6th most popular language. Interestingly, according to the index (the results of which are educated guesses only), Python would seem to be more popular than C#. I find this to be true, in terms of online activity within an increasingly vibrant community, but in my opinion, the job market hasn’t caught up yet. In fact, at least in Toronto, when there’s a Python opening it’s pretty much an event that’s worthy of being discussed on the local Python mailing list. C# openings are much more common. This may be different in Silicon Valley, of course. It would also seem that Delphi has experienced a huge come back, moving from the 11th position last year to the 8th one this time around. It’s hard to imagine that Delphi has had a similar level of adoption as C# and thus has become more popular than Perl, JavaScript and Ruby. Delphi is a great solution for Win32 programming, but I don’t quite believe this overly optimistic outlook. And if this is the case, where are all the Delphi jobs and buzz?
DB2: This interview shows a few good reasons why even smaller and medium sized companies are increasingly adopting DB2. And while the video doesn’t mention it, IBM is coming out with an updated version of DB2 Express-C 9.5. This new version, 9.5.2 or 9.5 FixPack 2, is going to introduce exciting new features, including an engine for full text search.
The Great Ruby Shootout These days you hear a lot of talk about parallel programming. Intel promotes it and despite their bias, it’s plausible that parallel programming will become important as the CPU market heads towards an increasingly larger number of cores, as opposed to focusing on the frequency of said CPUs. In the world of Ruby, this translates into multiprocessing, as opposed to multithreading due to the infamous GIL (Global Interpreter Lock). This means that Ruby will most likely approach the problem similarly to how Python 2.6 did with the multiprocessing module, which is a process-based interface. The obvious exceptions are JRuby and IronRuby, which establish a 1 to 1 relationship between green threads and OS threads.
For the shootout, it would be interesting to see some multithreaded code, so as to get a better sense of how well JRuby and IronRuby compare to MRI and 1.9, when more cores are available. In fact, the long-promised shootout will be performed on a quad-core machine with 8GB of RAM. If Charles Nutter, John Lam, or any of their team members would like to contribute some programs that are able to take advantage of “native” multithreading, I’d be very happy to include them in the Ruby Benchmark Suite, to be used for my shootout.
The repository requires some love and refactoring, since it needs to be split in two types of benchmarks. The simpler one will evaluate the execution time minus the startup time, while the more advanced benchmark will also exclude the time required for parsing and loading modules, classes and methods in the AST. It would also be nice to test each program with variable input sizes and report these results accordingly. Right now I’m very busy with the book, but as I become more available, I’ll start working on this.
Finally, I want to point out a very interesting article about performance and UIs. Slow is indeed a very relative concept, and it’s important to understand how to analyze and respond to the user requirements when it comes to the responsiveness of an application as a user interacts with it.
Hardware: I finally bought a Trackball made by Logitech and the Microsoft Ergonomic Keyboard (Microsoft makes great hardware). I don’t have wrist problems, but I’d like to see how these two affect my extensive computer usage. I plan to report my experience as soon as I’ve had a chance to use these input devices for a while, since I know this is a topic that interests lots programmers (many of whom end up being victims of RSI, and some of the IRS
). I also bought a bad-ass color laser printer which is quite handy when you’re a programmer and you are writing a book. I’ll let you know how it goes. What I didn’t buy, but still think is awesome, is the Flip minoHD. It’s the equivalent of an iPod for the world of camcorders. $235 for a camcorder that’s so perfectly compact, and yet that can record in HD, is a pretty sweet deal. I’m considering it for Christmas, assuming it reaches Canada by then.





















