hashabler-1.3.0: benchmarks/Main.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric,StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (
main
) where
import Criterion.Main
import Data.Word
import Data.Int
import Data.Ratio
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Char8 as B8
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Lazy as TL
import qualified Data.Primitive as P
import Control.DeepSeq
import Data.Hashabler
import qualified Data.Hashable as Their
instance NFData FNV32 where rnf = rnf . fnv32
instance NFData (Hash32 a) where rnf = rnf . hashWord32
instance NFData (Hash64 a) where rnf = rnf . hashWord64
-- BASELINE for list instances:
-- a fused foldl' equivalent -- NOTE ~ 2x faster than Unfolded on 7.10
hashLeftNoList :: FNV32 -> Word8 -> Word32 -- NOTE: tested w/ this monomorphic sig
{-# INLINE hashLeftNoList #-}
hashLeftNoList = go
where go !h 0 = fnv32 h
go !h !b = go (h `hash` b) (b-1)
-- raise hash benchmarks above criterion noise floor from function call and nf.
hash32Times :: Hashable a=> Int -> a -> Word32
{-# INLINE hash32Times #-}
hash32Times iters =
\a-> let go !h !0 = h
go !h !n = go (h `hash` a) (n-1)
in fnv32 $ go fnvOffsetBasis32 iters
main :: IO ()
main = do
# ifdef ASSERTIONS_ON
error "Sorry, please reconfigure without -finstrumented so that we turn off assertions in library code."
# endif
let bs50 = B.pack $ replicate 48 1
bs1000 = B.pack $ replicate 1000 1
t50 = T.pack $ replicate 25 'a' -- TODO verify this is 50 bytes
t1000 = T.pack $ replicate 500 'a' -- TODO verify this is 1000 bytes
--
bs1 = B.pack $ replicate 1 1
bs2 = B.pack $ replicate 2 1
bs3 = B.pack $ replicate 3 1
bs4 = B.pack $ replicate 4 1
bs5 = B.pack $ replicate 5 1
bs6 = B.pack $ replicate 6 1
bs7 = B.pack $ replicate 7 1
bs8 = B.pack $ replicate 8 1
bs9 = B.pack $ replicate 9 1
bs11 = B.pack $ replicate 11 1
bs16 = B.pack $ replicate 16 1
bs32 = B.pack $ replicate 32 1
bs64 = B.pack $ replicate 64 1
bs128 = B.pack $ replicate 128 1
bs256 = B.pack $ replicate 256 1
bs512 = B.pack $ replicate 512 1
bs1024 = B.pack $ replicate 1024 1
ba50 <- P.newByteArray 50 >>= \ba'-> P.fillByteArray ba' 0 50 1 >> P.unsafeFreezeByteArray ba'
ba50Aligned <- P.newAlignedPinnedByteArray 50 (P.alignment (undefined::Word64)) >>= \ba'-> P.fillByteArray ba' 0 50 1 >> P.unsafeFreezeByteArray ba'
ba50AlignedBadly <- P.newAlignedPinnedByteArray 50 (7) >>= \ba'-> P.fillByteArray ba' 0 50 1 >> P.unsafeFreezeByteArray ba'
ba1000 <- P.newByteArray 1000 >>= \ba'-> P.fillByteArray ba' 0 1000 1 >> P.unsafeFreezeByteArray ba'
-- lazy Text and ByteString:
let bs50LazyTrivial = BL.fromStrict bs50
bs1000Lazy_by20Chunks = BL.fromChunks $ replicate 20 bs50
let t50LazyTrivial = TL.fromStrict t50
t1000Lazy_by20Chunks = TL.fromChunks $ replicate 20 t50
let {-# INLINE byt #-}
byt = 0xFF :: Word8
-- TODO new set of list benchmarks:
-- - different ways of constructing as "good producers" (and not)
-- - different element types (e.g. Enum of Int vs Word32)
-- - different syntactic variations, w/ eta expansion etc.
let listBgroup nm sz = bgroup nm [
-- ideal code, for baseline:
bench "hashLeftNoList" $ nf (hashLeftNoList fnvOffsetBasis32) sz
-- ...and this only a few % faster:
--, bench "hashLeftUnfoldedNoList" $ nf (hashLeftUnfoldedNoList fnvOffsetBasis32) sz
-- Slow:
-- , bench "hashFoldr" $ nf (hashFoldr fnvOffsetBasis32) [1..250]
-- , bench "hashFoldr trying to fuse" $ nf (\i-> hashFoldr fnvOffsetBasis32 (take (fromIntegral sz) $ iterate (+1) i)) 1
-- Slow:
, bench "hashFoldl'" $ nf (hashFoldl' fnvOffsetBasis32) [1..sz]
-- !!! As fast as hashLeftNoList -- TODO is there really a rule firing here?
, bench "hashFoldl' trying to fuse" $ nf (\i-> hashFoldl' fnvOffsetBasis32 (take (fromIntegral sz) $ iterate (+1) i)) (1::Word8)
-- adding extra multiply adds ~ 65% overhead!:
--, bench "hashFoldl'Extra trying to fuse" $ nf (\i-> hashFoldl'Extra fnvOffsetBasis32 (take (fromIntegral sz) $ iterate (+1) i)) 1
-- Faster than un-fused (I think that's what's happening) fold-based code:
, bench "hashLeftUnfolded" $ nf (hashLeftUnfolded fnvOffsetBasis32) [1..sz]
--, bench "hashLeftUnfolded trying to fuse" $ nf (\i-> hashLeftUnfolded fnvOffsetBasis32 (take (fromIntegral sz) $ iterate (+1) i)) 1
]
allWordsText <- T.readFile "/usr/share/dict/words"
let allWordsListText = T.lines allWordsText
defaultMain [
bgroup "compare" [
bench "long Text, hashable" $ nf Their.hash allWordsText
, bench "[Text], hashable" $ nf Their.hash allWordsListText
, bench "long Text, hashabler" $ nf (hashWord32 . hashFNV32) allWordsText
, bench "[Text], hashabler" $ nf (hashWord32 . hashFNV32) allWordsListText
-- TODO ByteString
],
bgroup "compare with hashable" [
hashableBenchmarkTheir "hashable"
, hashableBenchmarkFNV64
, hashableBenchmarkSiphash64
],
bgroup "dev" [
-- We can more or less subtract this from benchmarks producing a Word32 hash:
bench "baseline Word32" $ nf (\x-> x) (777::Word32)
, bgroup "hashFNV32 on small primitive values x100" [
-- platform-dependent:
bench "Int" $ nf (hash32Times 100) (9999::Int)
, bench "Word" $ nf (hash32Times 100) (9999::Word)
, bench "Int8" $ nf (hash32Times 100) (maxBound :: Int8)
, bench "Word8" $ nf (hash32Times 100) (maxBound :: Word8)
, bench "Int16" $ nf (hash32Times 100) (maxBound :: Int16)
, bench "Word16" $ nf (hash32Times 100) (maxBound :: Word16)
, bench "Int32" $ nf (hash32Times 100) (maxBound :: Int32)
, bench "Word32" $ nf (hash32Times 100) (maxBound :: Word32)
, bench "Int64, in 32-bit range" $ nf (hash32Times 100) (maxBound :: Int64)
, bench "Int64, out of 32-bit range" $ nf (hash32Times 100) ((fromIntegral (maxBound :: Int32) *2) :: Int64)
, bench "Word64" $ nf (hash32Times 100) (maxBound :: Word64)
, bench "Char, small" $ nf (hash32Times 100) 'a'
, bench "Char, big" $ nf (hash32Times 100) '\65537'
, bench "Float" $ nf (hash32Times 100) (1.11111 :: Float)
, bench "Double" $ nf (hash32Times 100) (1.111111111111 :: Double)
, bench "Integer, in Int range" $ nf (hash32Times 100) (fromIntegral (maxBound :: Int) :: Integer)
, bench "Integer, just out of Int range" $ nf (hash32Times 100) ((fromIntegral (maxBound :: Int) * 2) :: Integer)
]
, bgroup "Sum types (of Word8, where relevant) x100" [
bench "Bool (True)" $ nf (hash32Times 100) True
, bench "Bool (False)" $ nf (hash32Times 100) False
, bench "Ordering (LT)" $ nf (hash32Times 100) LT
, bench "Ordering (EQ)" $ nf (hash32Times 100) EQ
, bench "Ordering (GT)" $ nf (hash32Times 100) GT
, bench "Maybe (Nothing)" $ nf (hash32Times 100) (Nothing :: Maybe Word8)
, bench "Maybe (Just)" $ nf (hash32Times 100) (Just byt)
, bench "Either (Left)" $ nf (hash32Times 100) (Left byt :: Either Word8 Word8)
, bench "Either (Right)" $ nf (hash32Times 100) (Right byt :: Either Word8 Word8)
]
, bgroup "Product types of Word8 x100" [
bench "Ratio" $ nf (hash32Times 100) (0xFE % byt)
, bench "(,)" $ nf (hash32Times 100) (byt,byt)
, bench "(,,)" $ nf (hash32Times 100) (byt,byt,byt)
, bench "(,,,)" $ nf (hash32Times 100) (byt,byt,byt,byt)
, bench "(,,,,)" $ nf (hash32Times 100) (byt,byt,byt,byt,byt)
, bench "(,,,,,)" $ nf (hash32Times 100) (byt,byt,byt,byt,byt,byt)
, bench "(,,,,,,)" $ nf (hash32Times 100) (byt,byt,byt,byt,byt,byt,byt)
, bench "(,,,,,,,)" $ nf (hash32Times 100) (byt,byt,byt,byt,byt,byt,byt,byt)
]
, bgroup "on array types, hashFNV64" [
bench "strict ByteString x50" $ nf hashFNV64 bs50
-- ought to be same as above:
, bench "trivial lazy ByteString x50" $ nf hashFNV64 bs50LazyTrivial
, bench "Text x50" $ nf hashFNV64 t50
-- ought to be same as above:
, bench "trivial lazy Text x50" $ nf hashFNV64 t50LazyTrivial
, bench "ByteArray x50" $ nf hashFNV64 ba50
, bench "ByteArray x50 (pinned, aligned)" $ nf hashFNV64 ba50Aligned -- (maybe non-aligned creation is aligned to word size)
, bench "ByteArray x50 (pinned, incorrectly-aligned)" $ nf hashFNV64 ba50AlignedBadly -- (no difference here either)
, bench "ByteArray x1000" $ nf hashFNV64 ba1000
, bench "strict ByteString x1000" $ nf hashFNV64 bs1000
, bench "lazy ByteString x1000, in 20 chunks" $ nf hashFNV64 bs1000Lazy_by20Chunks
, bench "Text x1000" $ nf hashFNV64 t1000
, bench "lazy Text x1000, in 20 chunks" $ nf hashFNV64 t1000Lazy_by20Chunks
-- TODO Integer of comparable size to above
-- TODO BigNat on GHC 7.10
-- TODO Natural on GHC 7.10
]
, bgroup "on ByteStrings of various sizes, siphash64" [
-- try to fool branch prediction in hashByteString and
let ls = [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
in bench "(baseline for fooling branch prediction)" $ nf (map (Hash64 :: Word64 -> Hash64 B.ByteString)) ls
, bench "100 (fooling branch prediction)" $ nf
(map (hashWord64 . siphash64 (SipKey 1 2)))
[ bs1, bs9, bs8, bs32, bs11, bs9, bs3, bs16, bs11 ]
, bench "96 (#1 more predictable branches)" $ nf
(map (hashWord64 . siphash64 (SipKey 1 2)))
[ bs16, bs16, bs16, bs16, bs16, bs16 ]
, bench "96 (#2 more predictable branches)" $ nf
(map (hashWord64 . siphash64 (SipKey 1 2)))
[ bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8 ]
, bench "1" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs1
, bench "2" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs2
, bench "3" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs3
, bench "4" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs4
, bench "5" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs5
, bench "6" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs6
, bench "7" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs7
, bench "8" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs8
, bench "16" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs16
, bench "32" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs32
, bench "64" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs64
, bench "128" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs128
, bench "256" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs256
, bench "512" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs512
, bench "1024" $ nf (hashWord64 . siphash64 (SipKey 1 2)) bs1024
]
, bgroup "on ByteStrings of various sizes, hashable" [
-- try to fool branch prediction in hashByteString and
let ls = [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
in bench "(baseline for fooling branch prediction)" $ nf (map (Hash64 :: Word64 -> Hash64 B.ByteString)) ls
, bench "100 (fooling branch prediction)" $ nf
(map Their.hash)
[ bs1, bs9, bs8, bs32, bs11, bs9, bs3, bs16, bs11 ]
, bench "96 (#1 more predictable branches)" $ nf
(map Their.hash)
[ bs16, bs16, bs16, bs16, bs16, bs16 ]
, bench "96 (#2 more predictable branches)" $ nf
(map Their.hash)
[ bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8, bs8 ]
, bench "1" $ nf Their.hash bs1
, bench "2" $ nf Their.hash bs2
, bench "3" $ nf Their.hash bs3
, bench "4" $ nf Their.hash bs4
, bench "5" $ nf Their.hash bs5
, bench "6" $ nf Their.hash bs6
, bench "7" $ nf Their.hash bs7
, bench "8" $ nf Their.hash bs8
, bench "16" $ nf Their.hash bs16
, bench "32" $ nf Their.hash bs32
, bench "64" $ nf Their.hash bs64
, bench "128" $ nf Their.hash bs128
, bench "256" $ nf Their.hash bs256
, bench "512" $ nf Their.hash bs512
, bench "1024" $ nf Their.hash bs1024
]
, bgroup "on array types, siphash64" [
bench "strict ByteString x50" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) bs50
-- ought to be same as above:
, bench "trivial lazy ByteString x50" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) bs50LazyTrivial
, bench "Text x50" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) t50
-- ought to be same as above:
, bench "trivial lazy Text x50" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) t50LazyTrivial
, bench "ByteArray x50" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) ba50
, bench "ByteArray x50 (pinned, aligned)" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) ba50Aligned -- (maybe non-aligned creation is aligned to word size)
, bench "ByteArray x50 (pinned, incorrectly-aligned)" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) ba50AlignedBadly -- (no difference here either)
, bench "ByteArray x1000" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) ba1000
, bench "strict ByteString x1000" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) bs1000
, bench "lazy ByteString x1000, in 20 chunks" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) bs1000Lazy_by20Chunks
, bench "Text x1000" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) t1000
, bench "lazy Text x1000, in 20 chunks" $ nf (hashWord64 . siphash64 (SipKey 0x0706050403020100 0x0F0E0D0C0B0A0908)) t1000Lazy_by20Chunks
-- TODO Integer of comparable size to above
-- TODO BigNat on GHC 7.10
-- TODO Natural on GHC 7.10
]
, listBgroup "medium-size lists" 250
-- In line with above, although NoList variants win out by a greater margin:
--, listBgroup "small lists" 5
]
]
-- --------------------------------------------------------
-- Sorry, couldn't figure out how to turn these into CPP macros:
-- Taken from 'hashable' Benchmarks.hs @47eaf9f:
hashableBenchmarkFNV64 :: Benchmark
{-# INLINE hashableBenchmarkFNV64 #-}
hashableBenchmarkFNV64 =
let
!mb = (2::Int)^(20 :: Int) -- 1 Mb
s5 = ['\0'..'\4']; s8 = ['\0'..'\7']; s11 = ['\0'..'\10']
s40 = ['\0'..'\39']; s128 = ['\0'..'\127']; s512 = ['\0'..'\511']
s1Mb = ['\0'..'\999999']
!bs5 = B8.pack s5; !bs8 = B8.pack s8; !bs11 = B8.pack s11
!bs40 = B8.pack s40; !bs128 = B8.pack s128; !bs512 = B8.pack s512
!bs1Mb = B8.pack s1Mb
blmeg = BL.take (fromIntegral mb) . BL.fromChunks . repeat
bl5 = BL.fromChunks [bs5]; bl8 = BL.fromChunks [bs8]
bl11 = BL.fromChunks [bs11]; bl40 = BL.fromChunks [bs40]
bl128 = BL.fromChunks [bs128]; bl512 = BL.fromChunks [bs512]
bl1Mb_40 = blmeg bs40; bl1Mb_128 = blmeg bs128
bl1Mb_64k = blmeg (B8.take 65536 bs1Mb)
!t5 = T.pack s5; !t8 = T.pack s8; !t11 = T.pack s11
!t40 = T.pack s40; !t128 = T.pack s128; !t512 = T.pack s512
!t1Mb = T.pack s1Mb
tlmeg = TL.take (fromIntegral mb) . TL.fromChunks . repeat
tl5 = TL.fromStrict t5; tl8 = TL.fromStrict t8
tl11 = TL.fromStrict t11; tl40 = TL.fromStrict t40
tl128 = TL.fromStrict t128; tl512 = TL.fromChunks (replicate 4 t128)
tl1Mb_40 = tlmeg t40; tl1Mb_128 = tlmeg t128
tl1Mb_64k = tlmeg (T.take 65536 t1Mb)
in bgroup "hashabler hashFNV64"
[ bgroup "ByteString"
[ bgroup "strict"
[ bench "5" $ whnf (hashWord64 . hashFNV64) bs5
, bench "8" $ whnf (hashWord64 . hashFNV64) bs8
, bench "11" $ whnf (hashWord64 . hashFNV64) bs11
, bench "40" $ whnf (hashWord64 . hashFNV64) bs40
, bench "128" $ whnf (hashWord64 . hashFNV64) bs128
, bench "512" $ whnf (hashWord64 . hashFNV64) bs512
, bench "2^20" $ whnf (hashWord64 . hashFNV64) bs1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf (hashWord64 . hashFNV64) bl5
, bench "8" $ whnf (hashWord64 . hashFNV64) bl8
, bench "11" $ whnf (hashWord64 . hashFNV64) bl11
, bench "40" $ whnf (hashWord64 . hashFNV64) bl40
, bench "128" $ whnf (hashWord64 . hashFNV64) bl128
, bench "512" $ whnf (hashWord64 . hashFNV64) bl512
, bench "2^20_40" $ whnf (hashWord64 . hashFNV64) bl1Mb_40
, bench "2^20_128" $ whnf (hashWord64 . hashFNV64) bl1Mb_128
, bench "2^20_64k" $ whnf (hashWord64 . hashFNV64) bl1Mb_64k
]
]
, bgroup "String"
[ bench "5" $ whnf (hashWord64 . hashFNV64) s5
, bench "8" $ whnf (hashWord64 . hashFNV64) s8
, bench "11" $ whnf (hashWord64 . hashFNV64) s11
, bench "40" $ whnf (hashWord64 . hashFNV64) s40
, bench "128" $ whnf (hashWord64 . hashFNV64) s128
, bench "512" $ whnf (hashWord64 . hashFNV64) s512
, bench "2^20" $ whnf (hashWord64 . hashFNV64) s1Mb
]
, bgroup "Text"
[ bgroup "strict"
[ bench "5" $ whnf (hashWord64 . hashFNV64) t5
, bench "8" $ whnf (hashWord64 . hashFNV64) t8
, bench "11" $ whnf (hashWord64 . hashFNV64) t11
, bench "40" $ whnf (hashWord64 . hashFNV64) t40
, bench "128" $ whnf (hashWord64 . hashFNV64) t128
, bench "512" $ whnf (hashWord64 . hashFNV64) t512
, bench "2^20" $ whnf (hashWord64 . hashFNV64) t1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf (hashWord64 . hashFNV64) tl5
, bench "8" $ whnf (hashWord64 . hashFNV64) tl8
, bench "11" $ whnf (hashWord64 . hashFNV64) tl11
, bench "40" $ whnf (hashWord64 . hashFNV64) tl40
, bench "128" $ whnf (hashWord64 . hashFNV64) tl128
, bench "512" $ whnf (hashWord64 . hashFNV64) tl512
, bench "2^20_40" $ whnf (hashWord64 . hashFNV64) tl1Mb_40
, bench "2^20_128" $ whnf (hashWord64 . hashFNV64) tl1Mb_128
, bench "2^20_64k" $ whnf (hashWord64 . hashFNV64) tl1Mb_64k
]
]
, bench "Int8" $ whnf (hashWord64 . hashFNV64) (127 :: Int8)
, bench "Int16" $ whnf (hashWord64 . hashFNV64) (0x7eef :: Int16)
, bench "Int32" $ whnf (hashWord64 . hashFNV64) (0x7eadbeef :: Int32)
, bench "Int" $ whnf (hashWord64 . hashFNV64) (0x7eadbeefdeadbeef :: Int)
, bench "Int64" $ whnf (hashWord64 . hashFNV64) (0x7eadbeefdeadbeef :: Int64)
, bench "Double" $ whnf (hashWord64 . hashFNV64) (0.3780675796601578 :: Double)
]
-- Taken from 'hashable' Benchmarks.hs @47eaf9f:
hashableBenchmarkSiphash64 :: Benchmark
{-# INLINE hashableBenchmarkSiphash64 #-}
hashableBenchmarkSiphash64 =
let
!mb = (2::Int)^(20 :: Int) -- 1 Mb
s5 = ['\0'..'\4']; s8 = ['\0'..'\7']; s11 = ['\0'..'\10']
s40 = ['\0'..'\39']; s128 = ['\0'..'\127']; s512 = ['\0'..'\511']
s1Mb = ['\0'..'\999999']
!bs5 = B8.pack s5; !bs8 = B8.pack s8; !bs11 = B8.pack s11
!bs40 = B8.pack s40; !bs128 = B8.pack s128; !bs512 = B8.pack s512
!bs1Mb = B8.pack s1Mb
blmeg = BL.take (fromIntegral mb) . BL.fromChunks . repeat
bl5 = BL.fromChunks [bs5]; bl8 = BL.fromChunks [bs8]
bl11 = BL.fromChunks [bs11]; bl40 = BL.fromChunks [bs40]
bl128 = BL.fromChunks [bs128]; bl512 = BL.fromChunks [bs512]
bl1Mb_40 = blmeg bs40; bl1Mb_128 = blmeg bs128
bl1Mb_64k = blmeg (B8.take 65536 bs1Mb)
!t5 = T.pack s5; !t8 = T.pack s8; !t11 = T.pack s11
!t40 = T.pack s40; !t128 = T.pack s128; !t512 = T.pack s512
!t1Mb = T.pack s1Mb
tlmeg = TL.take (fromIntegral mb) . TL.fromChunks . repeat
tl5 = TL.fromStrict t5; tl8 = TL.fromStrict t8
tl11 = TL.fromStrict t11; tl40 = TL.fromStrict t40
tl128 = TL.fromStrict t128; tl512 = TL.fromChunks (replicate 4 t128)
tl1Mb_40 = tlmeg t40; tl1Mb_128 = tlmeg t128
tl1Mb_64k = tlmeg (T.take 65536 t1Mb)
in bgroup "hashabler siphash64"
[ bgroup "ByteString"
[ bgroup "strict"
[ bench "5" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs5
, bench "8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs8
, bench "11" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs11
, bench "40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs40
, bench "128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs128
, bench "512" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs512
, bench "2^20" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bs1Mb
]
, bgroup "strict (with siphash-1-3)" -- TODO make proper benchmark set for siphash64_1_3
[ bench "5" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs5
, bench "8" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs8
, bench "11" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs11
, bench "40" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs40
, bench "128" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs128
, bench "512" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs512
, bench "2^20" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) bs1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl5
, bench "8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl8
, bench "11" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl11
, bench "40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl40
, bench "128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl128
, bench "512" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl512
, bench "2^20_40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl1Mb_40
, bench "2^20_128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl1Mb_128
, bench "2^20_64k" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) bl1Mb_64k
]
]
, bgroup "String"
[ bench "5" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s5
, bench "8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s8
, bench "11" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s11
, bench "40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s40
, bench "128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s128
, bench "512" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s512
, bench "2^20" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) s1Mb
]
, bgroup "Text"
[ bgroup "strict"
[ bench "5" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t5
, bench "8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t8
, bench "11" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t11
, bench "40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t40
, bench "128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t128
, bench "512" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t512
, bench "2^20" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) t1Mb
]
, bgroup "strict (with siphash-1-3)" -- TODO make proper benchmark set for siphash64_1_3
[ bench "5" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t5
, bench "8" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t8
, bench "11" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t11
, bench "40" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t40
, bench "128" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t128
, bench "512" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t512
, bench "2^20" $ whnf (hashWord64 . siphash64_1_3 (SipKey 1 2)) t1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl5
, bench "8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl8
, bench "11" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl11
, bench "40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl40
, bench "128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl128
, bench "512" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl512
, bench "2^20_40" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl1Mb_40
, bench "2^20_128" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl1Mb_128
, bench "2^20_64k" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) tl1Mb_64k
]
]
, bench "Int8" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (127 :: Int8)
, bench "Int16" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (0x7eef :: Int16)
, bench "Int32" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (0x7eadbeef :: Int32)
, bench "Int" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (0x7eadbeefdeadbeef :: Int)
, bench "Int64" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (0x7eadbeefdeadbeef :: Int64)
, bench "Double" $ whnf (hashWord64 . siphash64 (SipKey 1 2)) (0.3780675796601578 :: Double)
]
-- Same as above; just couldn't quite figure out how to get this to work
hashableBenchmarkTheir :: String -> Benchmark
{-# INLINE hashableBenchmarkTheir #-}
hashableBenchmarkTheir nm =
let
!mb = (2::Int)^(20 :: Int) -- 1 Mb
s5 = ['\0'..'\4']; s8 = ['\0'..'\7']; s11 = ['\0'..'\10']
s40 = ['\0'..'\39']; s128 = ['\0'..'\127']; s512 = ['\0'..'\511']
s1Mb = ['\0'..'\999999']
!bs5 = B8.pack s5; !bs8 = B8.pack s8; !bs11 = B8.pack s11
!bs40 = B8.pack s40; !bs128 = B8.pack s128; !bs512 = B8.pack s512
!bs1Mb = B8.pack s1Mb
blmeg = BL.take (fromIntegral mb) . BL.fromChunks . repeat
bl5 = BL.fromChunks [bs5]; bl8 = BL.fromChunks [bs8]
bl11 = BL.fromChunks [bs11]; bl40 = BL.fromChunks [bs40]
bl128 = BL.fromChunks [bs128]; bl512 = BL.fromChunks [bs512]
bl1Mb_40 = blmeg bs40; bl1Mb_128 = blmeg bs128
bl1Mb_64k = blmeg (B8.take 65536 bs1Mb)
!t5 = T.pack s5; !t8 = T.pack s8; !t11 = T.pack s11
!t40 = T.pack s40; !t128 = T.pack s128; !t512 = T.pack s512
!t1Mb = T.pack s1Mb
tlmeg = TL.take (fromIntegral mb) . TL.fromChunks . repeat
tl5 = TL.fromStrict t5; tl8 = TL.fromStrict t8
tl11 = TL.fromStrict t11; tl40 = TL.fromStrict t40
tl128 = TL.fromStrict t128; tl512 = TL.fromChunks (replicate 4 t128)
tl1Mb_40 = tlmeg t40; tl1Mb_128 = tlmeg t128
tl1Mb_64k = tlmeg (T.take 65536 t1Mb)
in bgroup nm
[ bgroup "ByteString"
[ bgroup "strict"
[ bench "5" $ whnf Their.hash bs5
, bench "8" $ whnf Their.hash bs8
, bench "11" $ whnf Their.hash bs11
, bench "40" $ whnf Their.hash bs40
, bench "128" $ whnf Their.hash bs128
, bench "512" $ whnf Their.hash bs512
, bench "2^20" $ whnf Their.hash bs1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf Their.hash bl5
, bench "8" $ whnf Their.hash bl8
, bench "11" $ whnf Their.hash bl11
, bench "40" $ whnf Their.hash bl40
, bench "128" $ whnf Their.hash bl128
, bench "512" $ whnf Their.hash bl512
, bench "2^20_40" $ whnf Their.hash bl1Mb_40
, bench "2^20_128" $ whnf Their.hash bl1Mb_128
, bench "2^20_64k" $ whnf Their.hash bl1Mb_64k
]
]
, bgroup "String"
[ bench "5" $ whnf Their.hash s5
, bench "8" $ whnf Their.hash s8
, bench "11" $ whnf Their.hash s11
, bench "40" $ whnf Their.hash s40
, bench "128" $ whnf Their.hash s128
, bench "512" $ whnf Their.hash s512
, bench "2^20" $ whnf Their.hash s1Mb
]
, bgroup "Text"
[ bgroup "strict"
[ bench "5" $ whnf Their.hash t5
, bench "8" $ whnf Their.hash t8
, bench "11" $ whnf Their.hash t11
, bench "40" $ whnf Their.hash t40
, bench "128" $ whnf Their.hash t128
, bench "512" $ whnf Their.hash t512
, bench "2^20" $ whnf Their.hash t1Mb
]
, bgroup "lazy"
[ bench "5" $ whnf Their.hash tl5
, bench "8" $ whnf Their.hash tl8
, bench "11" $ whnf Their.hash tl11
, bench "40" $ whnf Their.hash tl40
, bench "128" $ whnf Their.hash tl128
, bench "512" $ whnf Their.hash tl512
, bench "2^20_40" $ whnf Their.hash tl1Mb_40
, bench "2^20_128" $ whnf Their.hash tl1Mb_128
, bench "2^20_64k" $ whnf Their.hash tl1Mb_64k
]
]
, bench "Int8" $ whnf Their.hash (127 :: Int8)
, bench "Int16" $ whnf Their.hash (0x7eef :: Int16)
, bench "Int32" $ whnf Their.hash (0x7eadbeef :: Int32)
, bench "Int" $ whnf Their.hash (0x7eadbeefdeadbeef :: Int)
, bench "Int64" $ whnf Their.hash (0x7eadbeefdeadbeef :: Int64)
, bench "Double" $ whnf Their.hash (0.3780675796601578 :: Double)
]