Tags Perl

It is astonishing how different can be a performance of two trivial functions accomplishing the same task. In the last month, I needed a function to convert a string representing a binary number (i.e. "0101") to an integer (5). The first time, for a script that helps verify some VHDL test-benches, I used the following implementation from the Cookbook:

sub bin2dec
{
    return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}

The second time I forgot about the first time (typical), and implemented such a function myself:

sub binstr2num
{
    my @arr = split(//, $_[0]);

    my $val = 0;
    my $deg = 1;

    for (my $i = 31; $i >= 0; --$i)
    {
        $val += $deg if ($arr[$i] == 1);
        $deg *= 2;
    }

    return $val;
}

The second time it was for a toy implementation of a genetic algorithm (that "guesses" a number), so I noticed some performance problems - it ran too slow !

So, a little optimization was required. No problems, Perl gives all the tools for that. I ran perl on my script with -d:DProf, then run dprofpp, to see that my function binstr2num was taking most of the time (it is called quite often).

Only now I recalled that I used an implementation from the Cookbook only recently. And if it's from the Cookbook, it must be Good (TM), right ?

Right !! The Benchmark module came in very handy here, and the following was quickly coded:

my $vec = "01111110110101101100001011010101";

timethese($count, {
    'bin2dec'         => sub {bin2dec($vec)},
    'binstr2num'    => sub {binstr2num($vec)}});

And viola !

Benchmark: timing 1000000 iterations of bin2dec, binstr2num...
  bin2dec:  2 wallclock secs ( 2.59 usr +  0.00 sys =  2.59 CPU) @ 385505.01/s (n=1000000)
  binstr2num: 100 wallclock secs (98.47 usr +  0.00 sys = 98.47 CPU) @ 10155.58/s (n=1000000)

This is one big difference, ouch !!