[Dbix-class] Class::C3 and branches/DBIx-Class-C3
Matt S Trout
dbix-class at trout.me.uk
Tue Nov 15 20:52:28 CET 2005
Ok, so as the benchmark below demonstrates Class::C3 runs *much* faster
than NEXT (as of the 0.05 dist, quicksilver and I optimised it a little).
It also should free us from a number of NEXT bugs.
I've created a branch to attempt to make a port; it's somewhat working but
there are still some unresolvable inheritance chains in there. Anybody
who's got commit to trunk should have commit to the branch, so if you can
tweak something and get more tests passing, commit it. Stuff it, it's a
branch. If we break it I'll make another one :)
##################################################################
perl main.pl
All tests are run 5000 times, basic task is adding up numbers 1..10
Basic function call 0.047 s 9.5 us/iter
function calling function 0.052 s 10.3 us/iter
anonymous function calling function 0.061 s 12.1 us/iter
method calling function 0.063 s 12.5 us/iter
method calling function stored in self 0.066 s 13.1 us/iter
simple subclass 0.066 s 13.2 us/iter
SUPER redispatch 0.100 s 20.0 us/iter
SUPER^2 redispatch 0.141 s 28.2 us/iter
SUPER^3 redispatch 0.226 s 45.2 us/iter
SUPER^4 redispatch 0.192 s 38.4 us/iter
NEXT redispatch 0.702 s 140.3 us/iter
NEXT^2 redispatch 1.319 s 263.7 us/iter
NEXT^3 redispatch 1.976 s 395.2 us/iter
NEXT^4 redispatch 2.334 s 466.7 us/iter
NEXT, 4 Dummy supers 1.638 s 327.6 us/iter
NEXT, 8 Dummy supers 2.227 s 445.5 us/iter
NEXT, 4 Passthrough supers 3.256 s 651.1 us/iter
NEXT::ACTUAL, 4 Passthrough supers 3.231 s 646.3 us/iter
Class::C3 redispatch 0.379 s 75.8 us/iter
Class::C3^2 redispatch 0.315 s 63.0 us/iter
Class::C3^3 redispatch 0.433 s 86.6 us/iter
Class::C3^4 redispatch 0.605 s 121.0 us/iter
Class::C3, 4 Dummy supers 0.487 s 97.4 us/iter
Class::C3, 8 Dummy supers 0.523 s 104.6 us/iter
#####################################################
#!/usr/bin/perl
use Time::HiRes qw/sleep gettimeofday tv_interval/;
my $num_iters = 5000;
my $sum_to = 10;
print "All tests are run $num_iters times, ",
"basic task is adding up numbers 1..$sum_to\n\n";
sub dosomething { my $tot; foreach my $i (1..$sum_to) {$tot+=$i} }
run_test(\&dosomething,"Basic function call");
sub something_else { dosomething(); }
run_test(\&something_else,"function calling function");
run_test(sub {dosomething();},"anonymous function calling function");
my @objtests =
(
ObjTest1=>"method calling function",
ObjTest2=>"method calling function stored in self",
ObjTest3=>"simple subclass",
ObjTestS1=>"SUPER redispatch",
ObjTestS2=>"SUPER^2 redispatch",
ObjTestS3=>"SUPER^3 redispatch",
ObjTestS4=>"SUPER^4 redispatch",
ObjTestN1=>"NEXT redispatch",
ObjTestN2=>"NEXT^2 redispatch",
ObjTestN3=>"NEXT^3 redispatch",
ObjTestN4=>"NEXT^4 redispatch",
ObjTestND4=>"NEXT, 4 Dummy supers",
ObjTestND8=>"NEXT, 8 Dummy supers",
ObjTestNPT4=>"NEXT, 4 Passthrough supers",
ObjTestNPTA4=>"NEXT::ACTUAL, 4 Passthrough supers",
ObjTestC31=>"Class::C3 redispatch",
ObjTestC32=>"Class::C3^2 redispatch",
ObjTestC33=>"Class::C3^3 redispatch",
ObjTestC34=>"Class::C3^4 redispatch",
ObjTestC3D4=>"Class::C3, 4 Dummy supers",
ObjTestC3D8=>"Class::C3, 8 Dummy supers",
);
my $i;
for ($i = 0;$i < $#objtests;$i+=2 ) {
my ($k,$v) = @objtests[$i,$i+1];
$obj = $k->new(\&dosomething);
run_test(sub {$obj->doit},$v);
}
package ObjTest1;
sub new {my $class = shift; return bless {},$class}
sub doit { my $self = shift; ::dosomething(); }
package ObjTest2;
sub new {my $class = shift;my $sub = shift;
return bless {sub=>$sub},$class}
sub doit { my $self = shift; $self->{sub}->(); }
package ObjTest3;
use base 'ObjTest2';
package ObjTestS1;
use base 'ObjTest2';
sub doit { my $self = shift; $self->SUPER::doit(@_); }
package ObjTestS2;
use base 'ObjTestS1';
sub doit { my $self = shift; $self->SUPER::doit(@_); }
package ObjTestS3;
use base 'ObjTestS2';
sub doit { my $self = shift; $self->SUPER::doit(@_); }
package ObjTestS4;
use base 'ObjTestS3';
sub doit { my $self = shift; $self->SUPER::doit(@_); }
package ObjTestN1;
use base 'ObjTest2';
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package ObjTestN2;
use base 'ObjTestN1';
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package ObjTestN3;
use base 'ObjTestN2';
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package ObjTestN4;
use base 'ObjTestN3';
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package Dummy1; sub blank{};
package Dummy2; sub blank{};
package Dummy3; sub blank{};
package Dummy4; sub blank{};
package ObjTestND4;
use base qw/Dummy1 Dummy2 Dummy3 Dummy4 ObjTestN1/;
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package Dummy5; sub blank{};
package Dummy6; sub blank{};
package Dummy7; sub blank{};
package Dummy8; sub blank{};
package ObjTestND8;
use base qw/Dummy5 Dummy6 Dummy7 Dummy8 ObjTestND4/;
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package PassThrough1; sub doit { my $self = shift; $self->NEXT::doit(@_); }
package PassThrough2; sub doit { my $self = shift; $self->NEXT::doit(@_); }
package PassThrough3; sub doit { my $self = shift; $self->NEXT::doit(@_); }
package PassThrough4; sub doit { my $self = shift; $self->NEXT::doit(@_); }
package ObjTestNPT4;
use base qw/PassThrough1 PassThrough2 PassThrough3 PassThrough4 ObjTestN1/;
use NEXT;
sub doit { my $self = shift; $self->NEXT::doit(@_); }
package PTA1; sub doit { my $self = shift; $self->NEXT::ACTUAL::doit(@_); }
package PTA2; sub doit { my $self = shift; $self->NEXT::ACTUAL::doit(@_); }
package PTA3; sub doit { my $self = shift; $self->NEXT::ACTUAL::doit(@_); }
package PTA4; sub doit { my $self = shift; $self->NEXT::ACTUAL::doit(@_); }
package ObjTestNPTA4;
use base qw/PTA1 PTA2 PTA3 PTA4 ObjTestN1/;
use NEXT;
sub doit { my $self = shift; $self->NEXT::ACTUAL::doit(@_); }
package ObjTestC31;
use base 'ObjTest2';
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package ObjTestC32;
use base 'ObjTestC31';
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package ObjTestC33;
use base 'ObjTestC32';
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package ObjTestC34;
use base 'ObjTestC33';
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package ObjTestC3D4;
use base qw/Dummy1 Dummy2 Dummy3 Dummy4 ObjTestC31/;
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package ObjTestC3D8;
use base qw/Dummy5 Dummy6 Dummy7 Dummy8 ObjTestC3D4/;
use Class::C3;
sub doit { my $self = shift; $self->next::method(@_); }
package main;
my $start;
sub timer_start { $start = [gettimeofday]; }
sub timer_stop { return tv_interval $start; }
sub run_test {
my $sub = shift;
my $name = shift;
timer_start();
for (1..$num_iters) {
$sub->();
}
$time = timer_stop();
printf "%40s %6.3f s %6.1f us/iter\n",
$name,$time,($time/$num_iters)*1000000;
}
--
Matt S Trout Specialists in Perl consulting, web development, and
Technical Director UNIX/Linux systems architecture and automation. Mail
Shadowcat Systems Ltd. mst (at) shadowcatsystems.co.uk for more information
+ Help us build a better perl ORM: http://dbix-class.shadowcatsystems.co.uk/ +
More information about the Dbix-class
mailing list