How-To: Quick Rails Benchmarking

How-To: Quick Rails Benchmarking

This February 6th we are launching a new workshop: Advanced Rails. The workshop draws content from the Scaling Rails and Rails Antipatterns workshops, replacing them and creating best-of-breed content that will take your skill to the next level in creating well-crafted Rails applications that scale.

One of the topics we touch on is profiling and benchmarking your app. There are a number of tools available to achieve this, one of which is baked into Rails itself. Although we do discuss all of the great ways you can perform caching in a Rails app, experience has shown us that caching should be your last resource in your scaling strategy. Remember the two hardest things in computer science: Cache invalidation, naming things and off-by-one errors.

On to benchmarking, say you have identified an expensive method in one of your models that needs to be tuned. One easy and straight-forward way to measure your refactored process is to use the built in benchmarker to run quick tests. To get set up, you need to add the ruby-prof gem to your Gemfile, and have a properly patched ruby interpreter. I’m using the gcdata patch for MRI 1.9.2:

rvm install 1.9.2-p180 --patch gcdata --name gcdata

Now let’s assume the following expensive method in the Account class:

class Account
  def self.expensive_method
    sleep(1)
  end
end

We can now run a quick benchmark on that method by running it 10 times and taking some benchmarking measurements:

bundle exec rails benchmarker --runs 10 'Account.expensive_method'
Loaded suite script/rails
Started
BenchmarkerTest#test_10 (0 ms warmup)
           wall_time: 0 ms
              memory: 0 Bytes
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
BenchmarkerTest#test_user_expensive_method (1.10 sec warmup)
           wall_time: 1.00 sec
              memory: 0 Bytes
             objects: 0
             gc_runs: 0
             gc_time: 0 ms

Finished in 24.933979 seconds.

You can even run a profiler with rails profiler 'Account.expensive_method' 10 flat and get more information on what’s being called and which components in your system are taking longer.

With this quick benchmark, you can now create a second, hopefully optimized, Account.expensive_method_fast and run them side-by-side, allowing you to quickly measure two implementations of the same behavior, and allowing you to quickly iterate to find the best solution.

This is just the tip of the iceberg. If you have some Rails experience and want to take it to the next level to grow your app into a well-factored and scalable system, check out our new Advanced Rails workshop.

Harold Giménez Developer