Nov 21 2013

Taking Out the Trash at RubyConf 2013

Method calls

RubyConf 2013 was held in Miami and it was just as wonderful as always. In fact, I had the honor of speaking about effective debugging. But instead of writing again about speaking at a Ruby conference, I want to discuss one particular statement from RubyConf that inspired me.

Garbage Collecting

Matz, during his opening keynote, first mentioned what became a recurring theme at RubyConf 2013: garbage collecting. In this case, garbage collection isn’t referring to a mark-and-sweep algorithm, but rather to the idea that, as Rubyists, we give back to the community by helping out. And sometimes, helping out includes taking out the garbage. For example, this could mean resolving bugs or building features for an existing library or gem that you use.

I was further inspired by Mark Bates’ excellent talk on Ruby 2.0′s TracePoint API, in which he claimed that Rails makes an astonishing 122,538 method calls. That many method calls to serve one HTTP request sounds insane, so I decided to do a little “garbage collection” of my own to see if there was an opportunity for me to give back to the community. Maybe there would be an opportunity for me to isolate and identify some inefficiency that would require a nice pull request to rectify.

Hello World!

My first task was to replicate Mark’s results, so I grabbed his code. After some hacking and getting comfortable with Ruby 2.0′s Tracepoint library, I had a little cold water to throw on the 122,538 method call claim: the overhead of running a Rails application in development mode accounts for a large part of this enormous method call count.

To get to the bottom of this discrepancy, I started with the lower limit by setting up a “Hello World!” Rack application. I determined that to process a single HTTP request made via command-line curl, 947 method calls are required to process the request. That’s only a few orders of magnitude away.

Next, I set up a “Hello World!” Sinatra app. It was a little tricky to ensure that the Tracepoint code played nicely with the Sinatra framework—the Tracepoint code had to be included before the Sinatra framework. Sinatra ended up clocking in at a respectable 4,375 method calls to process an HTTP curl request.

After setting up a “Hello World!” Rails app, I found that running in development there were only 79,073 method calls for processing one curl HTTP request. I’m not sure what can account for the discrepancy of approximately 40,000 method calls for my experiment versus Mark’s presentation. Correction: In the comments below, Mark points out that he used Chrome so the 40000 less calls in my curl example is because curl doesn’t make subsequent requests for assets. He even showed a video of him creating a default Rails app, which is what I did as well.

However, I felt that using the development environment wasn’t a great comparison to Rack and Sinatra, as they don’t reload code on each request, like Rails does. It is more appropriate to compare Rack and Sinatra to running Rails in the production environment. There, I determined that Rails makes 15,136 method calls to process one curl HTTP request.

I couldn’t stop there, and went on to compare a curl HTTP request in Rails production (15,136) to a Google Chrome HTTP request (21,869). I attribute the discrepancy between curl and a web browser to the requests for assets. I also turned off turbolinks to see what the effect would be: only a few thousand fewer calls for a curl request (14,537).

Leveling up

At the end of this exercise, I had hoped to come away with a pull request that fixed some egregious inefficiency, but instead I’ve settled for a better understanding of the Ruby Tracepoint API, which should set the stage for my contributing more in the future. Even if I were to ignore all of the other benefits of attending RubyConf, I would consider this a good result. Sometimes taking out the trash may mean that I have to level up my skills!

Taking out the trash feels good. Feels real good. What garbage have you collected lately? And how has it made you a better developer?

5 Comments

  1. Mark Bates

    Cool to see you look into it. I think the big difference was I used Chrome to access the page and you used cURL. cURL won’t invoke things like the asset pipeline, etc… I can easily reproduce this in Chrome. I’d be curious to see what results you get when you don’t use cURL. Good article though. :)

    • Hey Mark,

      First off, thanks for the excellent presentation! I enjoyed it.

      Secondly, oops! You’re absolutely correct. I was comparing apples to oranges there. I’ll update the post momentarily.

      Thanks for reading!

  2. BBQ Steve

    On my primary work project we had a large controller class that had originally included a small primer model for testing. Over time, that primer model had grown to encompass a double-digit percentage of the app’s functionality — and still had the controller code. This week, I dove in and separated the model and the controller — and it felt SO FREAKIN GOOD. Everyone comments on how much more sensible things appear.

  3. Jon

    ++ & ++ Sharing this posts with Ruby leads in Europa! Miss you guys!

Leave a Comment

Join the discussion. Do not worry, your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>