diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs index 58add0f..14591a8 100644 --- a/benchmarks/Benchmarks.hs +++ b/benchmarks/Benchmarks.hs @@ -7,6 +7,7 @@ import Control.Monad.ST import Criterion.Main import Data.Hashable import Data.Hashable.SipHash +import Data.Int import Foreign.ForeignPtr import GHC.Exts import GHC.ST (ST(..)) @@ -61,6 +62,10 @@ main = do sse41SipHash (PS fp off len) = inlinePerformIO . withForeignPtr fp $ \ptr -> 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 fp8 $ \ p8 -> @@ -98,6 +103,11 @@ main = do , bench "512" $ whnf hash bs512 , 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" [ bench "5" $ whnf sipHash bs5 @@ -118,13 +128,19 @@ main = do , bench "2^20" $ whnf cSipHash bs1Mb ] , bgroup "cSipHash24" - [ bench "5" $ whnf cSipHash24 bs5 - , bench "8" $ whnf cSipHash24 bs8 - , bench "11" $ whnf cSipHash24 bs11 - , bench "40" $ whnf cSipHash24 bs40 - , bench "128" $ whnf cSipHash24 bs128 - , bench "512" $ whnf cSipHash24 bs512 - , bench "2^20" $ whnf cSipHash24 bs1Mb + [ bgroup "ByteString" + [ bench "5" $ whnf cSipHash24 bs5 + , bench "8" $ whnf cSipHash24 bs8 + , bench "11" $ whnf cSipHash24 bs11 + , bench "40" $ whnf cSipHash24 bs40 + , bench "128" $ whnf cSipHash24 bs128 + , 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" [ bench "5" $ whnf sse41SipHash bs5 @@ -144,6 +160,12 @@ main = do , bench "512" $ whnf hsSipHash bs512 , 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# } @@ -158,5 +180,22 @@ foreign import ccall unsafe "hashable_siphash" c_siphash :: CInt -> CInt -> Word64 -> Word64 -> Ptr Word8 -> CSize -> Word64 foreign import ccall unsafe "hashable_siphash24" c_siphash24 :: 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 :: 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 diff --git a/benchmarks/cbits/inthash.c b/benchmarks/cbits/inthash.c new file mode 100644 index 0000000..a796f31 --- /dev/null +++ b/benchmarks/cbits/inthash.c @@ -0,0 +1,46 @@ +#include + +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; +} diff --git a/benchmarks/hashable-benchmarks.cabal b/benchmarks/hashable-benchmarks.cabal index 6ac2b79..2b15fce 100644 --- a/benchmarks/hashable-benchmarks.cabal +++ b/benchmarks/hashable-benchmarks.cabal @@ -11,6 +11,7 @@ executable hashable-benchmarks ../cbits/hashByteString.c ../cbits/getRandomBytes.c ../cbits/siphash.c + cbits/inthash.c cbits/siphash-sse41.c hs-source-dirs: .. . main-is: Benchmarks.hs diff --git a/cbits/siphash.c b/cbits/siphash.c index b275496..308ebb3 100644 --- a/cbits/siphash.c +++ b/cbits/siphash.c @@ -4,6 +4,8 @@ #include typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; typedef uint8_t u8; #define ROTL(x,b) (u64)(((x) << (b)) | ((x) >> (64 - (b)))) @@ -92,3 +94,23 @@ u64 hashable_siphash24_offset(u64 k0, u64 k1, { 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)); +}