

Speeding up a Rails request by 150ms by changing 1 line - amanfredi
http://kevin.scaldeferri.com/blog/2009/05/08/RailsRackResponse.html

======
ankhmoop
I'm not sure why individuals feel the need to write an entire page of text
regarding a relatively straight-forward bug fixes. "Improved [Rails|Ruby|...]
performance by [X] ms by changing [N < 20] lines of code" posts are becoming a
common occurrence.

The regular occurrence of such issues in a project implies an immature, poorly
profiled code base, and are the kinds of things that other projects fix
without fanfare.

Our most recent database-backed dynamic web application can serve >10000
requests/sec on our mid-range hardware at <2 ms/req, which we achieved by
running the most basic of profiling early on and throughout the development
process, and using software that does the same. I don't expect a gold star for
this.

~~~
ZeroGravitas
You've missed an important but subtle point. The article points out that the
reason this was overlooked is not because Rails isn't profiled but because
this behaviour is happening outside the standard rails profiling scope. That
is a) why it's not a "relatively-straightforward bug fix", b) why it hadn't
been caught already and c) why it is interesting. Actually I take that back,
it _is_ a relatively-straightforward bug fix. As with all the best bugs it's
finding it that wasn't straightforward.

I think a similar thing happened about a year ago when people were profiling
rails but not profiling memory usage. After they realised GC was impacting
their performance they shifted their focus and improved things in that regard.
The most recent "X line Y% speedup" article I read here took this even further
and examined the impact of the size of stack vs. heap memory on GC times.

My particular favourite example of this is Steve Souders work showing how much
your web app performance is affected by the end users browser and its wacky
network and cache behaviour. He has claimed these factors can account for
80-90% of the end-users' waiting time. I know rails core have been working to
fix these issues as they did a presentation about.

That sounds to me like a bunch of useful lessons to be learned from. Certainly
more info than just "profiling good", more like non-holistic profiling can be
misleading. Your response certainly doesn't cover this as you talk about
"basic profiling", so what is outside the profiling you do? How would you know
if it is affecting performance and to what degree?

~~~
ankhmoop
_You've missed an important but subtle point. The article points out that the
reason this was overlooked is not because Rails isn't profiled but because
this behaviour is happening outside the standard rails profiling scope. That
is a) why it's not a "relatively-straightforward bug fix", b) why it hadn't
been caught already and c) why it is interesting. Actually I take that back,
it is a relatively-straightforward bug fix. As with all the best bugs it's
finding it that wasn't straightforward._

Properly profiling the full execution path should be an entirely obvious step
to take.

------
lallysingh
Between the lot of these, the only message I'm getting is "ruby and rails
authors happily dump speed in favor of not thinking terribly hard."

Seriously, is it _that_ hard to pull up dtrace and do a little analysis? They
even have dtrace-ruby bindings on MacOS!
<http://www.infoq.com/news/2007/10/ruby-leopard>

------
icey
Rails returns the body 1 line at a time? That can't seriously be true, can it?

~~~
kscaldef
True. Seriously. At least in 2.3. Pre-Rack, I don't imagine that code would
have been present.

~~~
carbon8
It's in 2.3 stable, but it appears to no longer be present in edge (in fact,
ActionPack has already gone through a lot of changes):

<http://is.gd/xP8Y> (github link)

~~~
mtarnovan
String.each is the same as String.each_line in ruby 1.8. This code rewrite
seems to be the reason that code breaks on ruby 1.9 if body is a string (this
is guarded against in the body setter). (ruby 1.9 removes String.each)

<http://github.com/josh/rack/tree/master> :

* NOTE: String bodies break in 1.9, use an Array consisting of a single String instead.

p.s. this is definitely worth a 2.3.3 tag and release

------
zcrar70
> We’re pretty obsessed with performance at Gilt Groupe

Not wishing to troll, but I'm not sure that Ruby/Rails is you're looking for
if you're obsessed with performance...

~~~
callmeed
Not to put words in anyone's mouth, but perhaps he meant _"obsessed with rails
performance ..."_

------
jasonkester
It makes me want to cry that people are still writing things in technologies
that require you to drop little timing statements into your code to profile
them.

Profilers have been around for what? 30 years? I think the first time I hooked
Ants Profiler up to an ASP.NET site was 2002. Are these other web technologies
really that far behind the state of the art?

~~~
kscaldef
I didn't feel like getting into the nitty-gritty details of my analysis, but
Ruby does have a profiler, and it integrates into Rails quite well, and I was
using it together with timers in this investigation. However, the exact same
issue applies to the profiler as to simple timers, which is that the 150ms in
question happens _after_ Rails hands off the reply to the web server, so as
long as you are only measuring within the Rails framework, you will not see
it.

~~~
jasonkester
Strange. My expectation would be that you'd hook a profiler up to the web
process and it would simply follow all ruby code paths, regardless of whether
Rails were involved or not. Or do we have different definitions of Profiler?

You're talking about a separate application that watches executing code and
keeps statistics, right? As in, not simply a set of timing functions in a
wrapper somewhere in the framework? If so, how does it come off the trolley
after Rails finishes its job?

~~~
kscaldef
ruby-prof is a module that runs inside the ruby process, and hooks into the
interpreter to track what's happening. You have options for how to run it. You
can run the entire program within the profiler, but if you do that, you won't
get data out until the process ends (you kill the webserver, in this case).
Or, you can do what's more typical for profiling Rails, which is to explicitly
activate the profiler for the course of a single request, and report on that
single request.

