drclaw
drclaw

Reputation: 2483

Why the performance difference in += vs +?

Debugging some code ended up testing the differences in the statements such as $counter=$counter + 1; vs $counter+=1;

my $run=True;
my $counter=0;
my $sup=Supply.interval(1);
my $tap= $sup.tap({
    $run=$_ < 10;
});
{
    while $run {
        #$counter+=1;
        $counter=$counter + 1;
    }
    $tap.close;
    say "Iterations per second: {$counter/(now - ENTER now)}"; #
}

I'm getting around 20% more iterations per second for $counter=$counter+1 compared to $counter+=1;

Whats happening in the background thats so different?

EDIT:

Interestingly when trying this with an array and hyper operators the performance is greatly increased when using the +=.

eg @counter=@counter>>+<<@value; vs @counter>>+=<<@value; I get about 2.8 times the iterations of the loop using >>+=<< with arrays of 10_000 elements.

As far as I can tell via the time cmd there is minimal parallel execution in either case (total user + system is within 2% of real time).

Any insight on how/why this is would be great. Thanks!

Upvotes: 14

Views: 341

Answers (1)

Elizabeth Mattijsen
Elizabeth Mattijsen

Reputation: 26924

I've golfed your benchmark to:

my $a = 0; for ^10_000_000 { $a += 1 }

vs:

my $a = 0; for ^10_000_000 { $a = $a + 1 }

If you run these examples in the profiler with perl6 --profile -e '...', then you'll see that the difference is indeed in the 20% range. The only thing that is really different, is the total number of frames: 49935579 for += 1, and 39932197 for = $a + 1.

The underlying difference (before any optimizations), is that += goes through a metaop path. It is not defined as a separate operator, so it needs to create the operator on the fly, taking the original operator (&infix:<+>) as a parameter and building a Callable out of that.

FWIW, I'm glad to see the difference is only 20% nowadays: it wasn't too long ago when anything involving metaops was at least 2x as slow :-)

Upvotes: 16

Related Questions