I spend quite a few of my lunch breaks playing around with some hobby game development in Ruby. I noticed that the game was running poorly. Eventually, I found that I had been needlessly creating many small Arrays in a very tight loop in my collision detection code. As with many things in life, the journey is much more interesting than the destination. Here’s how an hour of debugging resulted in an easy performance gain:
TIP: for 1.9 add this to Gemfile: gem 'perftools.rb', :git => 'git://github.com/bearded/perftools.rb.git', :branch => 'perftools-1.8'
The results show that 36% of time is being spent in the garbage collector. Perftools.rb doesn’t have any heap inspection tools and I’m using ruby 1.9; ObjectSpace.count_objects seemed like a good place to start.
I saw a lot of arrays constantly being collected; but where were they coming from?
I decided to use set_trace_func to see where all those temporary arrays were instantiated. Unfortunately I found that using the [ ] syntax for a new array does not invoke Array#initialize. After changing all my array calls to Array.new, I was ready for some set_trace_func action.
set_trace_func told me the file and lines to investigate. It turned out that I was returning arrays from methods just to turn around and splat them back out elsewhere. After a quick refactor, my garbage collection is down from 36% of my CPU time to 15%. Not bad for a lunchtime endeavor.