On Mon, 2023-12-18 at 13:39 +0700, John Naylor wrote: > For now just two: > v10-0002 is Jeff's change to the search path cache, but with the > chunked interface that I found to be faster.
Did you consider specializing for the case of an aligned pointer? If it's a string (c string or byte string) it's almost always going to be aligned, right? I hacked up a patch (attached). I lost track of which benchmark we're using to test the performance, but when I test in a loop it seems substantially faster. It reads past the NUL byte, but only to the next alignment boundary, which I think is OK (though I think I'd need to fix the patch for when maxalign < 8). Regards, Jeff Davis
From 055d5cc24404584fd98109fabdcf83348e5c49b4 Mon Sep 17 00:00:00 2001 From: Jeff Davis <j...@j-davis.com> Date: Mon, 18 Dec 2023 16:44:27 -0800 Subject: [PATCH v10jd] Optimize hash function further. --- src/backend/catalog/namespace.c | 46 +++++++++++++++++++++++++--- src/include/common/hashfn_unstable.h | 9 ++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index c23f46aca3..368a7fabec 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -245,15 +245,44 @@ static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames, * offers a more convenient API. */ +/* From: https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord */ +#define haszero64(v) \ + (((v) - 0x0101010101010101UL) & ~(v) & 0x8080808080808080UL) + static inline uint32 -spcachekey_hash(SearchPathCacheKey key) +cstring_hash_aligned(const char *str, uint64 seed) +{ + const char *const start = str; + const char *buf = start; + int chunk_len = 0; + fasthash_state hs; + + fasthash_init(&hs, FH_UNKNOWN_LENGTH, seed); + + Assert(PointerIsAligned(start, uint64)); + while (!haszero64(*(uint64 *)buf)) + { + fasthash_accum64(&hs, buf); + buf += sizeof(uint64); + } + + while (buf[chunk_len] != '\0') + chunk_len++; + fasthash_accum(&hs, buf, chunk_len); + buf += chunk_len; + + return fasthash_final32(&hs, buf - start); +} + +static inline uint32 +cstring_hash_unaligned(const char *str, uint64 seed) { - const char *const start = key.searchPath; - const char *buf = key.searchPath; + const char *const start = str; + const char *buf = str; fasthash_state hs; /* WIP: maybe roleid should be mixed in normally */ - fasthash_init(&hs, FH_UNKNOWN_LENGTH, key.roleid); + fasthash_init(&hs, FH_UNKNOWN_LENGTH, seed); while (*buf) { int chunk_len = 0; @@ -269,6 +298,15 @@ spcachekey_hash(SearchPathCacheKey key) return fasthash_final32(&hs, buf - start); } +static inline uint32 +spcachekey_hash(SearchPathCacheKey key) +{ + if (PointerIsAligned(key.searchPath, uint64)) + return cstring_hash_aligned(key.searchPath, key.roleid); + else + return cstring_hash_unaligned(key.searchPath, key.roleid); +} + static inline bool spcachekey_equal(SearchPathCacheKey a, SearchPathCacheKey b) { diff --git a/src/include/common/hashfn_unstable.h b/src/include/common/hashfn_unstable.h index bf1dbee28d..553fab0415 100644 --- a/src/include/common/hashfn_unstable.h +++ b/src/include/common/hashfn_unstable.h @@ -105,6 +105,15 @@ fasthash_combine(fasthash_state *hs) hs->accum = 0; } +/* Accumulate 8 bytes from aligned pointer and combine it into the hash */ +static inline void +fasthash_accum64(fasthash_state *hs, const char *ptr) +{ + Assert(PointerIsAligned(ptr, uint64)); + hs->accum = *(uint64 *)ptr; + fasthash_combine(hs); +} + /* Accumulate up to 8 bytes of input and combine it into the hash */ static inline void fasthash_accum(fasthash_state *hs, const char *k, int len) -- 2.34.1