rootcho has asked for the wisdom of the Perl Monks concerning the following question:

hi,
For a long time I was wondering what is the speed difference, between obj vs func, by_name vs positional parameter passing.
And some cases is it worth it to choose the faster way over the more secure and convinient
So here are the results.
Rate obj_named_param named_pram obj_pos_param obj_i +nternal param obj_named_param 392157/s -- -14% -45% + -48% -56% named_pram 454545/s 16% -- -37% + -40% -49% obj_pos_param 716332/s 83% 58% -- + -5% -19% obj_internal 754148/s 92% 66% 5% + -- -15% param 889680/s 127% 96% 24% + 18% -- localhost work # perl time.pl Rate obj_named_param named_pram obj_pos_param obj_ +internal param obj_named_param 387297/s -- -12% -45% + -48% -55% named_pram 440141/s 14% -- -37% + -41% -49% obj_pos_param 701262/s 81% 59% -- + -6% -19% obj_internal 742942/s 92% 69% 6% + -- -14% param 860585/s 122% 96% 23% + 16% --
The fastest way as probably was expected was using subroutines and passing the parameters by position. The interesting thing is that it is more than 2 times faster compared to using object and passing the values by name. That seems like alot ;(, I mean there is many modules which use named params, if we can speed this on CPAN level, it will be many saved cpu-cycles ;).
Also it seems that the time consumer here is converting the @_ => %p.
param - sub by position named_param - sub by name obj_internal - the values we use are stored inside the object. obj_pos_param - obj passing values by position obj_named_param - obj passed by name
Here is the test script :
#!/usr/bin/perl package Blah; sub new { my $class = shift; my $self = { arg1 => 1, arg2 => 1 }; bless $self,$class ; return $self; } sub obj_internal { my $self = shift; return $$obj{arg1} + $$obj{arg2} } sub obj_pos_param { my ($self, $p1,$p2) = @_; return $p1 + $p2 } sub obj_named_param { my ($self, %p) = @_; return $p{arg1} + $p{arg2} } package main; use Benchmark qw(:all); our $obj = Blah->new; sub param { my ($p1,$p2) = @_; return $p1 + $p2 } sub named_param { my %p = @_; return $p{arg1} + $p{arg2} } cmpthese (5000000, { param => 'param(1,1)', named_pram => 'named_param(arg1 => 1,arg2 => 1)', obj_internal => '$obj->obj_internal()', obj_pos_param => '$obj->obj_pos_param(1,1)', obj_named_param => '$obj->obj_named_param(arg1 => 1,arg2 => 1)', })
Correct me if my micro benchmark are flawed.(i mean i know they are flawed if you look at the big picture, but in this micro way..).
Do you know some trick that we can use to speed up by_name passing ?

Replies are listed 'Best First'.
Re: speed : obj vs func, by_name vs positional
by GrandFather (Saint) on May 24, 2007 at 23:04 UTC

    obj_internal would be better rewritten as:

    sub obj_internal { my $self = shift; return $self->{arg1} + $self->{arg2} }

    Using strictures (use strict; use warnings;) would have alerted you to the issue as would printing the results returned from each test routine:

    print param(1, 2), "\n"; print named_param(arg1 => 1,arg2 => 2), "\n"; print $obj->obj_internal(), "\n"; print $obj->obj_pos_param(1, 2), "\n"; print $obj->obj_named_param(arg1 => 1,arg2 => 2), "\n";

    That aside (the results for the fixed benchmark are comparable with the original results), the interesting thing here is how little extra overhead in absolute time is added when using the more robust pass by name in an object context. It would be rare indeed that the run time difference is important. The advantage in terms of time for design and maintenance far outweigh any minor run time improvement.

    A nice confirmation of the mantras: "Don't prematurely optimize" and "Don't micro-optimize".


    DWIM is Perl's answer to Gödel
Re: speed : obj vs func, by_name vs positional
by Joost (Canon) on May 24, 2007 at 22:40 UTC
    Correct me if my micro benchmark are flawed.(i mean i know they are flawed if you look at the big picture, but in this micro way..).

    Calling the tests themselves and doing the addition will add time, so the actual speed difference is (slightly?) higher than results imply.

    Do you know some trick that we can use to speed up by_name passing ?
    Take a look at how POE does it. But really, the best way to optimize this stuff is to inline the subroutine/method calls or find some other way of doing the algorithm.

    If that isn't enough, move to XS/C. If that isn't enough, inline the calls in C. :-) update: in my experience, when you're already doing XS/C you'll find out how much time perl sub/method calls really take. 99.5% of the time it won't matter a bit, but when speed is really important you'll just want to get rid of the calls all together.

Re: speed : obj vs func, by_name vs positional
by princepawn (Parson) on May 25, 2007 at 14:09 UTC
    The interesting thing is that it is more than 2 times faster compared to using object and passing the values by name.
    Eeek. I'm a diehard Params::Validate user and so, on top of passing my parms by name, I also validate them. I shudder to think of the time lost... then again Mason uses P::V internally.

    And writing code without validating parameters is poor software engineering. Instead of trying to add hairs up to a head, I personally would just follow the 80/20 rule and try to optimize that 20% that might be causing speed issues.


    Carter's compass: I know I'm on the right track when by deleting something, I'm adding functionality