From: Willy Tarreau Date: Fri, 11 Aug 2023 18:11:30 +0000 (+0200) Subject: MINOR: tools: improve ptr hash distribution on 64 bits X-Git-Tag: v2.9-dev3~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=58946d44f87e982a83f6ce34f7aefae37425e45c;p=thirdparty%2Fhaproxy.git MINOR: tools: improve ptr hash distribution on 64 bits When testing the pointer hash on 64-bit real pointers (map entries), it appeared that the shift by 33 bits that hoped to compensate for the 3 nul LSB degrades the hash, and the centering is more optimal on 31-(bits+1)/2. This makes sense since the topmost bit of the multiplicator is 31, so for an input of 1 bit and 1 bit of output we would always get zero. With the formula adjusted this way, we can get up to ~15% more unique entries at 10 bits and ~24% more at 11 bits. --- diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index cea68c868d..e0a91f0c4f 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1085,12 +1085,13 @@ static inline uint statistical_prng_range(uint range) * to compute statistic buckets, in that it's fast and reasonably distributed * thanks to mixing the bits via a multiplication by a prime number and using * the middle bits on 64-bit platforms or remixing the topmost with lowest ones - * on 32-bit. It provides ~2588 unique values (~1510 non-colliding) at 100% - * fill ratio for 12 bits, ~1296 (~756 non-colliding) at 100% fill ratio for 11 - * bits, ~648 (~378 non-colliding) at 100% fill ratio for 10 bits, ~163 (95 non - * colliding) at 100% fill ratio for 8 bits, hence 1-1/e and 1/e respectively. - * It must be inlined so that is always a compile-time constant. It - * supports output sizes from 0 to 32 bits. + * on 32-bit. It provides ~2491 unique values (~1354 non-colliding) for 2^12 + * valid pointers at 12 bits, ~1454 (~941 non-colliding) for 2^11 valid ptrs + * at 11 bits, ~707 (~434 non-colliding) for 2^10 valid ptrs at 10 bits, ~347 + * (212 non colliding) for 2^9 valid ptrs at 9 bits, and 165/99 for 2^8 ptrs + * at 8 bits, hence 1-1/e and 1/e respectively. It must be inlined so that + * is always a compile-time constant. It supports output sizes from 0 + * to 32 bits. */ static forceinline uint ptr_hash(const void *p, const int bits) { @@ -1103,7 +1104,7 @@ static forceinline uint ptr_hash(const void *p, const int bits) if (sizeof(long) == 4) x ^= x >> 32; else - x >>= 33 - bits / 2; + x >>= 31 - (bits + 1) / 2; return x & (~0U >> (-bits & 31)); }