Skip to content

Commit

Permalink
murmur3: add PC hash inverse
Browse files Browse the repository at this point in the history
Adds inline routines to calculate Murmur3-32 for program counters and
the inverse.
  • Loading branch information
riptl authored and ripatel-fd committed Jan 25, 2024
1 parent 902c3b6 commit c16b514
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 44 deletions.
14 changes: 10 additions & 4 deletions src/ballet/murmur3/fd_murmur3.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "fd_murmur3.h"

uint
fd_murmur3_32( void const * _data,
ulong sz,
uint seed ) {
static uint
fd_murmur3_32_( void const * _data,
ulong sz,
uint seed ) {

uchar const * data = _data;
uint sz_tag = (uint)sz;
Expand Down Expand Up @@ -53,3 +53,9 @@ fd_murmur3_32( void const * _data,
return hash;
}

uint
fd_murmur3_32( void const * _data,
ulong sz,
uint seed ) {
return fd_murmur3_32_( _data, sz, seed );
}
51 changes: 51 additions & 0 deletions src/ballet/murmur3/fd_murmur3.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,57 @@ fd_murmur3_32( void const * data,
ulong sz,
uint seed );

/* fd_pchash computes the hash of a program counter suitable for use as
the call instruction immediate. Equivalent to fd_murmur3_32 with
zero seed and pc serialized to little-endian ulong. */

static inline uint
fd_pchash( uint pc ) {
uint x = pc;
x *= 0xcc9e2d51U;
x = fd_uint_rotate_left( x, 15 );
x *= 0x1b873593U;
x = fd_uint_rotate_left( x, 13 );
x *= 5;
x += 0xe6546b64U;
x = fd_uint_rotate_left( x, 13 );
x *= 5;
x += 0xe6546b64U;
x ^= 8;
x ^= x >> 16;
x *= 0x85ebca6bU;
x ^= x >> 13;
x *= 0xc2b2ae35U;
x ^= x >> 16;
return x;
}

/* Inverse of the above. E.g.:
fd_pchash_inverse( fd_pchash( (uint)x ) )==(uint)x
and:
fd_pchash( fd_pchash_inverse( (uint)x ) )==(uint)x */

static inline uint
fd_pchash_inverse( uint hash ) {
uint x = hash;
x ^= x >> 16;
x *= 0x7ed1b41dU;
x ^= (x >> 13) ^ (x >> 26);
x *= 0xa5cb9243U;
x ^= x >> 16;
x ^= 8;
x -= 0xe6546b64U;
x *= 0xcccccccdU;
x = fd_uint_rotate_right( x, 13 );
x -= 0xe6546b64U;
x *= 0xcccccccdU;
x = fd_uint_rotate_right( x, 13 );
x *= 0x56ed309bU;
x = fd_uint_rotate_right( x, 15 );
x *= 0xdee13bb1U;
return x;
}

FD_PROTOTYPES_END

#endif /* HEADER_fd_src_ballet_murmur3_fd_murmur3_h */
129 changes: 89 additions & 40 deletions src/ballet/murmur3/test_murmur3.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,49 +64,98 @@ main( int argc,
"\n\t\t", sz, hash, expected ));
}

FD_LOG_NOTICE(( "Benchmarking small inputs" ));

/* warmup */
uint hash = 42U;
for( ulong i=0UL; i<100000UL; i++ ) {
uint x[2] = { (uint)i, hash };
hash = fd_murmur3_32( &x, 8UL, 0 );
for( uint i=0U; i<10U<<17; i++ ) {
ulong pc = i;
uint hash = fd_murmur3_32( &pc, 8UL, 0U );
FD_TEST( fd_pchash( i )==hash );
FD_TEST( fd_pchash_inverse( hash )==i );
}

/* for real */
ulong bench_cnt = 100000000UL;
long dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ ) {
uint x[2] = { (uint)i, hash };
hash = fd_murmur3_32( &x, 8UL, 0 );
}
FD_COMPILER_FORGET( hash );
dt += fd_log_wallclock();
FD_LOG_NOTICE(( "%.3f ns/hash (sz 8)", (double)((float)dt / (float)bench_cnt) ));

FD_LOG_NOTICE(( "Benchmarking hashrate" ));

uchar msg[ 1024UL ];
ulong sz = 1024UL;
for( ulong i=0UL; i<sz; i+=8UL )
FD_STORE( ulong, msg+i, fd_rng_ulong( rng ) );

/* warmup */
for( ulong i=0UL; i<10000UL; i++ ) {
uint hash = fd_murmur3_32( &msg, sz, 0U );
FD_COMPILER_FORGET( hash );
}
FD_LOG_NOTICE(( "Benchmarking small inputs" ));

/* for real */
bench_cnt = 1000000UL;
dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ ) {
uint hash = fd_murmur3_32( &msg, sz, 0U );
__asm__( "" : "=m" (*msg) : "r" (hash) : "cc" );
}
dt += fd_log_wallclock();
double gbps = ((double)(8*bench_cnt*sz)) / ((double)dt);
FD_LOG_NOTICE(( "~%6.3f GiB/s (sz %4lu)", gbps, sz ));
do {
/* warmup */
uint hash = 42U;
for( ulong i=0UL; i<100000UL; i++ ) {
uint x[2] = { (uint)i, hash };
hash = fd_murmur3_32( &x, 8UL, 0 );
}

/* for real */
ulong bench_cnt = 100000000UL;
long dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ ) {
uint x[2] = { (uint)i, hash };
hash = fd_murmur3_32( &x, 8UL, 0 );
}
FD_COMPILER_UNPREDICTABLE( hash );
dt += fd_log_wallclock();
FD_LOG_NOTICE(( "%.3f ns/hash (sz 8)", (double)((float)dt / (float)bench_cnt) ));
} while(0);

FD_LOG_NOTICE(( "Benchmarking hashrate (generic)" ));

do {
uchar msg[ 1024UL ];
ulong sz = 1024UL;
for( ulong i=0UL; i<sz; i+=8UL )
FD_STORE( ulong, msg+i, fd_rng_ulong( rng ) );

/* warmup */
for( ulong i=0UL; i<10000UL; i++ ) {
uint hash = fd_murmur3_32( &msg, sz, 0U );
FD_COMPILER_FORGET( hash );
}

/* for real */
ulong bench_cnt = 1000000UL;
long dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ ) {
uint hash = fd_murmur3_32( &msg, sz, 0U );
__asm__( "" : "=m" (*msg) : "r" (hash) : "cc" );
}
dt += fd_log_wallclock();
double gbps = ((double)(8*bench_cnt*sz)) / ((double)dt);
FD_LOG_NOTICE(( "~%6.3f GiB/s (sz %4lu)", gbps, sz ));
} while(0);

FD_LOG_NOTICE(( "Benchmarking hashrate (pchash)" ));

do {
/* warmup */
uint hash = 42U;
for( ulong i=0UL; i<100000UL; i++ )
hash = fd_pchash( hash );

/* for real */
ulong bench_cnt = 100000000UL;
long dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ )
hash = fd_pchash( hash );
FD_COMPILER_UNPREDICTABLE( hash );

dt += fd_log_wallclock();
FD_LOG_NOTICE(( "%.3f ns/pchash", (double)((float)dt / (float)bench_cnt) ));
} while(0);

FD_LOG_NOTICE(( "Benchmarking hashrate (pchash_inverse)" ));

do {
/* warmup */
uint hash = 42U;
for( ulong i=0UL; i<100000UL; i++ )
hash = fd_pchash_inverse( hash );

/* for real */
ulong bench_cnt = 100000000UL;
long dt = -fd_log_wallclock();
for( ulong i=0UL; i<bench_cnt; i++ )
hash = fd_pchash_inverse( hash );
FD_COMPILER_UNPREDICTABLE( hash );

dt += fd_log_wallclock();
FD_LOG_NOTICE(( "%.3f ns/pchash", (double)((float)dt / (float)bench_cnt) ));
} while(0);

fd_rng_delete( fd_rng_leave( rng ) );
FD_LOG_NOTICE(( "pass" ));
Expand Down

0 comments on commit c16b514

Please sign in to comment.