Rails performance scripts: profiler and benchmarker

Filed Under (Performance, Rails, Ruby) by Leonardo Borges on 20-11-2008

Tagged Under : , ,

There are several ways you can measure your rails application’s performance. The techniques range from filling your code with “puts” statements - :p - to fancy ones like NewRelic - which is quite nice, I must say.

But what many people don’t know is that rails ships with a handful of scripts to help you out. One of which is called profiler, located under your application’s scripts/performance directory.

By default it uses the standard ruby profiler but if you want more speed - and additional reporting options - , consider installing the ruby-prof gem.

So if you execute it without params, you’ll get a clue of how it works:

$ script/performance/profiler
Usage: ./script/performance/profiler 'Person.expensive_method(10)' [times] [flat|graph|graph_html]

Pretty self explanatory, right?

As a sample code, I have in my rails app a dumb model with a really dumb method I wanna profile:

class Article < ActiveRecord::Base
  def self.find_all_with_delay
    sleep 10
    self.find(:all)
  end
end

Clearly this method doesn’t perform well and is a bottle neck in our super application! But let’s see what rails’ profiler tells us:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ script/performance/profiler 'Article.find_all_with_delay' 1 graph > text_graph.perf
Loading Rails...
Using the ruby-prof extension.
Thread ID: 109440
Total Time: 10.147995
 
  %total   %self     total      self      wait     child            calls   Name
--------------------------------------------------------------------------------
 100.00%   0.00%     10.15      0.00      0.00     10.15                1     Global#[No method] (/Users/leo/projects/test/vendor/rails/railties/lib/commands/performance/profiler.rb:24}  /Users/leo/projects/test/vendor/rails/railties/lib/commands/performance/profiler.rb:24
                     10.15      0.00      0.00     10.15              1/1     Object#profile_me
--------------------------------------------------------------------------------
                     10.15      0.00      0.00     10.15              1/1     Global#[No method]
 100.00%   0.00%     10.15      0.00      0.00     10.15                1     Object#profile_me ((eval):1}  (eval):1
                      0.00      0.00      0.00      0.00              1/1     Class#const_missing
                     10.15      0.00      0.00     10.15              1/1     <Class::Article(id: integer, name: string, content: string, created_at: datetime, updated_at: datetime)>#find_all_with_delay
--------------------------------------------------------------------------------
                     10.15      0.00      0.00     10.15              1/1     Object#profile_me
  99.97%   0.00%     10.15      0.00      0.00     10.15                1     <Class::Article(id: integer, name: string, content: string, created_at: datetime, updated_at: datetime)>#find_all_with_delay (/Users/leo/projects/test/app/models/article.rb:2}  /Users/leo/projects/test/app/models/article.rb:2
                      0.15      0.00      0.00      0.15              1/1     <Class::ActiveRecord::Base>#find
                     10.00     10.00      0.00      0.00              1/1     Kernel#sleep
--------------------------------------------------------------------------------
                     10.00     10.00      0.00      0.00              1/1     <Class::Article(id: integer, name: string, content: string, created_at: datetime, updated_at: datetime)>#find_all_with_delay
  98.54%  98.54%     10.00     10.00      0.00      0.00                1     Kernel#sleep (ruby_runtime:0}  ruby_runtime:0
--------------------------------------------------------------------------------
...

As you can see, the group around line 13 is where most of the time is spent, going through our stupid call to Kernel#sleep and detailing every and each call from the very beginning. The report is much larger, so I recommend you give it a try. It’s really useful.

Now, displeased with my method’s performance, I wrote a new one that I think performs much better:

  def self.find_all_with_less_delay
    sleep 5
    self.find(:all)
  end

Nice huh? :) But how can we be sure it performs better? It turns out that under scripts/performance there is another useful script: benchmarker

Again, running it without arguments reveals it’s usage:

$ script/performance/benchmarker 
Usage: ./script/performance/benchmarker [times] 'Person.expensive_way' 'Person.another_expensive_way' ...

So, ready to see which one of my methods performs better? Let’s check:

$ script/performance/benchmarker 1 'Article.find_all_with_delay' 'Article.find_all_with_less_delay'
            user     system      total        real
#1      0.020000   0.000000   0.020000 ( 10.016033)
#2      0.010000   0.000000   0.010000 (  5.015390)

Pretty neat way to benchmark your methods huh?
Profiler and benchmarker are a powerful combination that have been helping me a lot in the projects I’m working on.

Hope you like it! See u soon! ;)

Don’t use REXML. I mean it.

Filed Under (Rails, Ruby) by Leonardo Borges on 08-10-2008

Tagged Under : ,

REXML is the standard XML processing library for Ruby. It’s on Ruby’s core and is terribly slow.

Yeah, I know it’s pretty simple to use, got a nice interface and, again, it’s just there. And it is a good library, for most things. But if you, as me, came to a point that processing XML is taking 50% of the time to render a rails action, it’s time to change.

My tip? Use libxml instead. The numbers on their home page speak for themselves. Try it yourself, you won’t be disappointed. And I’m really happy with the performance increase on our app.

RailsConf Europe 2008: impressions and highlights

Filed Under (Conferences, Rails, Ruby) by Leonardo Borges on 09-09-2008

I’m back in Madrid again after the RailsConf and I think it’s time to say something about it. :)

First off, the infrastructure provided by the conference was really great. The rooms, WiFi connection, food…  Really well organized.

Now to the sessions, highlights:

Tutorials (Tuesday)
- Meta-programming Ruby for fun and profit (Neal Ford, Patrick Farley)
The old and good techniques that made Ruby so powerful. Here Neal and Patrick walked us through the main tricks to meta programming like open classes - and conditionally open them - , dynamically define methods, sending messages to objects and how Ruby can help test your Java code in a much easier way.

I’ve put the link to the slides but honestly I don’t think they’re too much useful without the talking.

Sessions (Wednessday)
- EC2, MapReduce and Distributed processing (Jonathan Dahl)
Jonathan explained the theory behind MapReduce using very simple ruby examples, providing the basics on how to distribute and paralelize tasks accross multiple machines.

He also introduced Hadoop, a platform built in Java that “lets one easily write and run applications that process vast amounts of data”. What I liked the most was the simplicity he explained this subject. As of today, his presentation is not available online. Stay tuned as I’m gonna update this post with the links, as soon as they’re available.

Sessions (Thursday)
- Debugging & Testing the Web Tier (Neal Ford)
If you’ve been concerned about testing your app’s web tier lately, this presentation would probably not show you anything new. Neal talks about the need to debug and test javascript behaviour accross multiple browsers, using tools like Firebug, JSUnit and Selenium. If you have no idea about what these tools are, please stop now and go evaluate them!

We are pretty concerned about testing on my actual job, but selenium tests can be a pain sometimes - a.k.a extremely slow. And what ends up happening is that they are forgotten. Developers only run the test suite if it’s not painful and it’s lightning fast. Here’s is where the highlight for this session comes: CrossCheck.

The idea is to be able to test your javascript code accross multiple browsers without the need to launch them. In fact, you don’t even need a browser installed. The negative point is that it’s kinda fallen behind because now you can only test older versions of browsers. But since the project is getting a lot of traction, I’m pretty sure this will be solved soon.

Conclusion

My overall impression of the other sessions I attended is that some speakers just didn’t have time to properly prepare themselves, what made me think this years’s RailsConf wasn’t all that I expected.

But I also met interesting people and after all one of the key points in a conference is networking. :)

Definitely worth it though. And that’s why I took the time to provide this highlights.

c u soon

RailsConf Europe 2008: heading to berlin!

Filed Under (Conferences, Rails, Ruby) by Leonardo Borges on 30-08-2008

Tagged Under : , ,

The title says it already.

On monday I’ll be going to Berlin to attend this year´s RailsConf.

This will be my first one and of course my expectations are pretty high!

As usual, after the conference I’ll try and give a summary of what happened there, providing as much content as I can.

Anyone else’s going??? :)

C u there!

Mac OS X: Getting MySQL and Rails to work

Filed Under (Mac, Rails, Ruby) by Leonardo Borges on 28-08-2008

Tagged Under : , ,

So I couldn’t resist and bought myself a MacBook Pro! It’s my first week with my new toy and I’m really enjoying it.

But I need to do something useful with it so I started to prepare it to be my new development platform, starting with Ruby/Rails + MySQL: Here is where the fun begins!

After I installed both Rails and MySQL, I fired up a terminal an typed:

sudo gem install mysql

…and here is what u get

ERROR: Failed to build gem native extension.

If you google this error you will find a couple solutions and this is the one that worked for me:

ARCHFLAGS="-Os -arch x86_64 -fno-common"
sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql
--with-mysql-config=/usr/local/mysql/bin/mysql_config

Now, confident enough, I created a sample rails app and tried to create the development database:

leo$ rake db:create (in /Users/leo/projects/test)
dyld: lazy symbol binding failed: Symbol not found: _mysql_init

Doesn’t look happy yet huh? This took me a while to figure out but it turned out to be fairly simple.
I have no idea why but after I installed the gem I had the file mysql.bundle in two different places:

/Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
/Library/Ruby/Gems/1.8/gems/mysql-2.7/mysql.bundle

The solution was to remove the first copy of the file. Now everything is working fine at this end!
I really hope this is useful to someone!

Rails: Vulnerability on REXML

Filed Under (Rails, Ruby, Security) by Leonardo Borges on 24-08-2008

Tagged Under : , ,

REXML, the XML library uses by many ruby apps, including rails, has a vulnerability that requires an immediate patch on whatever rails version you’re using.

Details and instructions on the official rails weblog, here.

But basically, this is what you need to do:

gem install rexml-expansion-fix

Then, require rexml-expansion-fix in your rails’s app environment.rb file.

The biggest Rails event in latin america

Filed Under (Conferences, Rails, Ruby) by Leonardo Borges on 04-08-2008

Tagged Under : , ,

Behold latin american railers!

This year we will have the Rails Summit Latin America on October, 15th and 16th, in São Paulo, Brazil.

It’s by far the biggest Rails event we’ve ever had, including many of the speakers that were present at RailsConf.

Fábio Akita is also one of the speakers and provides more details on his blog.

If you’re a assumed rails geek don’t miss the opportunity to hear from the big names and to know a beautiful country like Brazil.

Oh, btw, if you’re brazilian, like me, you have no excuse to miss this party!

Enjoy!!!


Rails Summit Latin America

Passenger (mod_rails) and problems with custom Apache installation

Filed Under (Rails, Ruby) by Leonardo Borges on 07-06-2008

Tagged Under : ,

This week we started to test mod_rails in a couple of projects where I work on. One in production.

Of course it’s too early for any conclusions, but I just wanted to share a couple of problems you might find when the installer tries to compile the Apache module.

In our case, and I believe it is the case of many servers out there, we have a custom Apache installation, what makes the installer not find it and/or not find the Apache Portable Runtime (APR) sometimes.

The first one is easy and is documented here. You just seed to export the following environment variable, pointing to your apache installation:

export APXS2=/opt/apache2/bin/apxs

The second one is a bit tricky but it happened only when I tried to install passenger in another server that had CentOS. In this case, you will also need the following environment variable, pointing to your Apache APR config:

export APR_CONFIG=/usr/local/apache2/bin/apr-1-config

It took me a fair amount of time googling around to find this answer, so I hope it’ll be useful for someone. :)

Euruko 2008: Materials available

Filed Under (Conferences, Rails, Ruby) by Leonardo Borges on 14-05-2008

Tagged Under : , ,

As some of you know I went to the European Ruby Conf in Prague, this year.

The event was awesome and it’s good to know they finally made available the majority of the slides, here.

They also published Matz’s keynote, and more videos from the conference are being edited right now, so stay tuned to their home page!

Enjoy!

A couple of things from here…

Filed Under (Rails, Ruby, World) by Leonardo Borges on 10-05-2008

Tagged Under : , ,

It’s been some time since my last post but here I am! Where? In Spain, of course! Having a great time, I must say.

I arrived last week in Madrid and the past 2 weeks before that I spent basically packing my stuff. There is still some paperwork going on but everything is flowing well.

Besides this little feedback, I was reading this week’s issue of the excellent series This Week In Ruby, from my friend Antonio Cangiano. I found something quite interesting, a plugin called HoboFields.

One of the things that bothers me in rails is the fact that by looking at your model classes, you can’t tell the fields you have there. Sure, you can look at the migration script. Yeah, you can also load the development environment and inspect the object. It’s a pain in the @zz! But this is the way ActiveRecord works…

Other ORM solutions like DataMapper, allows you to define the fields directly in the class. It’s a much cleaner and clear way to maintain your models. And you get to know what properties you have just by looking at your classes.

That’s exactly what HoboFields adds to ActiveRecord.

You define your properties and its types straight into your model class, and the plugin creates the migration scripts for you. Coming from a java world my self, I find it rather interesting, useful and it also reminds me of the way Hibernate works. You define your mappings with anotations in your class and hibernate just generate the schemas from there.

It’s worth a try.