Skip to content

Commit

Permalink
Try different methods of hashing integers.
Browse files Browse the repository at this point in the history
Preliminary results on my laptop:

Status quo (id):     9 ns
Wang 32-bit (best): 12
Jenkins 32-bit:     13
Wang 64-bit:        14
SipHash 32-bit:     33
SipHash 64-bit:     36
  • Loading branch information
bos committed Oct 13, 2012
1 parent 93d1bb4 commit 6881817
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 7 deletions.
53 changes: 46 additions & 7 deletions benchmarks/Benchmarks.hs
Expand Up @@ -7,6 +7,7 @@ import Control.Monad.ST
import Criterion.Main import Criterion.Main
import Data.Hashable import Data.Hashable
import Data.Hashable.SipHash import Data.Hashable.SipHash
import Data.Int
import Foreign.ForeignPtr import Foreign.ForeignPtr
import GHC.Exts import GHC.Exts
import GHC.ST (ST(..)) import GHC.ST (ST(..))
Expand Down Expand Up @@ -61,6 +62,10 @@ main = do
sse41SipHash (PS fp off len) = sse41SipHash (PS fp off len) =
inlinePerformIO . withForeignPtr fp $ \ptr -> inlinePerformIO . withForeignPtr fp $ \ptr ->
return $! sse41_siphash k0 k1 (ptr `plusPtr` off) (fromIntegral len) return $! sse41_siphash k0 k1 (ptr `plusPtr` off) (fromIntegral len)
cSipHash8 v = c_siphash24_u8 k0 k1 (fromIntegral v)
cSipHash16 v = c_siphash24_u16 k0 k1 (fromIntegral v)
cSipHash32 v = c_siphash24_u32 k0 k1 (fromIntegral v)
cSipHash64 v = c_siphash24_u64 k0 k1 (fromIntegral v)


withForeignPtr fp5 $ \ p5 -> withForeignPtr fp5 $ \ p5 ->
withForeignPtr fp8 $ \ p8 -> withForeignPtr fp8 $ \ p8 ->
Expand Down Expand Up @@ -98,6 +103,11 @@ main = do
, bench "512" $ whnf hash bs512 , bench "512" $ whnf hash bs512
, bench "2^20" $ whnf hash bs1Mb , bench "2^20" $ whnf hash bs1Mb
] ]
, bench "Int8" $ whnf hash (0xef :: Int8)
, bench "Int16" $ whnf hash (0x7eef :: Int16)
, bench "Int32" $ whnf hash (0x7eadbeef :: Int32)
, bench "Int" $ whnf hash (0x7eadbeefdeadbeef :: Int)
, bench "Int64" $ whnf hash (0x7eadbeefdeadbeef :: Int64)
] ]
, bgroup "sipHash" , bgroup "sipHash"
[ bench "5" $ whnf sipHash bs5 [ bench "5" $ whnf sipHash bs5
Expand All @@ -118,13 +128,19 @@ main = do
, bench "2^20" $ whnf cSipHash bs1Mb , bench "2^20" $ whnf cSipHash bs1Mb
] ]
, bgroup "cSipHash24" , bgroup "cSipHash24"
[ bench "5" $ whnf cSipHash24 bs5 [ bgroup "ByteString"
, bench "8" $ whnf cSipHash24 bs8 [ bench "5" $ whnf cSipHash24 bs5
, bench "11" $ whnf cSipHash24 bs11 , bench "8" $ whnf cSipHash24 bs8
, bench "40" $ whnf cSipHash24 bs40 , bench "11" $ whnf cSipHash24 bs11
, bench "128" $ whnf cSipHash24 bs128 , bench "40" $ whnf cSipHash24 bs40
, bench "512" $ whnf cSipHash24 bs512 , bench "128" $ whnf cSipHash24 bs128
, bench "2^20" $ whnf cSipHash24 bs1Mb , bench "512" $ whnf cSipHash24 bs512
, bench "2^20" $ whnf cSipHash24 bs1Mb
]
, bench "Int8" $ whnf cSipHash8 (0x5a :: Int8)
, bench "Int16" $ whnf cSipHash16 (0x5a5a :: Int16)
, bench "Int32" $ whnf cSipHash32 (0x5a5a5a5a :: Int32)
, bench "Int64" $ whnf cSipHash64 (0x5a5a5a5a5a5a5a5a :: Int64)
] ]
, bgroup "sse41SipHash" , bgroup "sse41SipHash"
[ bench "5" $ whnf sse41SipHash bs5 [ bench "5" $ whnf sse41SipHash bs5
Expand All @@ -144,6 +160,12 @@ main = do
, bench "512" $ whnf hsSipHash bs512 , bench "512" $ whnf hsSipHash bs512
, bench "2^20" $ whnf hsSipHash bs1Mb , bench "2^20" $ whnf hsSipHash bs1Mb
] ]
, bgroup "Int"
[ bench "wang32" $ whnf hash_wang_32 0xdeadbeef
, bench "wang64" $ whnf hash_wang_64 0xdeadbeefdeadbeef
, bench "jenkins32a" $ whnf hash_jenkins_32a 0xdeadbeef
, bench "jenkins32b" $ whnf hash_jenkins_32b 0xdeadbeef
]
] ]


data ByteArray = BA { unBA :: !ByteArray# } data ByteArray = BA { unBA :: !ByteArray# }
Expand All @@ -158,5 +180,22 @@ foreign import ccall unsafe "hashable_siphash" c_siphash
:: CInt -> CInt -> Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 :: CInt -> CInt -> Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64
foreign import ccall unsafe "hashable_siphash24" c_siphash24 foreign import ccall unsafe "hashable_siphash24" c_siphash24
:: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 :: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64
foreign import ccall unsafe "hashable_siphash24_u64" c_siphash24_u64
:: Word64 -> Word64 -> Word64 -> Word64
foreign import ccall unsafe "hashable_siphash24_u32" c_siphash24_u32
:: Word64 -> Word64 -> Word32 -> Word64
foreign import ccall unsafe "hashable_siphash24_u16" c_siphash24_u16
:: Word64 -> Word64 -> Word16 -> Word64
foreign import ccall unsafe "hashable_siphash24_u8" c_siphash24_u8
:: Word64 -> Word64 -> Word8 -> Word64
foreign import ccall unsafe "siphash_sse41" sse41_siphash foreign import ccall unsafe "siphash_sse41" sse41_siphash
:: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 :: Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64

foreign import ccall unsafe "hash_wang_32" hash_wang_32
:: Word32 -> Word32
foreign import ccall unsafe "hash_wang_64" hash_wang_64
:: Word64 -> Word64
foreign import ccall unsafe "hash_jenkins_32a" hash_jenkins_32a
:: Word32 -> Word32
foreign import ccall unsafe "hash_jenkins_32b" hash_jenkins_32b
:: Word32 -> Word32
46 changes: 46 additions & 0 deletions benchmarks/cbits/inthash.c
@@ -0,0 +1,46 @@
#include <stdint.h>

uint32_t hash_wang_32(uint32_t a)
{
a = (a ^ 61) ^ (a >> 16);
a = a + (a << 3);
a = a ^ (a >> 4);
a = a * 0x27d4eb2d;
a = a ^ (a >> 15);
return a;
}

uint64_t hash_wang_64(uint64_t key)
{
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
key = key ^ ((key >> 24) | (key << 40));
key = (key + (key << 3)) + (key << 8); // key * 265
key = key ^ ((key >> 14) | (key << 50));
key = (key + (key << 2)) + (key << 4); // key * 21
key = key ^ ((key >> 28) | (key << 36));
key = key + (key << 31);
return key;
}

uint32_t hash_jenkins_32a(uint32_t a)
{
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);
return a;
}

uint32_t hash_jenkins_32b(uint32_t a)
{
a -= (a<<6);
a ^= (a>>17);
a -= (a<<9);
a ^= (a<<4);
a -= (a<<3);
a ^= (a<<10);
a ^= (a>>15);
return a;
}
1 change: 1 addition & 0 deletions benchmarks/hashable-benchmarks.cabal
Expand Up @@ -11,6 +11,7 @@ executable hashable-benchmarks
../cbits/hashByteString.c ../cbits/hashByteString.c
../cbits/getRandomBytes.c ../cbits/getRandomBytes.c
../cbits/siphash.c ../cbits/siphash.c
cbits/inthash.c
cbits/siphash-sse41.c cbits/siphash-sse41.c
hs-source-dirs: .. . hs-source-dirs: .. .
main-is: Benchmarks.hs main-is: Benchmarks.hs
Expand Down
22 changes: 22 additions & 0 deletions cbits/siphash.c
Expand Up @@ -4,6 +4,8 @@
#include <stdint.h> #include <stdint.h>


typedef uint64_t u64; typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8; typedef uint8_t u8;


#define ROTL(x,b) (u64)(((x) << (b)) | ((x) >> (64 - (b)))) #define ROTL(x,b) (u64)(((x) << (b)) | ((x) >> (64 - (b))))
Expand Down Expand Up @@ -92,3 +94,23 @@ u64 hashable_siphash24_offset(u64 k0, u64 k1,
{ {
return _siphash(2, 4, k0, k1, str + off, len); return _siphash(2, 4, k0, k1, str + off, len);
} }

u64 hashable_siphash24_u8(u64 k0, u64 k1, u8 key)
{
return _siphash(2, 4, k0, k1, (const u8 *) &key, sizeof(u8));
}

u16 hashable_siphash24_u16(u64 k0, u64 k1, u16 key)
{
return _siphash(2, 4, k0, k1, (const u8 *) &key, sizeof(u16));
}

u16 hashable_siphash24_u32(u64 k0, u64 k1, u32 key)
{
return _siphash(2, 4, k0, k1, (const u8 *) &key, sizeof(u32));
}

u64 hashable_siphash24_u64(u64 k0, u64 k1, u64 key)
{
return _siphash(2, 4, k0, k1, (const u8 *) &key, sizeof(u64));
}

0 comments on commit 6881817

Please sign in to comment.