Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^3: Should multiplication by integer be avoided in favour of division for performance reasons? (benchmark pitfalls)

by vr (Curate)
on Nov 29, 2019 at 08:57 UTC ( [id://11109421]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Should multiplication by integer be avoided in favour of division for performance reasons? (benchmark pitfalls)
in thread Should multiplication by integer be avoided in favour of division for performance reasons?

There is no @main::a. You are benchmarking couple of no-ops.

use strict; use warnings; use Benchmark qw/ cmpthese timeit /; our @b = my @a = map log, 1..1e6; timeit( 1, 'print "\$#a = $#a\n";' ); timeit( 1, 'print "\$#b = $#b\n";' ); cmpthese( -2, { a => '[ map $_ * 4, @a ]', b => '[ map $_ * 4, @b ]', }); cmpthese( -2, { 1 => '[ map $_ * 4, @b ]', 2 => '[ map $_ / (1/4), @b ]', }); __END__ $#a = -1 $#b = 999999 Rate b a b 7.70/s -- -100% a 10680591/s 138780824% -- Rate 1 2 1 7.76/s -- -28% 2 10.7/s 39% --
  • Comment on Re^3: Should multiplication by integer be avoided in favour of division for performance reasons? (benchmark pitfalls)
  • Select or Download Code

Replies are listed 'Best First'.
Re^4: Should multiplication by integer be avoided in favour of division for performance reasons? (benchmark pitfalls)
by dave_the_m (Monsignor) on Nov 29, 2019 at 14:35 UTC
    The issue only occurs when a specific multiply op (i.e. a particular '*' on a particular line) is called multiple times, and on one occasion returns an integer result, and on subsequent other occasions returns a float. When this occurs the PADTMP (the private variable that the op uses to return its result) gets upgraded from an SVt_IV to a SVt_PVNV, which is the smallest type that can hold both an integer and a float. As it happens it can also potentially hold a string, and because of this, it is more expensive to free. So the extra time you're seeing in the benchmarks is just due to freeing the temporary array's now-more-complex elements. You can see a similar effect here, which involves no arithmetic:
    use Benchmark 'cmpthese'; my $x = 1; $x = 1.1; # $x promoted to PVNV our @a = map $x, 1..1e6; my $y = 1.1; our @b = map $y, 1..1e6; cmpthese( -2, { 1 => '{my @c = @a}', 2 => '{my @c = @b}', __END__ Rate 1 2 1 26.7/s -- -35% 2 40.9/s 53% --

    As it happens, perl's multiply operator is optimised to handle int*int and float*float quickly; other permutations like int*float and float*string take slower paths. As it also happens, if you do $float * 4, the constant 4 is internally upgraded to hold both an IV and NV value, so subsequent iterations take the fast float*float code path.

    Dave.

      Thank you for looking into this, dave_the_m. But there's still performance issue if integer, or float that appears to be integer, is not the first, but last element of array. Then there's just one expensive-to-free element in derived array?

      use strict; use warnings; use Devel::Peek; use Benchmark qw/ cmpthese timeit /; our @a = map log, 2..1e6; push @a, 0/1; print "************ a ************\n"; Dump $a[-2]; Dump $a[-1]; my @b = map $_ * 4, @a; print "************ b ************\n"; Dump $b[-2]; Dump $b[-1]; cmpthese( -2, { 1 => 'my @c = map $_ * 4, @a', 2 => 'my @c = map $_ / (1/4), @a', }); __END__ ************ a ************ SV = NV(0x55f0580) at 0x55f0598 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 13.8155105579643 SV = NV(0x102a388) at 0x102a3a0 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 0 ************ b ************ SV = NV(0xae879c8) at 0xae879e0 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 55.2620422318571 SV = PVNV(0x714ec8) at 0xae879f8 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 0 NV = 0 PV = 0 Rate 1 2 1 10.3/s -- -20% 2 12.8/s 25% --
        Bear in mind that Benchmark.pm does something like the equivalent of
        eval q[ for my $i (1..$n) { my @c = map $_ * 4, @a; } ]
        Since the same multiply op is used for all iterations, once it gets "poisoned" by trying to return an IV value for the last element of the first iteration, further calls to that op will start returning PVNVs. So for iterations 2+, all elements of @c will be PVNVs and thus slower to free.

        It's also the case that multiply is fractionally slower at returning a PVNV value rather than an NV value.

        Dave.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11109421]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-04-18 06:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found