Forum: Ruby Performance characteristics of Ruby constructs.

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
7359ed44852399295c6247dd9719b81b?d=identicon&s=25 Ola Bini (Guest)
on 2006-05-23 07:16
(Received via mailing list)
Hi.

I'm right in the situation where I would like to find out some
performance characteristics for various parts of Ruby, to optimize an
application. Is there any resources available for this?

To make it concrete, let's take two examples.

I've recently written a hybrid state-based, table-driven LL(1) parser,
where I gather productions (in the form of symbols) on a stack, and then
execute these with send(), until a get back the next terminal. This
works really great, but right now I'm wondering how cheap send() is,
compared to using a real table-driven approach.

Next example: there's fairly heave use of Class#=== throughout the
application, and the profiler says I spend much time there. It's a
fairly small class of Class comparisons I'm doing, though, so maybe it
would get me better performance by polluting the global namespace like
this:
class Object
  def __is_directive_token?; false; end
  def __is_sequence_start_token?; false; end
end
class Token
end
class DirectiveToken
  def __is_directive_token?; true; end
end
and just do tok.__is_directive_token? instead of DirectiveToken === tok.

Any thoughts in this? Is there any place to find general information
this, or I'm out in the wild right now?

Regards
 Ola Bini
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-05-23 09:23
(Received via mailing list)
On May 22, 2006, at 10:13 PM, Ola Bini wrote:

> I'm right in the situation where I would like to find out some
> performance characteristics for various parts of Ruby, to optimize an
> application. Is there any resources available for this?

The built-in profiler, Shugo's Prof and ZenHacks' zenprofile are all
great for this.  Oh, I almost forgot benchmark.rb, also built-in.

> To make it concrete, let's take two examples.

I'll skip straight to the second example.

> Next example: there's fairly heave use of Class#=== throughout the
> application, and the profiler says I spend much time there.

Since you already know how to use the profiler you should be able to
iteratively test small changes to make optimize either problem
correctly.  Propose a change, make it, test its effectiveness, revert
if it doesn't help, repeat.

> end
>
> class DirectiveToken
>   def __is_directive_token?; true; end
> end
>
> and just do tok.__is_directive_token? instead of DirectiveToken ===
> tok.

(This machine has a 266MHz Geode CPU, so forgive the poor numbers.)

$ cat bm.rb
require 'benchmark'

class Object
   def directive_token?
     false
   end
end

class DirectiveToken
   def directive_token?
     true
   end
end

o = Object.new
dt = DirectiveToken.new
n = 1_000_000

Benchmark.bmbm do |bm|
   bm.report '#diretive_token?' do
     n.times { o.directive_token?; dt.directive_token? }
   end

   bm.report '#===' do
     n.times { DirectiveToken === o; DirectiveToken === dt }
   end
end

$ ruby -v bm.rb
ruby 1.8.2 (2004-12-25) [i386-freebsd5]
Rehearsal ----------------------------------------------------
#diretive_token?  15.226562   0.156250  15.382812 ( 16.111389)
#===              18.054688   0.117188  18.171875 ( 19.082567)
------------------------------------------ total: 33.554688sec

                        user     system      total        real
#diretive_token?  15.625000   0.125000  15.750000 ( 16.463518)
#===              17.617188   0.171875  17.789062 ( 18.649016)

> Any thoughts in this? Is there any place to find general
> information this, or I'm out in the wild right now?

My biggest question is: Why do you need to do all those class
comparisons?  Perhaps you can change your design to increase speed.

Also, if small enough, posting your code may get the local parser
geeks proposing all sorts of tuning tips.

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
7359ed44852399295c6247dd9719b81b?d=identicon&s=25 Ola Bini (Guest)
on 2006-05-23 10:06
(Received via mailing list)
Hi!

Thank you for the help.
I had forgot about the builtin benchmark.rb, actually. But what I was
looking for was more of the kind of information where I can read about
this, instead of trying different ways to get what I want. The big
problem
is that most of the code doing stuff (like the Class#===) is distributed
in
many places, and if I'm going to replace it, it would be good to find
out
beforehand if it's worth it, especially when just replacing one point
won't
show that much difference in the performance.
Actually, replacing the Class#=== with predicates on classes gave me
about
5% in performance, in this limited domain.

The class comparisons are right now done, because it's an LL(1) parser,
and
the lookahead checks the type of the next token to determine which
action
to take.

I probably won't post the code directly to the list, but when I've
optimized it sufficiently it will go into the next release of RbYAML,
and
I'll ask the parser geeks to take a look at it. =)

Regards
  Ola
Db212dec0d83349ef63c6100957b52d4?d=identicon&s=25 Robert Feldt (Guest)
on 2006-05-23 10:19
(Received via mailing list)
On 5/23/06, Ola Bini <Ola.Bini@ki.se> wrote:
> Hi!
>
> Thank you for the help.
> I had forgot about the builtin benchmark.rb, actually.
>
I don't know of any good general info on speed of different Ruby
constructs (there is some in the "Ruby Developers Guide" but probably
a bit dated now) but if you decide to use benchmarking the attached
benchmarking code might be more useful than the built-in one. It is
based on code by Mauricio Fernandez to ensure you have a certain
confidence in the measured time results. I simply added a ranked
print-out of the times. There is a todo in the comment of things that
should be added to make it even more useful (I had code for doing this
way back when involved in writing a Ruby book but lost it in a HD
crash and haven't had the need for it since then).

Anyway if this is useful feel free to use it (and please blog about /
publish any generally applicable performance results).

Regards,

Robert Feldt
Db212dec0d83349ef63c6100957b52d4?d=identicon&s=25 Robert Feldt (Guest)
on 2006-05-23 10:22
(Received via mailing list)
> Anyway if this is useful feel free to use it (and please blog about /
> publish any generally applicable performance results).
>
BTW, you should definetely use bmbm instead of bm...

Regards,

Robert
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2006-05-23 17:59
(Received via mailing list)
2006/5/23, Ola Bini <Ola.Bini@ki.se>:
> Actually, replacing the Class#=== with predicates on classes gave me about
> 5% in performance, in this limited domain.
>
> The class comparisons are right now done, because it's an LL(1) parser, and
> the lookahead checks the type of the next token to determine which action
> to take.

I think Eric is right in that you should rethink your design.  Usually
in OO languages you use method overloading to get proper behavior.  A
fast alternative in your case might be to use a hash with blocks.

action[ next_token.class ].call( whatever, arguments )

Note though that this has slightly different semantics as === will
check for subclasses also while the hash approach will only tackle
individual classes - unless you add some magic to the hash like this:

>> action = Hash.new {|h,cl| cl ? h[cl.ancestors[1]] : lambda {"fallback"} }
=> {}
>> action[Enumerable] = lambda { "foo" }
=> #<Proc:0x100d0948@(irb):68>
>> action[String].call
=> "foo"
>> action[Fixnum].call
=> "fallback"

Cheers

robert
This topic is locked and can not be replied to.