perl method definition benchmark

2010-12-01 perl method class Benchmark MooseX::Declare Method::Signatures::Simple Function::Parameters

Update 2024-11-25: Added Function::Parameters into the benchmark.

Here is benchmark of running methods of perl class defined by several methods:

Introduction

There are ways how to avoid typing when defining a perl classes. While modules like Moose or Class::Accessor typically take care of attribute accessor generation while methods are usually left as they are in plain perl. Usual pattern looks like this:

sub run {
    my $self = shift;
    my ($bar, $baz, %opts) = @_;
    
    ...
}

I used MooseX::Declare (MXD) in one of my recent larger projects. It looks nice

method run($bar, $baz, %opts) {
    ...
}

but I quickly realized that it is slow. Very slow. So I reverted it back to plain perl by a small script and stopped thinking about methods and their signatures.

But recently I found another module trying to achieve same syntax, Method::Signatures::Simple (MSS). Still remembering previous lesson, made some benchmarks to prevent surprises later. Further work led me to use of Function::Parameters, which has even nicer syntax.

Results

Benchmark module brings handy cmpthese function, that runs the variants and creates handy comparison table:

            Rate    mxd  plain    mss     fp
mxd      46367/s     --  -100%  -100%  -100%
plain 11851048/s 25459%     --    -9%   -18%
mss   13025677/s 27992%    10%     --   -10%
fp    14485495/s 31141%    22%    11%     --

It looks that MSS bring very minor penalty, while slowness of MXD is more than apparent. What was pretty surprising, Function::Parameters that use keyword filter built in more recent perls is even faster than plain method.

Benchmark source

use Benchmark qw(:all);

my $plain = Plain->new();
my $mss   = MSS->new();
my $mxd   = MXD->new();
my $fp    = FP->new();

cmpthese(-2, {
    plain => sub { $plain->run(10,20) },
    mss   => sub { $mss->run(10,20)   },
    mxd   => sub { $mxd->run(10,20)   },
    fp    => sub { $fp->run(10,20)    },
});

BEGIN {
    package Plain;
    sub new { bless {},shift }
    sub run {
        my ($self,$a,$b) = @_;
        my ($c,$d) = ($a,$b);
    }


    package MSS;
    use Method::Signatures::Simple;
    sub new { bless {},shift }
    method run($a,$b) {
        my ($c,$d) = ($a,$b);
    }


    use MooseX::Declare;
    class MXD {
        method run($a,$b) {
            my ($c,$d) = ($a,$b);
        }
    }


    package FP;
    use Function::Parameters;
    sub new { bless {},shift }
    method run($a,$b) {
        my ($c,$d) = ($a,$b);
    }
}