heh, unpack is actually faster than a custom XS solution (since it's not called via entersub???)
unpack: 1.200000 1.400000 1.800000 12345678.901230 2147483648
custom: 1.200000 1.400000 1.800000 12345678.901230 2147483648
nonportable: 1.200000 1.400000 1.800000 12345678.901230 2147483648
unsafe: 1.200000 1.400000 1.800000 12345678.901230 2147483648
Rate custom unsafe nonportable unpack
custom 524225/s -- -6% -6% -20%
unsafe 555156/s 6% -- -1% -16%
nonportable 559449/s 7% 1% -- -15%
unpack 658398/s 26% 19% 18% --
(Some variation, but this is a typical run)
You could save a itsy teeny bit by going to pure XS rather than using Inline::C, but I doubt it will be noticeable.
use strict;
use warnings;
use Benchmark qw( cmpthese );
use Inline C => <<'__EOI__';
/* unpack("FFFFL", sv) */
void custom_unpack(SV* sv) {
dXSARGS;
NV f1;
NV f2;
NV f3;
NV f4;
U32 u;
STRLEN len;
char* buf = SvPVbyte(sv, len);
if (len != sizeof(NV)*4 + sizeof(U32))
croak("Length mismatch");
memcpy(&f1, buf, sizeof(NV)); buf += sizeof(NV);
memcpy(&f2, buf, sizeof(NV)); buf += sizeof(NV);
memcpy(&f3, buf, sizeof(NV)); buf += sizeof(NV);
memcpy(&f4, buf, sizeof(NV)); buf += sizeof(NV);
memcpy(&u, buf, sizeof(U32));
SP -= items;
EXTEND(SP, 5);
mPUSHn(f1);
mPUSHn(f2);
mPUSHn(f3);
mPUSHn(f4);
mPUSHu(u);
XSRETURN(5);
}
/* unpack("FFFFL", sv) */
/* Only works on machine where NV */
/* and U32 can be byte-aligned */
void custom_unpack_nonportable(SV* sv) {
dXSARGS;
STRLEN len;
char* buf = SvPVbyte(sv, len);
if (len != sizeof(NV)*4 + sizeof(U32))
croak("Length mismatch");
SP -= items;
EXTEND(SP, 5);
mPUSHn(*(NV*)buf);
mPUSHn(*(NV*)(buf + sizeof(NV)));
mPUSHn(*(NV*)(buf + sizeof(NV)*2));
mPUSHn(*(NV*)(buf + sizeof(NV)*3));
mPUSHn(*(U32*)(buf + sizeof(NV)*4));
XSRETURN(5);
}
/* unpack("FFFFL", sv) */
/* Doesn't get magic */
/* Doesn't stringify */
/* Doesn't switch string format */
/* Doesn't do size checks */
/* Only works on machine where NV */
/* and U32 can be byte-aligned */
void custom_unpack_unsafe(SV* sv) {
dXSARGS;
char* buf = SvPVX(sv);
SP -= items;
EXTEND(SP, 5);
mPUSHn(*(NV*)buf);
mPUSHn(*(NV*)(buf + sizeof(NV)));
mPUSHn(*(NV*)(buf + sizeof(NV)*2));
mPUSHn(*(NV*)(buf + sizeof(NV)*3));
mPUSHn(*(U32*)(buf + sizeof(NV)*4));
XSRETURN(5);
}
__EOI__
my %tests = (
'unpack' => 'my @x = unpack("FFFFL", $buf);',
'custom' => 'my @x = custom_unpack($buf);',
'nonportable' => 'my @x = custom_unpack_nonportable($buf);',
'unsafe' => 'my @x = custom_unpack_unsafe($buf);',
);
$_ = 'use strict; use warnings; our $buf; ' . $_
for values(%tests);
local our $buf = pack('FFFFL', 1.2, 1.4, 1.8, 12345678.90123, 0x800000
+00);
printf("unpack: %f %f %f %f %u\n", unpack("FFFFL", $buf));
printf("custom: %f %f %f %f %u\n", custom_unpack($buf));
printf("nonportable: %f %f %f %f %u\n", custom_unpack_nonportable($buf
+));
printf("unsafe: %f %f %f %f %u\n", custom_unpack_unsafe($buf));
cmpthese(-2, \%tests);
Update: Added custom_unpack_unsafe
|