gfx/p5-MouseX-NativeTraits — Issue #1: ...::ArrayRef::generate_push needs optimization
Author: datamuc
Created: 2012-01-13 22:36:04+00:00
State: open

Hi,

push is really slow on larger arrays, I guess it's because the whole array get's copied around a few times:

sub generate_push {
my($self) = @_;
my $reader = $self->reader;
my $writer = $self->writer;

return sub {
my($instance, @values) = @_;

my @new_values = @{ $reader->($instance) };
push @new_values, @values;
$writer->($instance, \@new_values); # commit
return scalar @new_values;
};
}

It should be faster to check `@new_values` against `isa` and then `push @{ $reader->($instance) }, @new_values;`

Here's a benchmark:

{

package Foo;
sub new { my $self = {}; bless $self, 'Foo'; $self }
}
{

package A::Moose::Mutable;
use Moose;
has foo => ( isa => 'Str', is => 'rw' );
has rpobjects => (
is => 'rw',
isa => 'ArrayRef[Foo]',
traits => ['Array'],
default => sub { [] },
handles => { add => 'push', },
);

no Moose;
}
{

package A::Mouse::OwnpushCopy;
use Mouse;
use List::MoreUtils qw/any/;
use Carp qw/croak/;
has foo => ( isa => 'Str', is => 'rw' );
has rpobjects => (
is => 'rw',
isa => 'ArrayRef[Foo]',
traits => ['Array'],
default => sub { [] },
);

sub add {
my $self = shift;
my @array = @{$self->rpobjects};
push @array, @_;
$self->rpobjects(\@array);
}

no Mouse;
__PACKAGE__->meta->make_immutable;
}{

package A::Mouse::Ownpush;
use Mouse;
use List::MoreUtils qw/any/;
use Carp qw/croak/;
has foo => ( isa => 'Str', is => 'rw' );
has rpobjects => (
is => 'rw',
isa => 'ArrayRef[Foo]',
traits => ['Array'],
default => sub { [] },
);

sub add {
my $s = shift;
croak("not Foo") if any { ref $_ ne 'Foo' } @_;
push @{ $s->rpobjects }, @_;
}

no Mouse;
__PACKAGE__->meta->make_immutable;
}
{

package A::Mouse;
use Mouse;
has foo => ( isa => 'Str', is => 'rw' );
has rpobjects => (
is => 'rw',
isa => 'ArrayRef[Foo]',
traits => ['Array'],
default => sub { [] },
handles => { add => 'push', },
);
no Mouse;
__PACKAGE__->meta->make_immutable;
}
{

package A::Moose;
use Moose;
has foo => ( isa => 'Str', is => 'rw' );
has rpobjects => (
is => 'rw',
isa => 'ArrayRef[Foo]',
traits => ['Array'],
default => sub { [] },
handles => { add => 'push', },
);
no Moose;
__PACKAGE__->meta->make_immutable;
}

package main;
use Benchmark qw(:all);

my $mouse = A::Mouse->new( foo => "x" );
my $mouseop = A::Mouse::Ownpush->new( foo => "x" );
my $mouseopc = A::Mouse::OwnpushCopy->new( foo => "x" );
my $moose = A::Moose->new( foo => "x" );
my $moosem = A::Moose::Mutable->new( foo => "x" );

cmpthese(
$ARGV[0],
{
mouse => sub {
$mouse->add( Foo->new );
},
mouse_ownpushcopy => sub {
$mouseopc->add( Foo->new );
},
mouse_ownpush => sub {
$mouseop->add( Foo->new );
},
moose => sub {
$moose->add( Foo->new );
},
moose_mutable => sub {
$moosem->add( Foo->new );
},
}
);

__END__
danielt@bfh:~/tmp » perl bench.pl -3
Rate mouse_ownpushcopy mouse moose moose_mutable mouse_ownpush
mouse_ownpushcopy 517/s -- -3% -100% -100% -100%
mouse 535/s 3% -- -100% -100% -100%
moose 116284/s 22394% 21638% -- -6% -23%
moose_mutable 123134/s 23719% 22919% 6% -- -19%
mouse_ownpush 151345/s 29177% 28192% 30% 23% --