# Some optimization hacks: your opinion?

**URL:** <https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154>\
**Category:** Rails\
**Created:** [November 12, 2008, 7:14pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154 "2008-11-12T19:14:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 12, 2008, 7:14pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/1 "2008-11-12T19:14:40Z")

</div>

Hi everyone,

I found and tried two optimization hacks; however, I don’t feel too  
comfortable with them. Therefore I would appreciate your opinion:

- Caching proc objects, i.e.

- and disabling the GC during an action:

On some of our machines and with some requests they boost performance  
by as much as 50%. however, as I don’t know if I shuld feel ssave with  
them I would like to hear your opinions.

BTW: A longer version of this text, with some explanation, is here:

> **[0x0a: Some optimization hacks…](https://1rad.wordpress.com/2008/11/10/0x0a-some-optimization-hacks/)**
>
> We are working on a somewhat larger Rails application, and one of the actions renders a table with up to 9.000 table elements. Now, somewhere when rendering that table we use a line like some\_array…

/eno

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 12, 2008, 9:50pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/2 "2008-11-12T21:50:25Z")

</div>

Some questions about disabling GC:

- Memory consuming action - will it kill server?

- Very small (not memory consuming) action - won’t GC.start slow it  
down significantly? (it’s called every time)

- Lets assume that one of your libraries used by the action is calling  
GC.start explicitly - the library “knows” it consumes a lot of memory  
and tries to free it in the right time - what will happen?

These are just some random questions about “bad” scenarios.

On Nov 12, 6:02 pm, “Enrico Thierbach”

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 12, 2008, 11:43pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/3 "2008-11-12T23:43:07Z")

</div>

Hi reHa,

On Wed, Nov 12, 2008 at 9:49 PM, reHa [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Some questions about disabling GC:
> 
> - Memory consuming action - will it kill server?
> 
> - Lets assume that one of your libraries used by the action is calling  
> GC.start explicitly - the library “knows” it consumes a lot of memory  
> and tries to free it in the right time - what will happen?

Hell, for sure those are dangerous situations. But then I guess I  
would know about the memory consumption of my app, or measure it in a  
high usage scenario.

I guess this is an issue for all apps, GC running or not: If you are  
running some code that needs much RAM all at the same time (so even  
the GC kicking in couldn’t help) this can already kill your server.  
(And I have seen ActiveRecord queries taking up up to somewhere close  
to 1 GByte) So you should always know what memory requirements your  
app has. And if you are know that and know that you are on the right  
side of the tracks, then, I guess, you should be fine.

In our app we have quite a strict upper limit on how many objects we  
have to deal with, so I guess I might feel safe 🙂

> - Very small (not memory consuming) action - won’t GC.start slow it  
> down significantly? (it’s called every time)

Yes, certainly. On my developer machine a GC run takes ~200msecs,  
which would turn fast actions in pretty slow ones 🙂 So I would like  
to have the GC run somewhere in the rails kernel - _after_ the  
response would be sent back to the client. But that, of course, can  
only be done by patching rails. And of course I wouldn’t run that code  
on all actions, only on some anyways.

> These are just some random questions about “bad” scenarios.

Thanks for your response. Did anyone use techniques like that before?

# /eno

A wee piece of ruby every monday: [http://1rad.wordpress.com/](http://1rad.wordpress.com/)

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 13, 2008, 11:38am UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/4 "2008-11-13T11:38:47Z")

</div>

Hi philip,

> restart (hence the need to passing a lambda into your namedscope).  
> as far as I can see, my code would never be called in those  
> circumstances, as 5.days doesn’t evaluate to a symbol, does it?

Comparing Rails’ original implementation

def to\_proc  
Proc.new { |\*args| args.shift. **send** (self, \*args) }  
end

with the improved(?) one:

def to\_proc  
@to\_proc ||= Proc.new { |\*args| args.shift. **send** (self, \*args) }  
end

you have the same values “going” into the Proc, namely the symbol  
(i.e. self). What I don’t know The question is more if there is  
something “invisible” going on in there?

Speaking of questions: does anyone know in what circumstances the  
\*args array can hold any values at all?

regards,  
/eno

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 13, 2008, 12:19am UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/5 "2008-11-13T00:19:59Z")

</div>

> would know about the memory consumption of my app, or measure it in a  
> In our app we have quite a strict upper limit on how many objects we  
> have to deal with, so I guess I might feel safe 🙂

Be careful here… I wrote an app awhile back that used the  
ultraviolet syntax highlighter. Didn’t even occur to me it might chew  
up a lot of ram and in all my usage it didn’t. Until I sent it a  
couple pages of horribly formatted html and it ballooned into a couple  
hundred megs. Kind of surprised me.

Point being… just be sure to double check your assumptions about  
memory usage… everyone knows to take another look at imagemagick,  
but some others suffer in odd cases as well…

Also, as to the Proc enhancement, I haven’t thought about it and my  
head hurts…

But what happens if one of the arguments is say Time.now? Will that  
get evaluated _once_ or each time? That is, will you have the same  
issue you’d have if you wrote:

named\_scope :foo, :conditions =\> [“created\_at \>= ?”, 5.days.ago]

Where 5.days.ago gets evaulated _once_ and never changes until you  
restart (hence the need to passing a lambda into your namedscope).

-philip

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 13, 2008, 2:41pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/6 "2008-11-13T14:41:59Z")

</div>

On Nov 13, 10:31 am, “Enrico Thierbach”  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> def to\_proc  
> Proc.new { |\*args| args.shift. **send** (self, \*args) }  
> end
> 
> with the improved(?) one:
> 
> def to\_proc  
> @to\_proc ||= Proc.new { |\*args| args.shift. **send** (self, \*args) }  
> end

This is interesting.  
I can’t remember quite what it is that makes .map(&:name) slower  
than .map{|o| o.name}

But I have a feeling that it was to do with the cost of instantiating  
a new Proc object each time.

With your solution,  
I’d be interested in seeing some benchmarks.

---

<div class="post-metadata">

**Author:** ![Enrico\_Thierbach](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/4af34b/32.png) [@Enrico\_Thierbach](https://www.ruby-forum.com/u/Enrico_Thierbach)\
**Post date:** [November 13, 2008, 4:48pm UTC](https://www.ruby-forum.com/t/some-optimization-hacks-your-opinion/153154/7 "2008-11-13T16:48:12Z")

</div>

Sure: there you go, in a somewhat 🙂 clinical testcase.

----------------- snip -----------------  
require “benchmark”

CNT=200000

Benchmark.bm { |x|  
x.report “V1” do  
(1…CNT).each do [1].each { |i| i.to\_i } end  
end  
}

class Symbol  
def to\_proc; Proc.new { |\*args| args.shift. **send** (self, \*args) };  
end  
end

Benchmark.bm { |x|  
x.report “V2” do  
(1…CNT).each do [].each (&:to\_i) end  
end  
}

class Symbol  
def to\_proc; Proc.new { |obj| obj. **send** (self) }; end  
end

Benchmark.bm { |x|  
x.report “V3” do  
(1…CNT).each do [1].each (&:to\_i) end  
end  
}

class Symbol  
def to\_proc; @proc ||= Proc.new { |\*args| args.shift. **send** (self,  
\*args) }; end  
end

Benchmark.bm { |x|  
x.report “V4” do  
(1…CNT).each do [1].each (&:to\_i) end  
end  
}  
----------------- snap ----------------

The result is on my machine as follows:

```
  user system total real

```

V1 0.200000 0.000000 0.200000 ( 0.201815)  
user system total real  
V2 0.860000 0.000000 0.860000 ( 0.870993)  
user system total real  
V3 0.950000 0.000000 0.950000 ( 0.953523)  
user system total real  
V4 0.680000 0.010000 0.690000 ( 0.685361)

The fastest, V1, doesn’t build proc objects at all. V2 is rails’  
default implementation, V4 caches the Proc objects inside the symbol,  
i.e. generates the Proc object only.

Of course, invoking 200000 Proc objects this way is usually not what  
you are doing in any application; we, however, had a test case where  
we did it 9000 times per action and it matched badly with the garbage  
collector. Ruby enterprise behaved much much better 🙂

/eno
