I was bored and decided to benchmark ($s1,$s2 etc)=@ar vs @ar1=@ar2. should be roughly equal? Thats what you would think..
However, when i tried this code:
use Benchmark; @base=qw/one two three four five six seven/; timethese(1_000_000,{ '$'=>sub {($s1,$s2,$s3,$s4,$s5,$s6,$s7)=@base;}, '@'=>sub{@s=@base;} });
I got these results.
Benchmark: timing 1000000 iterations of $, @... $: 3 wallclock secs ( 2.86 usr + 0.00 sys = 2.86 CPU) @ 34 +9650.35/s (n=1000000) @: 11 wallclock secs (10.16 usr + 0.00 sys = 10.16 CPU) @ 98 +425.20/s (n=1000000)
odd? Yeah.. However, when i tried this code:
use Benchmark; my $sub=eval 'sub {('.join(',',map{'$s'.$_}1..1000).')=@base}'; @base=(1..1_000); timethese(1_000_000,{ '$'=>$sub, '@'=>sub{@s=@base;} });
i got these results:
Benchmark: timing 1000000 iterations of $, @... $: 131 wallclock secs (130.77 usr + 0.00 sys = 130.77 CPU) @ 7647.01/s (n=1000000) @: 149 wallclock secs (149.56 usr + 0.00 sys = 149.56 CPU) @ 6686.28/s (n=1000000)
Anyone have a brilliant explanation? (sorry for the pageful of $sXs, but i wanted to make the script just copy and paste).

Also note that i am running these test on this box: Win98se, amd1600mhz, 512ddr ram. So if anyone else wants to try the above code with different configs and see if its a win98 thing or something.

Replies are listed 'Best First'.
Re: list of scalars vs arrays, speed?
by demerphq (Chancellor) on May 02, 2002 at 11:08 UTC
    Well, I doubt its brilliant but I believe I can venture a hypothesis:

    The scalar version allows perl more opportunities to optimize. For instance it will know at compile time how many elements to copy from the right hand side and it will not have to dynamically allocate space for the target array at run time. Also it will not have to do basic administrative details like emptying the target array before refilling it, in the case of the scalars it need only copy the value or undef the var.

    There are probably other less obvious optimizations that Perl can do at compile time with the scalars but must do at run time with the array.

    BTW: Next time you might consider writing your killer scalar sub a bit differently:

    my $sub=eval 'sub {('.join(',',map{'$s'.$_}0..1000).')=@base}';
    :-)

    Yves / DeMerphq
    ---
    Writing a good benchmark isnt as easy as it might look.

      ... I knew i was missing something there. I forgot about doing it before the test.. I didnt originally use eval because i didnt want to add the over head of an eval in my time these loops.
Re: list of scalars vs arrays, speed?
by Matts (Deacon) on May 02, 2002 at 07:47 UTC
    It seems likely to me that the first one's slow performance is because it has to first extend the @s array because it's initially empty. It then has to copy over all the values into newly created scalars in the array. Whereas when you're just copying into scalars, the scalars are just there and already exist, so no extending, just a matter of sv_setsv() internally.

    The second test gains because the overhead of the large number of values overwhelms the extending delay.

      If I add a couple of tests where, instead of messing with globals you use lexical variables (just stick a 'my' at the front of each sub), I get the following results from a cmpthese(-10,{...}) run. I've combined the two sizes of test, hopefully the table is self explanatory.
                    Rate $ 1000 @ 1000 my $ 1000 my @ 1000 my @ 5    @ 5 my $ 5    $ 5
      $ 1000      1192/s     --   -15%      -15%      -22%   -99%   -99%  -100%  -100%
      @ 1000      1399/s    17%     --       -1%       -8%   -99%   -99%  -100%  -100%
      my $ 1000   1408/s    18%     1%        --       -8%   -99%   -99%  -100%  -100%
      my @ 1000   1528/s    28%     9%        8%        --   -99%   -99%  -100%  -100%
      my @ 5    126214/s 10492%  8921%     8861%     8162%     --   -34%   -60%   -63%
      @ 5       191633/s 15981% 13596%    13506%    12445%    52%     --   -40%   -44%
      my $ 5    317943/s 26581% 22624%    22474%    20713%   152%    66%     --    -7%
      $ 5       341012/s 28517% 24273%    24111%    22224%   170%    78%     7%     --
      
      Hmm... I do like the way the 1000s are almost the reverse of the 5s. Life's too short to go generating a graph to find out where the crossover points are, but it's certainly odd...
Re: list of scalars vs arrays, speed?
by dws (Chancellor) on May 02, 2002 at 05:45 UTC
    I'd be curious to see what happens if you reverse the order of the tests.


    Update: belg4mit rightly called me for being ambiguous. The naive way of reversing the order (i.e., swapping the elements in the hash that's passed to timethis()) won't work. You need to invoked timethis() once per test. The idea of reversing the order is to factor out memory fragmentation effects that biase towards the first test.

      Order? The subs are passed as a hashref, user has no control over order. He'd have to call timethis twice.

      --
      perl -pew "s/\b;([mnst])/'$1/g"

        He'd have to call timethis twice.

        How, exactly, is that a problem?

Re: list of scalars vs arrays, speed?
by perrin (Chancellor) on May 02, 2002 at 16:00 UTC
    Tests like this can be fun to play with and may provide interesting insights into Perl internals, but don't let the results affect your programming style. Differences this small are not a useful speed optimization. Optimize for readability instead.
    A reply falls below the community's threshold of quality. You may see it by logging in.