From 4a3907617f95f5d31e41978b7adf3ca42330ff5e Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 7 Sep 2022 10:56:03 +0200 Subject: [PATCH] MINOR: tools: add generic pointer hashing functions There are a few places where it's convenient to hash a pointer to compute a statistics bucket. Here we're basically reusing the hash that was used by memory profiling with a minor update that the multiplier was corrected to be prime and stand by its promise to have equal numbers of 1 and 0, and that 32-bit platforms won't lose range anymore. A two-pointer variant was also added. --- include/haproxy/tools.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index abbca3f4d..0e719832c 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1070,6 +1070,47 @@ static inline uint statistical_prng_range(uint range) return mul32hi(statistical_prng(), range ? range - 1 : 0); } +/* returns a hash on bits of pointer

that is suitable for being used + * 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. + */ +static forceinline uint ptr_hash(const void *p, const int bits) +{ + unsigned long long x = (unsigned long)p; + + x *= 0xc1da9653U; + if (sizeof(long) == 4) + x ^= x >> 32; + else + x >>= 33 - bits / 2; + return x & (~0U >> (-bits & 31)); +} + +/* Same as above but works on two pointers. It will return the same values + * if the second pointer is NULL. + */ +static forceinline uint ptr2_hash(const void *p1, const void *p2, const int bits) +{ + unsigned long long x = (unsigned long)p1; + unsigned long long y = (unsigned long)p2; + + x *= 0xc1da9653U; + y *= 0x96531cadU; + x ^= y; + if (sizeof(long) == 4) + x ^= x >> 32; + else + x >>= 33 - bits / 2; + return x & (~0U >> (-bits & 31)); +} + + /* Update array with the character transition to . If * is zero, it's assumed that is the first character. If is zero * its assumed to mark the end. Both may be zero. is a 1024-entries array