LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_bloom.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 312 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 22 0.0 %

          Line data    Source code
       1             : #include "fd_bloom.h"
       2             : 
       3             : #include "../../util/log/fd_log.h"
       4             : #if FD_HAS_AVX512
       5             : #include "../../util/simd/fd_avx512.h"
       6             : #endif
       7             : 
       8             : #include <math.h>
       9             : 
      10             : static const double FD_BLOOM_LN_2 = 0.69314718055994530941723212145818;
      11             : FD_FN_CONST ulong
      12           0 : fd_bloom_align( void ) {
      13           0 :   return FD_BLOOM_ALIGN;
      14           0 : }
      15             : 
      16             : FD_FN_CONST ulong
      17             : fd_bloom_footprint( double false_positive_rate,
      18           0 :                     ulong  max_bits ) {
      19           0 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return 0UL;
      20           0 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return 0UL;
      21             : 
      22           0 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return 0UL;
      23             : 
      24           0 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      25             : 
      26           0 :   ulong l;
      27           0 :   l = FD_LAYOUT_INIT;
      28           0 :   l = FD_LAYOUT_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      29           0 :   l = FD_LAYOUT_APPEND( l, 8UL,            num_keys*sizeof(ulong) );
      30           0 :   l = FD_LAYOUT_APPEND( l, 8UL,            (max_bits+7UL)/8UL );
      31           0 :   return FD_LAYOUT_FINI( l, FD_BLOOM_ALIGN );
      32           0 : }
      33             : 
      34             : void *
      35             : fd_bloom_new( void *     shmem,
      36             :               fd_rng_t * rng,
      37             :               double     false_positive_rate,
      38           0 :               ulong      max_bits ) {
      39             : 
      40           0 :   if( FD_UNLIKELY( !shmem ) ) {
      41           0 :     FD_LOG_WARNING(( "NULL shmem" ));
      42           0 :     return NULL;
      43           0 :   }
      44             : 
      45           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_bloom_align() ) ) ) {
      46           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
      47           0 :     return NULL;
      48           0 :   }
      49             : 
      50           0 :   if( FD_UNLIKELY( false_positive_rate<=0.0 ) ) return NULL;
      51           0 :   if( FD_UNLIKELY( false_positive_rate>=1.0 ) ) return NULL;
      52             : 
      53           0 :   if( FD_UNLIKELY( max_bits<1UL || max_bits>32768UL ) ) return NULL;
      54             : 
      55           0 :   if( FD_UNLIKELY( !rng ) ) return NULL;
      56             : 
      57           0 :   ulong num_keys = (ulong)( round( (double)max_bits*FD_BLOOM_LN_2 ) );
      58             : 
      59           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      60           0 :   fd_bloom_t * bloom = FD_SCRATCH_ALLOC_APPEND( l, FD_BLOOM_ALIGN, sizeof(fd_bloom_t) );
      61           0 :   void * _keys       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, num_keys*sizeof(ulong) );
      62           0 :   void * _bits       = FD_SCRATCH_ALLOC_APPEND( l, 8UL, (max_bits+7UL)/8UL );
      63           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, FD_BLOOM_ALIGN ) == (ulong)shmem + fd_bloom_footprint( false_positive_rate, max_bits ) );
      64             : 
      65           0 :   bloom->keys      = (ulong *)_keys;
      66           0 :   bloom->keys_len  = 0UL;
      67           0 :   bloom->bits      = (ulong *)_bits;
      68           0 :   bloom->bits_len  = 0UL;
      69             : 
      70           0 :   bloom->hash_seed = 0UL;
      71           0 :   bloom->rng       = rng;
      72             : 
      73           0 :   bloom->false_positive_rate = false_positive_rate;
      74           0 :   bloom->max_bits = max_bits;
      75             : 
      76           0 :   FD_COMPILER_MFENCE();
      77           0 :   FD_VOLATILE( bloom->magic ) = FD_BLOOM_MAGIC;
      78           0 :   FD_COMPILER_MFENCE();
      79             : 
      80           0 :   return (void *)bloom;
      81           0 : }
      82             : 
      83             : fd_bloom_t *
      84           0 : fd_bloom_join( void * shbloom ) {
      85           0 :   if( FD_UNLIKELY( !shbloom ) ) {
      86           0 :     FD_LOG_WARNING(( "NULL shbloom" ));
      87           0 :     return NULL;
      88           0 :   }
      89             : 
      90           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shbloom, fd_bloom_align() ) ) ) {
      91           0 :     FD_LOG_WARNING(( "misaligned shbloom" ));
      92           0 :     return NULL;
      93           0 :   }
      94             : 
      95           0 :   fd_bloom_t * bloom = (fd_bloom_t *)shbloom;
      96             : 
      97           0 :   if( FD_UNLIKELY( bloom->magic!=FD_BLOOM_MAGIC ) ) {
      98           0 :     FD_LOG_WARNING(( "bad magic" ));
      99           0 :     return NULL;
     100           0 :   }
     101             : 
     102           0 :   return bloom;
     103           0 : }
     104             : 
     105             : void
     106             : fd_bloom_initialize( fd_bloom_t * bloom,
     107           0 :                      ulong        num_items ) {
     108           0 :   double num_bits = ceil( ((double)num_items * log( bloom->false_positive_rate )) / log( 1.0 / pow( 2.0, log( 2.0 ) ) ) );
     109           0 :   num_bits = fmax( 1.0, fmin( (double)bloom->max_bits, num_bits ) );
     110             : 
     111           0 :   ulong num_keys;
     112           0 :   if( FD_UNLIKELY( num_items == 0UL ) ) {
     113           0 :     num_keys = 0UL;
     114           0 :   } else {
     115           0 :     num_keys = fd_ulong_max( 1UL, (ulong)( round( ((double)num_bits/(double)num_items) * FD_BLOOM_LN_2 ) ) );
     116           0 :   }
     117           0 :   for( ulong i=0UL; i<num_keys; i++ ) bloom->keys[ i ] = fd_rng_ulong( bloom->rng );
     118             : 
     119           0 :   bloom->keys_len = num_keys;
     120           0 :   bloom->bits_len = (ulong)num_bits;
     121           0 :   fd_memset( bloom->bits, 0, (ulong)((num_bits+7UL)/8UL) );
     122           0 : }
     123             : 
     124             : static inline ulong
     125             : fnv_hasher( uchar const * ele,
     126             :             ulong         ele_sz,
     127           0 :             ulong         key ) {
     128           0 :   for( ulong i=0UL; i<ele_sz; i++ ) key = (key^(ulong)ele[i])*1099511628211UL;
     129           0 :   return key;
     130           0 : }
     131             : 
     132             : static inline void
     133             : fnv_hasher4( uchar const * ele,
     134             :              ulong         ele_sz,
     135             :              ulong const * keys,
     136             :              ulong         key_cnt,
     137           0 :              ulong         out[ static 4 ] ) {
     138           0 :   ulong h0 = keys[ 0 ];
     139           0 :   ulong h1 = keys[ fd_ulong_if( key_cnt>1UL, 1UL, 0UL ) ];
     140           0 :   ulong h2 = keys[ fd_ulong_if( key_cnt>2UL, 2UL, 0UL ) ];
     141           0 :   ulong h3 = keys[ fd_ulong_if( key_cnt>3UL, 3UL, 0UL ) ];
     142           0 :   for( ulong i=0UL; i<ele_sz; i++ ) {
     143           0 :     ulong b = (ulong)ele[i];
     144           0 :     h0 = (h0^b)*1099511628211UL;
     145           0 :     h1 = (h1^b)*1099511628211UL;
     146           0 :     h2 = (h2^b)*1099511628211UL;
     147           0 :     h3 = (h3^b)*1099511628211UL;
     148           0 :   }
     149           0 :   out[0] = h0; out[1] = h1; out[2] = h2; out[3] = h3;
     150           0 : }
     151             : 
     152             : void
     153             : fd_bloom_insert( fd_bloom_t *  bloom,
     154             :                  uchar const * key,
     155           0 :                  ulong         key_sz ) {
     156           0 :   if( FD_UNLIKELY( !bloom->bits_len ) ) return;
     157           0 :   if( FD_UNLIKELY( bloom->keys_len==1UL ) ) { /* one chain, not four */
     158           0 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ 0 ] ) % bloom->bits_len;
     159           0 :     bloom->bits[ bit / 64UL ] |= (1UL << (bit % 64UL));
     160           0 :     return;
     161           0 :   }
     162           0 :   for( ulong i=0UL; i<bloom->keys_len; i+=4UL ) {
     163           0 :     ulong cnt = fd_ulong_min( bloom->keys_len-i, 4UL );
     164           0 :     ulong h[4];
     165           0 :     fnv_hasher4( key, key_sz, bloom->keys+i, cnt, h );
     166           0 :     for( ulong j=0UL; j<cnt; j++ ) {
     167           0 :       ulong bit = h[ j ] % bloom->bits_len;
     168           0 :       bloom->bits[ bit / 64UL ] |= (1UL << (bit % 64UL));
     169           0 :     }
     170           0 :   }
     171           0 : }
     172             : 
     173             : int
     174             : fd_bloom_contains( fd_bloom_t *  bloom,
     175             :                    uchar const * key,
     176           0 :                    ulong         key_sz ) {
     177           0 :   if( FD_UNLIKELY( !bloom->keys_len || !bloom->bits_len ) ) return 0;
     178           0 :   if( FD_UNLIKELY( bloom->keys_len==1UL ) ) {
     179           0 :     ulong bit = fnv_hasher( key, key_sz, bloom->keys[ 0 ] ) % bloom->bits_len;
     180           0 :     return !!(bloom->bits[ bit / 64UL ] & (1UL << (bit % 64UL)));
     181           0 :   }
     182           0 :   for( ulong i=0UL; i<bloom->keys_len; i+=4UL ) {
     183           0 :     ulong cnt = fd_ulong_min( bloom->keys_len-i, 4UL );
     184           0 :     ulong h[4];
     185           0 :     fnv_hasher4( key, key_sz, bloom->keys+i, cnt, h );
     186           0 :     for( ulong j=0UL; j<cnt; j++ ) {
     187           0 :       ulong bit = h[ j ] % bloom->bits_len;
     188           0 :       if( !(bloom->bits[ bit / 64UL ] & (1UL << (bit % 64UL))) ) {
     189           0 :         return 0;
     190           0 :       }
     191           0 :     }
     192           0 :   }
     193           0 :   return 1;
     194           0 : }
     195             : 
     196             : #if FD_HAS_AVX512 && FD_HAS_INT128
     197             : 
     198             : /* bloom_bit is h%bits_len.  magic is floor((2^64-1)/bits_len), which
     199             :    makes q floor(h/bits_len) or one less. */
     200             : 
     201             : static inline ulong
     202             : bloom_bit( ulong bits_len,
     203             :            ulong magic,
     204           0 :            ulong h ) {
     205           0 :   ulong q   = (ulong)(((uint128)h*(uint128)magic)>>64);
     206           0 :   ulong bit = h - q*bits_len;
     207           0 :   return fd_ulong_if( bit>=bits_len, bit-bits_len, bit );
     208           0 : }
     209             : 
     210             : static inline void
     211             : bloom_set( ulong * bits,
     212             :            ulong   bits_len,
     213             :            ulong   magic,
     214           0 :            ulong   h ) {
     215           0 :   ulong bit = bloom_bit( bits_len, magic, h );
     216           0 :   bits[ bit/64UL ] |= 1UL<<(bit%64UL);
     217           0 : }
     218             : 
     219             : static inline int
     220             : bloom_test( ulong const * bits,
     221             :             ulong         bits_len,
     222             :             ulong         magic,
     223           0 :             ulong         h ) {
     224           0 :   ulong bit = bloom_bit( bits_len, magic, h );
     225           0 :   return (int)((bits[ bit/64UL ]>>(bit%64UL)) & 1UL);
     226           0 : }
     227             : 
     228             : /* bloom_transpose8 loads the 8 contiguous 32 byte elements at ele so
     229             :    that wq[k] lane j holds the k-th 8 byte word of element ele8_lane(j).
     230             :    The lane to element map, 0,2,1,3,4,6,5,7, is an involution, so
     231             :    bloom_lane_mask converts a bit set both ways. */
     232             : 
     233             : static inline void
     234             : bloom_transpose8( uchar const * ele,
     235           0 :                   wwv_t         wq[ static 4 ] ) {
     236           0 :   wwv_t r0 = wwv_ldu( ele       ); wwv_t r1 = wwv_ldu( ele+ 64UL );
     237           0 :   wwv_t r2 = wwv_ldu( ele+128UL ); wwv_t r3 = wwv_ldu( ele+192UL );
     238           0 :   wwv_t t0 = _mm512_unpacklo_epi64( r0, r1 ); wwv_t t1 = _mm512_unpackhi_epi64( r0, r1 );
     239           0 :   wwv_t t2 = _mm512_unpacklo_epi64( r2, r3 ); wwv_t t3 = _mm512_unpackhi_epi64( r2, r3 );
     240           0 :   wwv_t lo = wwv( 0UL, 1UL, 4UL, 5UL,  8UL,  9UL, 12UL, 13UL );
     241           0 :   wwv_t hi = wwv( 2UL, 3UL, 6UL, 7UL, 10UL, 11UL, 14UL, 15UL );
     242           0 :   wq[0] = wwv_select( lo, t0, t2 ); wq[1] = wwv_select( lo, t1, t3 );
     243           0 :   wq[2] = wwv_select( hi, t0, t2 ); wq[3] = wwv_select( hi, t1, t3 );
     244           0 : }
     245             : 
     246             : static inline uint
     247           0 : bloom_lane_mask( uint m ) {
     248           0 :   return (m&0x99U) | ((m&0x22U)<<1) | ((m&0x44U)>>1);
     249           0 : }
     250             : 
     251             : /* bloom_fnv8x4 is fnv_hasher4 of the 8 transposed elements in wq: h[c]
     252             :    lane j is the FNV of element ele8_lane(j) under keys[c], one zmm
     253             :    chain per key.  Lanes past cnt repeat key 0. */
     254             : 
     255             : static inline void
     256             : bloom_fnv8x4( wwv_t const * wq,
     257             :               ulong const * keys,
     258             :               ulong         cnt,
     259           0 :               ulong         h[ static 4 ][ 8 ] ) {
     260           0 :   wwv_t prime = wwv_bcast( 1099511628211UL );
     261           0 :   wwv_t h0 = wwv_bcast( keys[ 0 ] );
     262           0 :   wwv_t h1 = wwv_bcast( keys[ fd_ulong_if( cnt>1UL, 1UL, 0UL ) ] );
     263           0 :   wwv_t h2 = wwv_bcast( keys[ fd_ulong_if( cnt>2UL, 2UL, 0UL ) ] );
     264           0 :   wwv_t h3 = wwv_bcast( keys[ fd_ulong_if( cnt>3UL, 3UL, 0UL ) ] );
     265           0 :   for( ulong k=0UL; k<4UL; k++ ) {
     266           0 :     for( ulong b=0UL; b<8UL; b++ ) {
     267           0 :       wwv_t x = wwv_and( wwv_shr( wq[ k ], 8UL*b ), wwv_bcast( 0xffUL ) );
     268           0 :       h0 = wwv_mul( wwv_xor( h0, x ), prime );
     269           0 :       h1 = wwv_mul( wwv_xor( h1, x ), prime );
     270           0 :       h2 = wwv_mul( wwv_xor( h2, x ), prime );
     271           0 :       h3 = wwv_mul( wwv_xor( h3, x ), prime );
     272           0 :     }
     273           0 :   }
     274           0 :   wwv_st( h[0], h0 ); wwv_st( h[1], h1 ); wwv_st( h[2], h2 ); wwv_st( h[3], h3 );
     275           0 : }
     276             : 
     277             : /* bloom_fnv8x4x2 is bloom_fnv8x4 of two transposed 8 element blocks
     278             :    under the same keys, 8 chains interleaved: 4 dependent multiplies
     279             :    per byte do not fill the multiplier's pipeline, 8 nearly do. */
     280             : 
     281             : static inline void
     282             : bloom_fnv8x4x2( wwv_t const * wqa,
     283             :                 wwv_t const * wqb,
     284             :                 ulong const * keys,
     285             :                 ulong         cnt,
     286             :                 ulong         ha[ static 4 ][ 8 ],
     287           0 :                 ulong         hb[ static 4 ][ 8 ] ) {
     288           0 :   wwv_t prime = wwv_bcast( 1099511628211UL );
     289           0 :   wwv_t k0 = wwv_bcast( keys[ 0 ] );
     290           0 :   wwv_t k1 = wwv_bcast( keys[ fd_ulong_if( cnt>1UL, 1UL, 0UL ) ] );
     291           0 :   wwv_t k2 = wwv_bcast( keys[ fd_ulong_if( cnt>2UL, 2UL, 0UL ) ] );
     292           0 :   wwv_t k3 = wwv_bcast( keys[ fd_ulong_if( cnt>3UL, 3UL, 0UL ) ] );
     293           0 :   wwv_t a0 = k0; wwv_t a1 = k1; wwv_t a2 = k2; wwv_t a3 = k3;
     294           0 :   wwv_t b0 = k0; wwv_t b1 = k1; wwv_t b2 = k2; wwv_t b3 = k3;
     295           0 :   for( ulong k=0UL; k<4UL; k++ ) {
     296           0 :     for( ulong b=0UL; b<8UL; b++ ) {
     297           0 :       wwv_t xa = wwv_and( wwv_shr( wqa[ k ], 8UL*b ), wwv_bcast( 0xffUL ) );
     298           0 :       wwv_t xb = wwv_and( wwv_shr( wqb[ k ], 8UL*b ), wwv_bcast( 0xffUL ) );
     299           0 :       a0 = wwv_mul( wwv_xor( a0, xa ), prime ); b0 = wwv_mul( wwv_xor( b0, xb ), prime );
     300           0 :       a1 = wwv_mul( wwv_xor( a1, xa ), prime ); b1 = wwv_mul( wwv_xor( b1, xb ), prime );
     301           0 :       a2 = wwv_mul( wwv_xor( a2, xa ), prime ); b2 = wwv_mul( wwv_xor( b2, xb ), prime );
     302           0 :       a3 = wwv_mul( wwv_xor( a3, xa ), prime ); b3 = wwv_mul( wwv_xor( b3, xb ), prime );
     303           0 :     }
     304           0 :   }
     305           0 :   wwv_st( ha[0], a0 ); wwv_st( ha[1], a1 ); wwv_st( ha[2], a2 ); wwv_st( ha[3], a3 );
     306           0 :   wwv_st( hb[0], b0 ); wwv_st( hb[1], b1 ); wwv_st( hb[2], b2 ); wwv_st( hb[3], b3 );
     307           0 : }
     308             : 
     309             : static inline void
     310             : bloom_set8( ulong *       bits,
     311             :             ulong         bits_len,
     312             :             ulong         magic,
     313             :             ulong         h[ static 4 ][ 8 ],
     314             :             ulong         cnt,
     315           0 :             uint          lane_mask ) {
     316           0 :   for( uint m=lane_mask; m; m&=m-1U ) {
     317           0 :     ulong j = (ulong)fd_uint_find_lsb( m );
     318           0 :     for( ulong c=0UL; c<cnt; c++ ) bloom_set( bits, bits_len, magic, h[ c ][ j ] );
     319           0 :   }
     320           0 : }
     321             : 
     322             : void
     323             : fd_bloom_insert8( fd_bloom_t *  bloom,
     324             :                   uchar const * ele,
     325           0 :                   uint          lanes ) {
     326           0 :   ulong bits_len = bloom->bits_len;
     327           0 :   if( FD_UNLIKELY( !bits_len || !lanes ) ) return;
     328           0 :   ulong magic = ULONG_MAX/bits_len;
     329             : 
     330           0 :   wwv_t wq[4];
     331           0 :   bloom_transpose8( ele, wq );
     332           0 :   uint lane_mask = bloom_lane_mask( lanes );
     333             : 
     334           0 :   for( ulong i=0UL; i<bloom->keys_len; i+=4UL ) {
     335           0 :     ulong cnt = fd_ulong_min( bloom->keys_len-i, 4UL );
     336           0 :     ulong h[4][8] __attribute__((aligned(64)));
     337           0 :     bloom_fnv8x4( wq, bloom->keys+i, cnt, h );
     338           0 :     bloom_set8( bloom->bits, bits_len, magic, h, cnt, lane_mask );
     339           0 :   }
     340           0 : }
     341             : 
     342             : void
     343             : fd_bloom_insert16( fd_bloom_t *  bloom,
     344             :                    uchar const * ele_a,
     345             :                    uint          lanes_a,
     346             :                    uchar const * ele_b,
     347           0 :                    uint          lanes_b ) {
     348           0 :   ulong bits_len = bloom->bits_len;
     349           0 :   if( FD_UNLIKELY( !bits_len ) ) return;
     350           0 :   if( FD_UNLIKELY( !lanes_a ) ) { fd_bloom_insert8( bloom, ele_b, lanes_b ); return; }
     351           0 :   if( FD_UNLIKELY( !lanes_b ) ) { fd_bloom_insert8( bloom, ele_a, lanes_a ); return; }
     352           0 :   ulong magic = ULONG_MAX/bits_len;
     353             : 
     354           0 :   wwv_t wqa[4]; wwv_t wqb[4];
     355           0 :   bloom_transpose8( ele_a, wqa );
     356           0 :   bloom_transpose8( ele_b, wqb );
     357           0 :   uint lane_mask_a = bloom_lane_mask( lanes_a );
     358           0 :   uint lane_mask_b = bloom_lane_mask( lanes_b );
     359             : 
     360           0 :   for( ulong i=0UL; i<bloom->keys_len; i+=4UL ) {
     361           0 :     ulong cnt = fd_ulong_min( bloom->keys_len-i, 4UL );
     362           0 :     ulong ha[4][8] __attribute__((aligned(64)));
     363           0 :     ulong hb[4][8] __attribute__((aligned(64)));
     364           0 :     bloom_fnv8x4x2( wqa, wqb, bloom->keys+i, cnt, ha, hb );
     365           0 :     bloom_set8( bloom->bits, bits_len, magic, ha, cnt, lane_mask_a );
     366           0 :     bloom_set8( bloom->bits, bits_len, magic, hb, cnt, lane_mask_b );
     367           0 :   }
     368           0 : }
     369             : 
     370             : uint
     371             : fd_bloom_contains8( fd_bloom_t const * bloom,
     372           0 :                     uchar const *      ele ) {
     373           0 :   ulong bits_len = bloom->bits_len;
     374           0 :   ulong keys_len = bloom->keys_len;
     375           0 :   if( FD_UNLIKELY( !keys_len || !bits_len ) ) return 0U;
     376           0 :   ulong magic = ULONG_MAX/bits_len;
     377             : 
     378           0 :   wwv_t wq[4];
     379           0 :   bloom_transpose8( ele, wq );
     380             : 
     381             :   /* Lanes whose element has had every key so far set; a lane leaves
     382             :      on its first clear bit, as fd_bloom_contains returns there. */
     383           0 :   uint alive = 0xffU;
     384           0 :   for( ulong i=0UL; i<keys_len && alive; i+=4UL ) {
     385           0 :     ulong cnt = fd_ulong_min( keys_len-i, 4UL );
     386           0 :     ulong h[4][8] __attribute__((aligned(64)));
     387           0 :     bloom_fnv8x4( wq, bloom->keys+i, cnt, h );
     388           0 :     for( uint m=alive; m; m&=m-1U ) {
     389           0 :       ulong j = (ulong)fd_uint_find_lsb( m );
     390           0 :       for( ulong c=0UL; c<cnt; c++ ) {
     391           0 :         if( !bloom_test( bloom->bits, bits_len, magic, h[ c ][ j ] ) ) { alive &= ~(1U<<j); break; }
     392           0 :       }
     393           0 :     }
     394           0 :   }
     395           0 :   return bloom_lane_mask( alive );
     396           0 : }
     397             : 
     398           0 : #define BLOOM_MULTI_CHAIN_CNT (5UL) /* 40 lanes: 12 active set peers with 3 keys each */
     399             : 
     400             : uint
     401             : fd_bloom_contains_multi( fd_bloom_t * const * blooms,
     402             :                          ulong                cnt,
     403             :                          uchar const *        key,
     404           0 :                          ulong                key_sz ) {
     405             :   /* One lane per (bloom, key) pair.  A bloom with no keys or bits
     406             :      contains nothing (fd_bloom_contains) and takes no lane. */
     407           0 :   ulong keys[ 8UL*BLOOM_MULTI_CHAIN_CNT ];
     408           0 :   ulong off [ 32UL ];
     409           0 :   ulong tot = 0UL;
     410           0 :   for( ulong b=0UL; b<cnt; b++ ) {
     411           0 :     fd_bloom_t const * bloom = blooms[ b ];
     412           0 :     off[ b ] = tot;
     413           0 :     if( FD_UNLIKELY( !bloom->keys_len || !bloom->bits_len ) ) continue;
     414           0 :     if( FD_UNLIKELY( tot+bloom->keys_len>8UL*BLOOM_MULTI_CHAIN_CNT ) ) {
     415           0 :       uint hit = 0U;
     416           0 :       for( ulong i=0UL; i<cnt; i++ ) hit |= (uint)fd_bloom_contains( blooms[ i ], key, key_sz )<<i;
     417           0 :       return hit;
     418           0 :     }
     419           0 :     for( ulong k=0UL; k<bloom->keys_len; k++ ) keys[ tot++ ] = bloom->keys[ k ];
     420           0 :   }
     421           0 :   if( FD_UNLIKELY( !tot ) ) return 0U;
     422           0 :   for( ulong i=tot; i<8UL*BLOOM_MULTI_CHAIN_CNT; i++ ) keys[ i ] = 0UL;
     423             : 
     424             :   /* The key bytes go into every lane; the chains are independent so
     425             :      the multiply latency is hidden across them. */
     426           0 :   wwv_t prime = wwv_bcast( 1099511628211UL );
     427           0 :   wwv_t h[ BLOOM_MULTI_CHAIN_CNT ];
     428           0 :   for( ulong c=0UL; c<BLOOM_MULTI_CHAIN_CNT; c++ ) h[ c ] = wwv_ldu( keys+8UL*c );
     429           0 :   for( ulong i=0UL; i<key_sz; i++ ) {
     430           0 :     wwv_t x = wwv_bcast( (ulong)key[ i ] );
     431           0 :     for( ulong c=0UL; c<BLOOM_MULTI_CHAIN_CNT; c++ ) h[ c ] = wwv_mul( wwv_xor( h[ c ], x ), prime );
     432           0 :   }
     433           0 :   ulong hash[ 8UL*BLOOM_MULTI_CHAIN_CNT ] __attribute__((aligned(64)));
     434           0 :   for( ulong c=0UL; c<BLOOM_MULTI_CHAIN_CNT; c++ ) wwv_st( hash+8UL*c, h[ c ] );
     435             : 
     436           0 :   uint hit = 0U;
     437           0 :   for( ulong b=0UL; b<cnt; b++ ) {
     438           0 :     fd_bloom_t const * bloom = blooms[ b ];
     439           0 :     if( FD_UNLIKELY( !bloom->keys_len || !bloom->bits_len ) ) continue;
     440           0 :     ulong k=0UL;
     441           0 :     for( ; k<bloom->keys_len; k++ ) {
     442           0 :       ulong bit = hash[ off[ b ]+k ] % bloom->bits_len;
     443           0 :       if( !(bloom->bits[ bit/64UL ] & (1UL<<(bit%64UL))) ) break;
     444           0 :     }
     445           0 :     hit |= (uint)(k==bloom->keys_len)<<b;
     446           0 :   }
     447           0 :   return hit;
     448           0 : }
     449             : 
     450             : #else
     451             : 
     452             : void
     453             : fd_bloom_insert8( fd_bloom_t *  bloom,
     454             :                   uchar const * ele,
     455             :                   uint          lanes ) {
     456             :   for( ulong i=0UL; i<8UL; i++ ) {
     457             :     if( lanes & (1U<<i) ) fd_bloom_insert( bloom, ele+32UL*i, 32UL );
     458             :   }
     459             : }
     460             : 
     461             : void
     462             : fd_bloom_insert16( fd_bloom_t *  bloom,
     463             :                    uchar const * ele_a,
     464             :                    uint          lanes_a,
     465             :                    uchar const * ele_b,
     466             :                    uint          lanes_b ) {
     467             :   fd_bloom_insert8( bloom, ele_a, lanes_a );
     468             :   fd_bloom_insert8( bloom, ele_b, lanes_b );
     469             : }
     470             : 
     471             : uint
     472             : fd_bloom_contains8( fd_bloom_t const * bloom,
     473             :                     uchar const *      ele ) {
     474             :   uint hit = 0U;
     475             :   for( ulong i=0UL; i<8UL; i++ ) hit |= (uint)fd_bloom_contains( (fd_bloom_t *)bloom, ele+32UL*i, 32UL )<<i;
     476             :   return hit;
     477             : }
     478             : 
     479             : uint
     480             : fd_bloom_contains_multi( fd_bloom_t * const * blooms,
     481             :                          ulong                cnt,
     482             :                          uchar const *        key,
     483             :                          ulong                key_sz ) {
     484             :   uint hit = 0U;
     485             :   for( ulong i=0UL; i<cnt; i++ ) hit |= (uint)fd_bloom_contains( blooms[ i ], key, key_sz )<<i;
     486             :   return hit;
     487             : }
     488             : 
     489             : #endif
     490             : 
     491             : int
     492             : fd_bloom_init_inplace( ulong *      keys,
     493             :                        ulong *      bits,
     494             :                        ulong        keys_len,
     495             :                        ulong        bits_len,
     496             :                        ulong        hash_seed,
     497             :                        fd_rng_t *   rng,
     498             :                        double       false_positive_rate,
     499           0 :                        fd_bloom_t * out_bloom ) {
     500           0 :   if( FD_UNLIKELY( !keys || !bits || !out_bloom ) ) {
     501           0 :     FD_LOG_ERR(( "NULL keys, bits or out_bloom" ));
     502           0 :     return -1;
     503           0 :   }
     504           0 :   out_bloom->keys                = keys;
     505           0 :   for( ulong i=0UL; i<keys_len; i++ ) out_bloom->keys[ i ] = fd_rng_ulong( rng );
     506             : 
     507           0 :   out_bloom->keys_len            = keys_len;
     508           0 :   out_bloom->bits                = bits;
     509           0 :   out_bloom->bits_len            = bits_len;
     510           0 :   out_bloom->hash_seed           = hash_seed;
     511           0 :   out_bloom->rng                 = rng;
     512           0 :   out_bloom->false_positive_rate = false_positive_rate;
     513           0 :   out_bloom->max_bits            = bits_len;
     514             : 
     515           0 :   return 0;
     516           0 : }

Generated by: LCOV version 1.14