Looking for new maintainer for Memcached::libmemcached

Howdy folks.

I offered to help Tim Bunce maintain Memcached::libmemcached earlier this year and managed to get a single release out with a few fixes.

I intended a second release to solve some compilation issues, but never got around it, and I'm not sure I ever will - there's still more work to do to there, and my time/interests have moved on.

I'm looking for someone to take over maintainership of this. Bug reports have been fairly minimal so far, most of it coming down to "Please update to latest upstream version" or "allow to link against system version instead of bun…

Perl QA 2014 Recap

This year's Perl QA Hackathon has come and gone. I had an amazing time, and

The QA Hackathon is a gathering with the purpose of improving Perl's toolchain, testing infrastructure, and other bits surrounding language development and usage. At it's core is an incredibly friendly and intelligent group of people, and I always leave the conference feeling reinvigorated and motivated to get things done (and with a much larger todo list than I had going in...)

I brought my fiancée and a friend with me (we had a mini-vacation in Lyon after the c…

Perl 5.19.x performance improvements

Perl 5.19.9 was released today, and it includes some exciting new features like subroutine signatures, and postfix dereferencing.

The 5.19.X line also includes a number of optimisations that I'd like to discuss briefly, without going into too much detail (I hope).

Combined and/or operators in void context

The first improvement was added back in 5.19.6, and effects and and or operators in void context. It improves the short-cirtcuiting logic of and/or operations when inside of an if statement.

What this means is that in many cases, this:

if ($var1 || $var2) { ... }

will be ever-so-slightly faster if $var1 is true than it used to, and

unless ($var1 && $var2) { ... }

will be ever-so-slightly faster if $var1 is false. This is about a 2% speed improvement in my tests, for each of the above constructs being evaluated.

return at end of sub optimised out

This improvement was added in 5.19.8, and optimises out a return statement at the end of a sub so that:

return $x;

is compiled as

$x;

which is a fair bit faster (about 10%) since a return statement actually includes a few more ops behind the scenes than necessary for these cases.

Multiple single PADOPs combined into a list

The final optimisation was just released with 5.19.9 and turns multiple single PADOPs into its list form.

That means this:

my $x;
my $y;

becomes this:

my ($x, $y);

Which then can be optimised into a single PADRANGE op which was added back in 5.18.0.

This gives a speedup of about 7% in the above case, and will have a greater effect if more PADOPS (my $x; my @y; my %z) are used in a row.

Testing

For light testing, I used a best-case scenario subroutine for all above optimisations, and enabled each in turn to see how the sub improved. (I didn't test them individually, so numbers may vary. IE: I enabled return optimisations, then padrange optimisations, then and/or in void context optimisations).

Using this program:

#!/usr/bin/perl
use strict;
use warnings;

my $aa = 1;
my $bb = 0;

sub somesub {
        my $x;
        my $y;

        if ($aa || $bb) {
                $x = 1;
        }

        return $x;
}

for (1..50_000_000) {
        somesub();
}

I ran it 3 times for each test using "time ./opt.pl" (I know, start up costs skew results, but only ever so slightly in comparison to what was being tested in this case, and yes, 3 is not enough to give a really good average...), and averaged out the results:

Original:                                      6.69s
Optimise out return:                           6.03s   10% speedup
Optimise my $x; my $y; into my ($x; $y);:      5.62s    7% speedup
Optimise if ($a || $b) { ... } if $a is true:  5.53s    2% speedup

Total:                                                 19% speedup

I'm pretty happy with the results.

Playing with Perl's optimiser was a lot of fun (and a fair amount of frustration :)), and I hope to do more work in this area.

Perl 5.20 (which is set to release May of this year) will includes these optimisations, and I hope to have many more for 5.22 next year.

Cheers,

-- Matthew Horsfall (alh)

P.S. If anyone wants more in-depth details of the optimisations, I'm happy to provide them. (Separate blog posts?)

Devel::Quick - Simple DB::DB routines on the fly

Just wanted to share a new little debugging tool, Devel::Quick.

It allows you to write DB::DB subroutines on the fly, and provides a few variables by default to make things simpler.

Background

DB::DB (the DB subroutine under the DB package) -- if defined when Perl is run under '-d' -- will be executed before every line in the Perl source being run. If the DB::DB call is within a subroutine, you can also peak at the arguments passed into the sub.

Example

A simple example of a module using this is Devel::Trace, which will print out the source code about to be executed for every line.

With Devel::Quick, we can recreate this functionality like so:

$ perl -d:Quick='print ">> $filename:$line $code"' prog.pl

Or with -e

$ perl -d:Quick='print ">> $filename:$line $code"' -e 'print "Hello!\n";  
my $x = 3 + 5;  
print "X: $x\n";
'
>> -e:1 print "Hello!\n";
Hello!
>> -e:2 my $x = 3 + 5; 
>> -e:3 print "X: $x\n";
X: 8

Behind the scenes:

All that Devel::Quick is really doing is wrapping your code in this block:

package DB;

use strict;
use warnings;

sub DB {
    my ($package, $filename, $line,
           $subroutine, $hasargs, $wantarray,
           $evaltext, $is_require, $hints,
           $bitmask, $hinthash) = caller(0);

    my $args = \@_;

    my $code;
    {
        no strict 'refs';
        $code = @{"::_<$filename"}[$line];
    }

    no strict;

    <<CODE>>
}

By default, strict is turned off to make the one-liners easier, but you can enable it by doing:

perl -d:Quick=-strict,'print "..."'

or

perl -d:Quick=-s,'print "..."'

For more information, check out Devel::Quick on metacpan.

More Info

For more information on Perl debugging, see:

Cheers,

-- Matthew Horsfall (alh)

Introducing Devel::Nopeep, Devel::GDB::Breakpoint, and Devel::GDB::Parser::Breakpoint

I've created 3 new modules to help me out when working on the Perl core; I'm sharing them in the event others find them useful.

They are:

Devel::Nopeep

This module disables the peephole optimiser so that you can see what the op tree would look like before it works its magic (and benchmark the differences, if you like).

For example:

$ perl -MO=Concise -e 'if ($a && $b) {}'
8  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 3 -e:1) v:{ ->3
-     <1> null vK/1 ->8
6        <|> and(other->7) vK/1 ->8
-           <1> null sK/1 ->6
4              <|> and(other->5) sK/1 ->8
->                  <1> ex-rv2sv sK/1 ->4
3                    <$> gvsv(*a) s ->4
-                 <1> ex-rv2sv sK/1 ->-
5                    <$> gvsv(*b) s ->6
-           <@> scope vK ->-
7              <0> stub v ->8
-e syntax OK

Versus:

$ perl -MDevel::Nopeep -MO=Concise -e 'if ($a && $b) {}'
a  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 3 -e:1) v:{ ->3
-     <1> null vK/1 ->a
8        <|> and(other->9) vK/1 ->-
-           <1> null sK/1 ->8
5              <|> and(other->6) sK/1 ->-
4                 <1> rv2sv sK/1 ->5
3                    <$> gv(*a) s ->4
7                 <1> rv2sv sK/1 ->-
6                    <$> gv(*b) s ->7
-           <@> scope vK ->-
9              <0> stub v ->-
-e syntax OK

Devel::GDB::Breakpoint

This module lets you set breakpoints in your Perl code that you can easily match up to with gdb. If you have a large program and you want to break in different places, you can:

use Devel::GDB::Breakpoint;

breakpoint 3;
breakpoint 4;

And then with gdb:

$ gdb --args perl prog.pl
(gdb) b bp if val == 3
(gdb) b bp if val == 4
(gdb) run

Each Perl call to breakpoint sets up a call to the C function void bp(int val); that will be called at runtime.

Devel::GDB::Parser::Breakpoint

This module builds off of Devel::GDB::Breakpoint and allows you to set breakpoints that will be triggered when perl parses the code in question, way before it ever runs it (think BEGIN {}).

For example:

use Devel::GDB::Parser::Breakpoint;

if ($a && $b && parser_breakpoint 42 && $c) { }

And then like above:

$ gdb --args prog.pl
(gdb) b bp if val == 42
(gdb) run

I'll be spending a lot more time playing with Perl and might have some more things to share in the near future.

Cheers,

-- Matthew Horsfall (alh)