in reply to Performance of Perl references

Like Perrin says, your benchmark functions aren't well suited to what you're testing. Your functions only look up the array to be sorted once per invocation; then you go on to sort the array and then assign the result into another variable. The cost of using a reference is going to be swamped by these later steps.

The big performance win from references comes from being able to pass them in and out of subroutines more efficiently. This benchmark illustrates the benefit more clearly:

use strict; use Benchmark; my @x = (0..100_000); sub pass_by_value(@) { my $x; foreach (@_) { $x += $_ } return $x + } sub pass_by_reference(\@) { my $x; foreach (@$_) { $x += $_ } return $ +x } timethese(500, { 'Pass by Ref' => sub { pass_by_reference(@x) }, 'Pass by Value' => sub { pass_by_value(@x) } }); sub return_by_value(@) { return @x }; sub return_by_reference(\@) { return \@x }; timethese(500, { 'Return by Ref' => sub { return_by_reference(@x) }, 'Return by Value' => sub { return_by_value(@x) } });
Here are the benchmark results on my system:
Benchmark: timing 500 iterations of Pass by Ref, Pass by Value...
Pass by Ref:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)
            (warning: too few iterations for a reliable count)
Pass by Value: 78 wallclock secs (67.48 usr +  0.17 sys = 67.65 CPU) @  7.39/s (n=500)
Benchmark: timing 500 iterations of Return by Ref, Return by Value...
Return by Ref:  0 wallclock secs ( 0.00 usr +  0.00 sys =  0.00 CPU)
            (warning: too few iterations for a reliable count)
Return by Value: 16 wallclock secs (14.19 usr +  0.03 sys = 14.22 CPU) @ 35.16/s (n=500)

Replies are listed 'Best First'.
Re: Re: Performance of Perl references
by fuzzyping (Chaplain) on Jul 22, 2002 at 13:57 UTC
    So, passing references is where I'm going to experience the most performance gains from using refs. Makes sense. Hindsight, my benchmark was highly flawed in what it attempted to quantify. However, the real crux of my post has been, for the most part, left unanswered... where (else) are you likely to note great gains from using references. Where do you not want to use references?

    -fp
      Any time you derefernce to get to a value pointed to by a reference, it's called a layer of indirection. Every layer of indirection adds some overhead, so if you are acccessing data deep inside a complex data structure, it adds up. Normally this is negligable, but if you are doing so inside loops you can gain more speed by removing as many layers of indirecion as possible.
      Take the following code sample. The structure '$data' is two levels deep, and the subs 'foo' and 'bar' both loop thru and access all the data at the deepest level. 'foo' uses a naive aproach of multiple layers of indirection at the deepest level 'my $val = $data->{$key1}->{$key2}', while 'bar' reduces the indirection by assigning the inner data struct to a variable 'my $data2 = $data->{$key1}' and looping over it, accessing that data with 'my $val = $data2->{$key2}'.

      results:

      Benchmark: timing 100000 iterations of multiple_indirection, reduced_indirection...
      multiple_indirection: 29 wallclock secs (28.08 usr +  0.00 sys = 28.08 CPU) @ 3561.25/s (n=100000)
      reduced_indirection: 25 wallclock secs (24.19 usr +  0.00 sys = 24.19 CPU) @ 4133.94/s (n=100000)
                             Rate multiple_indirection  reduced_indirection
      multiple_indirection 3561/s                   --                 -14%
      reduced_indirection  4134/s                  16%                   --
      

      code:
      #!/usr/bin/perl my %innerdata; @innerdata{a..z} = a..z; my $data = { foo => { %innerdata }, bar => { %innerdata } }; sub foo { my $data = $_[0]; for $key1 (keys %$data) { for $key2 (keys %{$data->{$key1}}) { my $val = $data->{$key1}->{$key2}; # process $val; # print $val; } } } sub bar { my $data = $_[0]; for $key1 (keys %$data) { my $data2 = $data->{$key1}; for $key2 (keys %$data2) { my $val = $data2->{$key2}; # process $val; # print $val; } } } use Benchmark qw(cmpthese); cmpthese( 100000, { multiple_indirection => sub { foo($data) }, reduced_indirection => sub { bar($data) }, } )
      -- O thievish Night, Why should'st thou, but for some felonious end, In thy dark lantern thus close up the stars? --Milton