Skip to content

Conversation

christos
Copy link
Contributor

It would seem that FormOptionsHelper#options_for_select uses some syntactic sugar (Symbol#to_proc) which can cause severe performance problems under certain circumstances, when using ruby 1.8.7 w/ Rails 3-1-stable

In my case, I was rendering a page with 10 selects of about 700 options each (there is a use case for that, trust me), and after the first couple of requests it would take as long as 8 seconds more, per request (from 300ms to ~9secs). Eeek!

After a long session with perftools.rb and rack-perftools_profiler I managed to track it down to options_for_select and its use of map(&:to_s). The symptoms were seemingly random, long, garbage collection pauses, in the middle of a request.

Perftools.rb pointed me to Array.map creating tens of thousands of Proc objects as a side-effect of calling Symbol#to_proc.

Depending on the initial free memory allocation, garbage collection would not kick in until after 800MB of memory needed to be inspected by the GC. Unsurprisingly, my machine would stop responding during those long GC pauses.

I have not managed to reproduce with code the long GC pauses, I guess they need to happen inside the Rails rendering pipeline and under a specific memory situation, but I have managed to benchmark a significant improvement when replacing Symbol#to_proc with a block:

https://gist.github.com/1109416

The results:

Using ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin10.7.0], MBARI 0x6770, 
Ruby Enterprise Edition 2011.03

Rehearsal --------------------------------------------------------
Using Symbol#to_proc   3.520000   0.060000   3.580000 (  3.594295)
Standard call          2.890000   0.020000   2.910000 (  3.038064)
----------------------------------------------- total: 6.490000sec

                           user     system      total        real
Using Symbol#to_proc   3.750000   0.060000   3.810000 (  3.856077)
Standard call          2.690000   0.010000   2.700000 (  2.713586)

Now, I know 3.1 is only offering token Ruby 1.8.7 support and that 3.2 will most likely require 1.9.2, but this can be a real performance problem in real-world applications. One not worth not addressing for the sake of a bit of syntactic sugar...

The fix in this pull request should have zero side-effects and would save the mane of many a developer.

@fxn
Copy link
Member

fxn commented Jul 27, 2011

Support for Ruby 1.8.7 is planned to be removed for Rails 4. In the meantime, we are unrolling Symbol#to_proc, not systematically, but in spots where they prove to be problematic. Looks like you have a valid use case for those ones, so the patch is good.

Thanks Christos!

fxn added a commit that referenced this pull request Jul 27, 2011
Improve performance and memory usage for options_for_select with Ruby 1.8
@fxn fxn merged commit 348cd23 into rails:3-1-stable Jul 27, 2011
@christos
Copy link
Contributor Author

Thanks Xavi!

If Rails 3.2 is not going to drop support for Ruby 1.8.7, then shouldn't the patch be cherry picked into master as well?

@fxn
Copy link
Member

fxn commented Jul 27, 2011

Yes, I am going to cherry-pick now.

@saimonmoore
Copy link

I'll bite :) What's the use case? ;)

@christos
Copy link
Contributor Author

It is a 4 level deep hierarchy of options (TV program classifications) which client-side is converted by Javascript into 4 progressive disclosure select elements.

And yes, I could do it just with JS and JSON but I prefer progressive enhancement. Makes testing without selenium easier.

:)

@saimonmoore
Copy link

:) Thanks..just curious...

@pkmiec
Copy link

pkmiec commented Jul 29, 2011

lol ... i submitted a pull request for the same thing (#346), but got rejected. if at first you don't succeed, try again :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants