I am BARRY HESS > Blog

Fixing Slow Rake on Leopard

Hay Rake Third Version
Photo by JBAT

Update: I highly recommend going with Ruby Enterprise Edition and Evan Weaver's Ruby GC settings for much improved Ruby speed.

In the past few months, as a result of my clumsiness, I’ve been working on a new, Leopard-enabled MacBook. When replacing my wet and dying Tiger MacBook of yore, my one hope was that my daily executions of rake to test Harvest would execute a little faster. A 20% increase in processor speed doesn’t buy one a whole lot when web programming. The one place I figured I’d see a bump is the constant processor use of rake.

Wrong. So, so, wrong.

After moving to a new MacBook with Leopard installed, I experienced a test suite that ran 2-3 times slower than on my old machine. This became the difference between testing frequently and hardly at all; the difference between using and not using autotest. Pain to the max.

This post is going to get long, so I’m going to reveal now. For me, the issue was resolved by leaving the canonical Hivelogic world and reverting to the default Leopard installation of Ruby. Test speed returned to better-than-normal, and all at the price of only 6 hours of troubleshooting!

MySQL: Like shooting fish in a Superior-sized barrel

As always, my first suspicion was MySQL. I looked through my local Rails logs for particularly slow calls into MySQL. The initial thought was that a few bad-apple tests were not tuned very well for my environment. What I found was everything was slow and there were too many noticeably poor speeds to point to a few SQL calls as the culprits.

Next I compared my my.cnf file to my compadre‘s. I noticed no major smells in my file. Since I’m a DB dummy, more important was Dee’s estimation that indeed my configuration file looked alright. We even went so far as comparing MySQL variables from within the MySQL shell:

mysql> show variables;

Finally, I upgraded MySQL from 5.0.51 to 5.0.51b and reinstalled the ruby-mysql gem. No dice.

Sanity check: Benchmark the MacBook

Dee suggested I verify that my new MacBook itself wasn’t a lemon. I was doubtful since I’d noticed no other areas where it performed worse than its predecessor. Still, this was a great place to regroup. Benchmarking each MacBook put my mind in the right place to finish off my troubleshooting and uncover my problem.

I used Xbench to compare the general performance of my new and old MacBooks. Benchmark results favored the new machine everywhere except OpenGL. After reading the FAQ, it’s pretty clear OpenGL is a false positive for the old MacBook.

Rails: A general comparison between two machines

So I knew Rails was running slow when hitting the DB, but what about all by itself? I simply ran rake environment on both laptops and took a mental count. The command took ~3 seconds on the old machine and 6-7 seconds on the new one.

This was really enough, but I did run some model finders in each environment as a sort of sanity check. Performance results were in line with everything you’ve read so far.

Ruby: ActiveRecord-less and slow as ever

To hit the real meat-and-potatoes, I executed some Ruby-only code on both systems, benchmarking the whole way. Old Tiger:

$ ruby script/performance/benchmarker "(1..100).inject(1){|sum, n| sum*n}"
            user     system      total        real
#1      0.000000   0.000000   0.000000 (  0.000217)

New Leopard:

$ ruby script/performance/benchmarker "(1..100).inject(1){|sum, n| sum*n}"
            user     system      total        real
#1      0.000000   0.000000   0.000000 (  0.001347)

Over six times slower. New shit has come to light!

Sanity check II: Another system test

I wanted to run something from the command line that proved the new hotness was outperforming the old hoopty. Enter a little shell script built to copy an empty file to and from a folder 10,000 times:

echo "start at `date +%s`"
touch ./file.txt
mkdir ./fileholder


for ((a=1; a <= LIMIT ; a++))
  mv ./file.txt fileholder/
  mv ./fileholder/file.txt ./

rm ./file.txt
rm -rf ./fileholder

echo "end at `date +%s`"
exit 0

Rejoice! The new machine took 32 seconds to execute. The old one executed in 78 seconds. The winnowing process was imperfect, but I believe a winner has been crowned: Ruby.

Ruby: From source to simple

Both machines in question were on Ruby 1.8.6. The new one on patchlevel 114, the old one on 0. I attempted to install Ruby from source for patchlevel 230 (ACK!) and 111. No rake performance improvements were achieved. I also own a Leopard Mac Mini, installed from the Hivelogic instructions, and experienced the same rake downfalls (Sanity check III). Time to try Leopard’s default Ruby (patchlevel 114).

I did not want to remove /usr/local/bin from my path because I have other wonderful things installed there. Advisable or not, I simply renamed key binaries:

mv /usr/local/bin/ruby /usr/local/bin/ruby.bak
mv /usr/local/bin/rake /usr/local/bin/rake.bak
mv /usr/local/bin/irb /usr/local/bin/irb.bak

From there, all my gems needed reinstalled. gem install failed on my first try, but worked thereafter. The ruby-mysql gem had special needs (assuming a Hivelogic-style install of MySQL), which were addressed with:

sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

rake clean. Barry happy.

I can’t say I’m comfortable browsing my filesystem for gem source like I was with /usr/local, but I imagine that will come with time. My suspicion is the Hivelogic instructions can still work in Leopard given the appropriate compilation switches. I’m not the person to provide such information - perhaps someone already has?