in reply to Re^2: unpacking 6-bit values
in thread unpacking 6-bit values

I see a decline of close to 20% for adding mortality. The other big difference between my algorithm (and how I tested it) and the once you posted are that mine are not depending on the length of the buffer and are therefor more generic. The huge disadvantage in my testing is also the fact that I only use one single buffer, causing all 4095 values to be placed on the stack at once. And they all have to be removed when the test is done (something the non-mortalizing version skips).

Still the mortalizing version of my algorithm in C/XS is still 6 times faster than the uu version.

Thanks for the thread, it was fun to untangle.


Enjoy, Have FUN! H.Merijn

Replies are listed 'Best First'.
Re^4: unpacking 6-bit values
by BrowserUk (Patriarch) on Dec 11, 2010 at 15:44 UTC
    The other big difference between my algorithm (and how I tested it) and the once you posted are that mine are not depending on the length of the buffer and are therefor more generic.

    I should point out that the hard coded 24s in my code versions are there because I know that is the only length I will be dealing with. Discovering the length from the passed scalar, (and checking it is a multiple of 3), would have little or no effect upon performance.

    The point about the mortalisation comes into stark relief when you run your code in a tight loop. Where this version consumes a steady 14.7 MB for as long as you care to run it:

    #! perl -slw use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => '_24to32', CLEAN_AFTER_BUILD => 0; void uic( SV *src ) { int i = 0; STRLEN l; unsigned char *s = (unsigned char *)SvPV( src, l ); inline_stack_vars; inline_stack_reset; while (i < l) { int n = ( s[i] >> 2 ) & 0x3f; inline_stack_push( sv_2mortal( newSViv( n ) ) ); n = ( s[ i++ ] & 0x03 ) << 4; n |= ( s[i] >> 4 ) & 0x0f; inline_stack_push( sv_2mortal( newSViv( n ) ) ); n = ( s[ i++ ] & 0x0f ) << 2; n |= ( s[i] >> 6 ) & 0x03; inline_stack_push( sv_2mortal( newSViv( n ) ) ); n = s[ i++ ] & 0x3f; inline_stack_push( sv_2mortal( newSViv( n ) ) ); } inline_stack_done; } END_C use Math::Random::MT qw[ rand ]; while( 1 ) { my $packed = pack 'N6', map rand( 2**32 ), 1 .. 6; my @decoded = uic( $packed ); }

    This version:

    #! perl -slw use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => '_24to32', CLEAN_AFTER_BUILD => 0; void uic( SV *src ) { int i = 0; STRLEN l; unsigned char *s = (unsigned char *)SvPV( src, l ); inline_stack_vars; inline_stack_reset; while (i < l) { int n = ( s[i] >> 2 ) & 0x3f; inline_stack_push( newSViv( n ) ); n = ( s[ i++ ] & 0x03 ) << 4; n |= ( s[i] >> 4 ) & 0x0f; inline_stack_push( newSViv( n ) ); n = ( s[ i++ ] & 0x0f ) << 2; n |= ( s[i] >> 6 ) & 0x03; inline_stack_push( newSViv( n ) ); n = s[ i++ ] & 0x3f; inline_stack_push( newSViv( n ) ); } inline_stack_done; } END_C use Math::Random::MT qw[ rand ]; while( 1 ) { my $packed = pack 'N6', map rand( 2**32 ), 1 .. 6; my @decoded = uic( $packed ); }

    leaks memory at the rate of 3GB per minute, which means it has my machine swapping after less than 2 minutes and dies "Out of memory|", having consume all 16GB of swap space, some time later. Whatever the performance hit, it is unavoidable. It ought (and I believe could), be cheaper though.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.