Benchmarks Project and example for `||=`

Has anyone ever put together a suite of benchmarks that simply measure
interesting Ruby practices? For example, here is a comparison of using
||= vs not using it.

n = 1000000

puts “#{n} Times”

t = Time.now

@b = :b
n.times do
@b
end

puts “Simple Read : #{Time.now - t} seconds”

t = Time.now

n.times do
@a ||= :a
end

puts " Or Equals : #{Time.now - t} seconds"

On ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]:

1000000 Times
Simple Read : 0.395487 seconds
Or Equals : 0.508428 seconds

On ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]:

1000000 Times
Simple Read : 0.121280356 seconds
Or Equals : 0.183629043 seconds

Might be an interesting project.

On Thu, Oct 7, 2010 at 7:28 AM, Intransition [email protected]
wrote:

@b = :b
end

1000000 Times
Simple Read : 0.121280356 seconds
Or Equals : 0.183629043 seconds

Might be an interesting project.

It would be interesting to have performance comparisons of the various
idioms in common use.

In these examples, however, it’s not surprising that the first loop
(without
||=) would be faster. It’s not doing anything really. The second involves
testing wether the variable is defined or not, every iteration.

Regards,
Ammar

On Oct 7, 12:57 am, Ammar A. [email protected] wrote:

It would be interesting to have performance comparisons of the various
idioms in common use.

In these examples, however, it’s not surprising that the first loop (without
||=) would be faster. It’s not doing anything really. The second involves
testing wether the variable is defined or not, every iteration.

Yep. I wrote it b/c I wanted to know how much slower using ||= is.

On Thu, Oct 7, 2010 at 12:05 PM, Jeremy B. [email protected] wrote:

The point of comparison profiling like this is to find ways to improve
your code without changing its ultimate function. Your comparison here
compares two fundamentally different operations

It struck me as odd that Trans is benchmarking two different things
against each other.

As another example, I just benchmarked the time it takes me to get up
out of my sofa and walk to my front door and back at about 30 seconds.
That’s over 3 times FASTER than Fernando Alonso’s fastest lap of
1:47.976 in the Singapore Grand Prix a couple of Sunday’s ago.

So does that make me faster than a Ferrari F10, I don’t think so, and
I doubt that it has a practical significance.


Rick DeNatale

Help fund my talk at Ruby Conf 2010:http://pledgie.com/campaigns/13677
Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

On 10/7/2010 8:28 AM, Intransition wrote:

Yep. I wrote it b/c I wanted to know how much slower using ||= is.
The issue is one of relevance though. Of course using ||= is slower
than simply taking whatever value is in the variable, but why do you
care in the first place?

If you just wanted to take the value of a variable, you would never use
||= in the first place. If you have a need to assign a value to the
variable only if it’s not already defined though, then you need ||= or
one of its less idiomatic equivalents.

The point of comparison profiling like this is to find ways to improve
your code without changing its ultimate function. Your comparison here
compares two fundamentally different operations. A more relevant
comparison would be as follows:

n = 1000000

puts “#{n} Times”

t = Time.now

@c = :c
n.times do
@c = :c unless @c
@c
end

puts " Optional set then get (verbose) : #{Time.now - t} seconds"

t = Time.now

@b = :b
n.times do
@b = @b || :b
end

puts “Optional set then get (less verbose) : #{Time.now - t} seconds”

t = Time.now

n.times do
@a ||= :a
end

puts " Optional set then get (idiomatic) : #{Time.now - t} seconds"

ruby 1.9.2p0 (2010-08-18) [i386-mingw32]
1000000 Times
Optional set then get (verbose) : 0.125004 seconds
Optional set then get (less verbose) : 0.140628 seconds
Optional set then get (idiomatic) : 0.156254 seconds

ruby 1.8.7 (2010-06-23 patchlevel 299) [i386-mingw32]
1000000 Times
Optional set then get (verbose) : 0.20313 seconds
Optional set then get (less verbose) : 0.218756 seconds
Optional set then get (idiomatic) : 0.187505 seconds

In this light, the idiomatic method compares favorably; however, I do
find it odd that Ruby 1.9.2 seems to take a hit on the relative
performance of the idiomatic method as compared to Ruby 1.8.7.

-Jeremy

On 10/7/2010 5:11 PM, Intransition wrote:

is in fact a very good reason for my comparison. I often do:
speed, I would do:
The purpose of the benchmark was to see just how much “squeeze” I am
getting in the exchange.

Take a look at
http://ruby-doc.org/docs/ProgrammingRuby/html/classes.html. On that
page you’ll find some examples for defining a method named “once”.
Search for “ExampleDate.once” under the Class and Module Definitions
section.

You can use the “once” method as a directive that will ensure that a
given method which may be expensive to compute is only run 1 time after
which the cached value will be returned. I made a generalized version
of “once” as suggested there for use in an internal project where I
work. That way I get the best of delayed computation, clear code, and
fast results for a few methods that really need it.

It might be interesting to profile the performance of a method wrapped
by “once” compared to your other solutions.

-Jeremy

On Oct 7, 12:45 pm, Rick DeNatale [email protected] wrote:

That’s over 3 times FASTER than Fernando Alonso’s fastest lap of
1:47.976 in the Singapore Grand Prix a couple of Sunday’s ago.

So does that make me faster than a Ferrari F10, I don’t think so, and
I doubt that it has a practical significance.

I think this is a good a reminder as any that it’s hard to see what
someone else is getting at when you’re not seeing the use case. There
is in fact a very good reason for my comparison. I often do:

class X
def f
@f ||= ( do_some_calc_or_lookup )
end
end

I like this idiom as it provides the speed bump of caching and yet
encapsulates the entire procedure for getting the value in one place.
However, if I am really concerned about squeezing out every bit of
speed, I would do:

class X
def initialize
@f = ( do_some_calc_or_lookup )
end
def f
@f
end
end

The purpose of the benchmark was to see just how much “squeeze” I am
getting in the exchange.

On Oct 7, 2010, at 15:11 , Intransition wrote:

end
There is a damn good reason why lazy initializing exists in the first
place, and it invalidates your statement above.

If you were really concerned about squeezing out every bit of speed,
you’d profile the code to see how it is used. If #f isn’t being called
in a tight loop, or isn’t even being called much at all, then you might
be spending more time running initialize than you would have doing the
lazy initialize. You’ll never know that mentarbating over
micro-benchmarks.

On Oct 7, 9:27 pm, Ryan D. [email protected] wrote:

 @f

end
end

There is a damn good reason why lazy initializing exists in the first place, and it invalidates your statement above.

How?

If you were really concerned about squeezing out every bit of speed, you’d profile the code to see how it is used. If #f isn’t being called in a tight loop, or isn’t even being called much at all, then you might be spending more time running initialize than you would have doing the lazy initialize. You’ll never know that mentarbating over micro-benchmarks.

You assume I am not aware of how frequently X.new is bring called in
comparison to X#f. In my case, its about 1 to N where N >= 1, and so
forth for X#f2, X#f3, X#f4, etc. If #f wasn’t being used but on rare
occasion, I wouldn’t worry about it. Moreover, by knowing the relative
difference between the two, one can make a better effort at optimizing
upfront, and potentially save time later.

And yes I do indeed profile code when I am “really concerned about
squeezing out every bit of speed”. In fact, if memory serves, I was
doing exactly that when I was trying to decide if giving up the
convenience of ||= was worth the performance gain.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs