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

Apologies if this is not the correct section to post. I have a question on the performance impact of creating temporary variables in Perl. Is there much difference between say

sub diag { my $x = shift @_; my $y = shift @_; my $x_sq = $x * $x; my $y_sq = $y * $y; my $prod = $x_sq + $y_sq; my $result = sqrt($prod); return $result; }
vs
sub diag { return sqrt( $_[0] * $_[0] + $_[1] * $_[1]); }

Thanks in advance (I guess I'm asking the reasoning behind it, and whether it should have much of an impact if we were repeating similar a lot of times, not to just measure it)

UPDATE: Thanks to all who replied. Sorry I had a typo. The operations were of course supposed to be the same! I didn't need a solution for a specific problem, it was just a theory question so I just did a simple formula as an example. i.e pythagerous

Replies are listed 'Best First'.
Re: Very basic question on performance
by davido (Cardinal) on Mar 14, 2014 at 02:51 UTC

    Your examples do not produce the same results. The first one multiplies $x_sq * $y_sq, while the second example adds the equivalent terms. In my benchmark I changed the second code snippet to multiply instead.

    The Benchmark module is sort of the standard module used in testing and comparing code snippets. The following script is an example of how to use it to check what your intuition is telling you:

    use Inline C => 'DATA'; use Benchmark 'cmpthese'; sub vdiag { my( $x, $y ) = @_; my $x_sq = $x * $x; my $y_sq = $y * $y; my $prod = $x_sq * $y_sq; my $res = sqrt($prod); return $res; } sub ediag { return sqrt( $_[0] * $_[0] * $_[1] * $_[1] ); } cmpthese( -5, { cdiag => 'cdiag(7,9)', vdiag => 'vdiag(7,9)', ediag => 'ediag(7,9)', } ); __DATA__ __C__ #include <math.h> double cdiag ( double x, double y ) { double x_sq = x * x; double y_sq = y * y; double prod = x_sq * y_sq; return sqrt(prod); }

    That produces the following comparison table:

    $ ./mytest.pl Rate vdiag ediag cdiag vdiag 1589859/s -- -49% -82% ediag 3127854/s 97% -- -64% cdiag 8603134/s 441% 175% --

    So your intuition was correct, that declaring a bunch of variables takes a little longer. But you do have to put it in perspective; 1589859 iterations per second is already very fast. And if you are really concerned with performance in a tight loop or something, eliminating the clarity that comes from using named variables is, in this case, not the most effective solution. The C solution is still readable, and achieves 8603134 iterations per second. Write your Perl how you would like to read it back in six months. And when performance is a real bottleneck, take your biggest swing at the problem first.


    Dave

      Write your Perl how you would like to read it back in six months.

      Write your Perl how you would like to read it back in six months at 3 AM, and your deadline to deliver your working, tested project is 8 AM.

        Or in my case, at 9:30am, with the 3yo and 5yo kids, under my "supervision", playing nearby. ;)


        Dave

      I often use named variable for better clarity, but in this case, I find ediag to be more readable than vdiag, because you see immediately the math formula. It is by looking at the ediag function that I quickly saw that it can be simplified to:
      sub ediag { return $_[0] * $_[1]; }
      as I said in my other post. I would not pick up that immediately when looking at vdiag.

        Or more accurately:

        sub ediag { return abs($_[0]) * abs($_[1]); }

        ...or...

        sub ediag { abs(shift) * abs(shift); }

        It's possible (maybe even probable) that since the OP showed one subroutine that did this:

        sub one { sqrt( $_[0] * $_[0] * $_[1] * $_[1] ) }

        ...and another that did this:

        sub another{ sqrt( $_[0] * $_[0] + $_[1] * $_[1] ) }

        ...that we (I) should have been looking at his second example all along, and should have considered the first one a typo. If that's the case, then the square root of the sum of two squares does make more sense.


        Dave

      Write your Perl like it's 0300, the ENTIRE FINANCIAL SYSTEM is down, and the Union Payroll has to be delivered by 0800. Oh, and you have three levels of Management on a conference call asking you "How's it going?" every five minutes. AND the coffee pot just burned out the heating element.

      ----
      I Go Back to Sleep, Now.

      OGB

Re: Very basic question on performance
by kcott (Archbishop) on Mar 14, 2014 at 02:10 UTC

    G'day morrin,

    "I guess I'm asking the reasoning behind it, and whether it should have much of an impact if we were repeating similar a lot of times, not to just measure it"

    There's a built-in module called Benchmark which can run these multiple times and provide a comparison of running times.

    My guess is that the first will be slower. The reason being that you're declaring six variables and assigning values to them in addition to the arithmetic which is common to both subroutines.

    -- Ken

Re: Very basic question on performance
by Marshall (Canon) on Mar 14, 2014 at 03:37 UTC
    I would say that "none of the above" is best.
    sub diag { my ($x,$y) = @_; #faster }
Re: Very basic question on performance
by Laurent_R (Canon) on Mar 14, 2014 at 09:29 UTC

    If the aim is really to compute:

    sub diag { my $x = shift @_; my $y = shift @_; my $x_sq = $x * $x; my $y_sq = $y * $y; my $prod = $x_sq * $y_sq; my $result = sqrt($prod); return $result; }
    then it will be presumably much faster to calculate it this way:
    sub diag { my $x = shift @_; my $y = shift @_; return abs ($x * $y); }
    or this way:
    sub diag { return abs ($_[0] * $_[1]); }

    Update: I've just corrected the code above adding the abs function which I had omitted, since my original function would have returned a negative number if one of the arguments were negative. Thanks to clueless newbie and davido who pointed that to me.

Re: Very basic question on performance
by locked_user sundialsvc4 (Abbot) on Mar 14, 2014 at 11:57 UTC

    If this code is really being executed millions of times per second, such that whatever slight increment in speed that might be obtained from “bogosity” and/or “golf” has business ROI to actually counter the increase in maintenance and enhancement costs, then you might be able to make a case (to your boss!) for doing this.   But why not spend $30,000 on faster blade servers, and more of them?   “Throw sand in its face.”   “Throw silicon at it.”   You often come out way ahead.

    (Speaking philosophically and impersonally now ...)   “The trouble with computer programmers is, not only do they fail to realize just how expensive they are (beyond their salary and benefits!), but they also fail to realize what makes them so expensive.”   What would make this code expensive?   One of your successors, after you got hired-away by Google, specifying @_[2], instead of @_[3], in just one friggin’ place that happens to be on the lee-side of an if/then/else ... in April, in the code-path that won’t be used until the last week in December, when end-of-year close outs (due on January 1st following) are done.   The mistake isn’t obvious, because the code isn’t obvious.   Of course there isn’t a regression-testing suite, or of course it wasn’t run.   So, the error isn’t caught, the reporting is done ... and the numbers are public, duly filed with government regulators ... and they are wrong, and guess who tells us that?   “All for the want of a millisecond?”   No, thanks!   After all, I can always $$buy$$ time.

      I remain firmly of the opinion that if you're not using Perl's flexibility and freedom to write clearer, more maintainable code then you're Doing It Wrong.

      Generally - algorithm is most important and worth getting right, as that's got some big boons in efficiency. But it's very rarely worth trading off readability and maintainability for a few cpu cycles.

      As Brian Kernighan put it: "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?"