Hi to all who have answered!
Thanks for all your input.
Of course my question was driven by "need for speed".
I tried to minimize the number of loops to go over the buffer (2k, 4k, 8k, or 16k of values)
I extended the benchmark script and put the different solutions all in there.
Below you can see the results.
Three things:
-I was astonished that the unpack_pack_unpack way is still twice as fast as my solution using bitstrings.
-the solution with the borrowed pad to 8 bytes is
really nifty! With one single buffer padding,
one can nearly achieve what I wanted first. One unpack only.
-Next surprise: the used
$_ &= $mask for @values;
does the same as
map { $_ &= $mask) @values;
but is about 25% faster....Must be the useless generation of the resulting array...
(the test with
@values = map { $_ &= $mask) @values; gets a rate of only 4000/s!!)
So of course I'll go with the fastest solution, which has the advantage that it includes the
easy case of 8 bytes per value at no cost when I pre-compute the unpack format.
Thanks again,
Axel
se strict;
use warnings;
no warnings 'portable';
use Benchmark 'cmpthese';
my $bytes_per_value = 5;
my $count = 1_000;
my $value = 0xf_dead_beef_4;
my $bin_value = substr (pack ('Q', $value), 0, $bytes_per_value);
my $buffer = $bin_value x $count;
my $fmt = sprintf "(b%d)*", $bytes_per_value << 3;
my $pad_len = 8 - $bytes_per_value;
my $mask = ~ 0 >> $pad_len * 8;
my $pad = "\0" x $pad_len;
my @fmts = ('(Q<)', '(Q<X)', '(Q<X2)', '(Q<X3)');
my $fmt2 = $fmts[$pad_len] . sprintf ("%d", $count);
cmpthese -1, {
strings => sub {
my @values = map { oct '0b'.reverse ($_)} unpack ($fmt, $buffe
+r);
return \@values;
},
map_unpack => sub {
my @values = map { unpack 'Q<', "$_$pad" } unpack "(a$bytes_p
+er_value)*", $buffer;
return \@values;
},
unpack_pack_unpack => sub {
my @values = unpack '(Q<)*', pack '(a8)*', unpack "(a$bytes_pe
+r_value)*", $buffer;
},
numbers_map => sub {
my @values = unpack "(QX$pad_len)$count", $buffer.$pad;
map { $_ &= $mask } @values;
return \@values;
},
numbers_for => sub {
my @values = unpack $fmt2, $buffer.$pad;
if ($pad_len) {
$_ &= $mask for @values;
}
return \@values;
},
};
__END__
Rate strings map_unpack unpack_pack_unpack number
+s_map numbers_for
strings 1707/s -- -28% -47%
+ -69% -77%
map_unpack 2386/s 40% -- -26%
+ -56% -68%
unpack_pack_unpack 3242/s 90% 36% --
+ -41% -57%
numbers_map 5462/s 220% 129% 68%
+ -- -28%
numbers_for 7538/s 342% 216% 133%
+ 38% --
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.