From 6d9286a2021196370ae61ade3552f0382dbe9cc7 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Tue, 7 Dec 2021 08:36:08 -0600 Subject: [PATCH] Add some more changes to hashing to improve pointer hashing. --- src/core/value.c | 12 +++++++----- tools/hashbench/ints1.janet | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 tools/hashbench/ints1.janet diff --git a/src/core/value.c b/src/core/value.c index e1a82f32..a29c48d0 100644 --- a/src/core/value.c +++ b/src/core/value.c @@ -325,7 +325,7 @@ int32_t janet_hash(Janet x) { uint32_t lo = (uint32_t)(as.u & 0xFFFFFFFF); uint32_t hi = (uint32_t)(as.u >> 32); uint32_t hilo = (hi ^ lo) * 2654435769u; - hash = (int32_t)((hilo << 16) | ((hilo >> 16) & 0xFFFF)); + hash = (int32_t)((hilo << 16) | (hilo >> 16)); break; } case JANET_ABSTRACT: { @@ -339,15 +339,17 @@ int32_t janet_hash(Janet x) { /* fallthrough */ default: if (sizeof(double) == sizeof(void *)) { - /* Assuming 8 byte pointer */ + /* Assuming 8 byte pointer (8 byte aligned) */ uint64_t i = janet_u64(x); uint32_t lo = (uint32_t)(i & 0xFFFFFFFF); uint32_t hi = (uint32_t)(i >> 32); - hash = (int32_t)(hi ^ (lo >> 3)); + uint32_t hilo = (hi ^ lo) * 2654435769u; + hash = (int32_t)((hilo << 16) | (hilo >> 16)); } else { /* Assuming 4 byte pointer (or smaller) */ - hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0); - hash >>= 2; + ptrdiff_t diff = ((char *)janet_unwrap_pointer(x) - (char *)0); + uint32_t hilo = (uint32_t) diff * 2654435769u; + hash = (int32_t)((hilo << 16) | (hilo >> 16)); } break; } diff --git a/tools/hashbench/ints1.janet b/tools/hashbench/ints1.janet new file mode 100644 index 00000000..37219e13 --- /dev/null +++ b/tools/hashbench/ints1.janet @@ -0,0 +1,24 @@ +(def f @{}) +(var collisions 0) +(loop [x :range [0 300] y :range [0 300]] + (def key (hash (+ (* x 1000) y))) + (if (in f key) + (++ collisions)) + (put f key true)) +(print "ints 1 collisions: " collisions) + +(def f @{}) +(var collisions 0) +(loop [x :range [100000 101000] y :range [100000 101000]] + (def key (hash [x y])) + (if (in f key) (++ collisions)) + (put f key true)) +(print "int pair 1 collisions: " collisions) + +(def f @{}) +(var collisions 0) +(loop [x :range [10000 11000] y :range [10000 11000]] + (def key (hash [x y])) + (if (in f key) (++ collisions)) + (put f key true)) +(print "int pair 2 collisions: " collisions)