The mind is like a parachute. If it doesn't open, you're meat.

Script performance

09 Aug 2011

Code performance has two aspects: the actual performance measured hard seconds and the perceived performance AKA the responsiveness of the application.

When scripting, which for the purposes of this post I define as writing code that is executed once in the command line and then exits, a crucial metric is the startup time: the time it takes to load your script and start processing.

In the continuing battle to improve the performance and responsiveness of our rake build system (see here, here and here in reverse chronological order) the startup delay has now become the number one issue.

We have a name for it: "The Ruby tribute minute". It's not actually a minute, but in the last month it has climbed back up to 11 seconds which is a very noticeable delay, especially when you're doing 'rake -T'.

After a bit of experimentation trying (unsuccesfully) to get ruby-prof and profiler.rb running on Windows 7, I forked the code and started decorating it with Benchmark.measure calls.

The results proved very interesting. The overwhelming majority of the startup time was spent requiring couchrest, couchrestmodel and activerecord. We use couchrest to collect metrics (tasks called, time spent building, lines of code per build, firmware image sizes etc.) in a CouchDB instance which is then used to feed our information radiator.

Requiring couchrest costs ~2 seconds, couchrestmodel costs ~4.5 seconds, activerecord ~3.5 seconds (couchrestmodel requires activerecord but so do other gems we use).

Isolating the problem does not actually help since these numbers fall significantly. For example the following test

400: Invalid request

gives significantly reduced times:

400: Invalid request

btw. the stock Snow Leopard Ruby was a lot faster with rubygems 1.5.0:

400: Invalid request

but suffers with rubygems 1.8.7

400: Invalid request

I will take a wild guess and assume side effects from the additional gems loaded increase loading times but I can only theorize.

The current workaround consists of removing the require statements from the top of the files and adding them in the tasks where the gems are actually used. This shaves about 6.5 seconds from our startup times and improves rake responsiveness significantly but has the drawback of peppering require statements all over the place. I'm extremely interested in figuring out a better way to do this and also why the current rubygems version performs so bad.

Now to go back and refactor rutema so that active_record is not loaded unless needed...

blog comments powered by Disqus