packages feed

hashes-0.1.0.0: bench/Main.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- |
-- Module: Main
-- Copyright: Copyright © 2021 Lars Kuhtz <lakuhtz@gmail.com>
-- License: MIT
-- Maintainer: Lars Kuhtz <lakuhtz@gmail.com>
-- Stability: experimental
--
module Main
( main
) where

import Criterion
import Criterion.Main

import qualified Data.ByteArray as BA
import qualified Data.ByteArray.Hash as BA
import qualified Data.ByteString as B
import Data.Word

import GHC.Ptr

import Test.QuickCheck

-- internal modules

import qualified Data.Hash.SipHash as H
import qualified Data.Hash.FNV1 as H

-- -------------------------------------------------------------------------- --
-- Main

main :: IO ()
main = do
    putStrLn "prop_sip"
    quickCheck prop_sip
    putStrLn "prop_fnv1a"
    quickCheck prop_fnv1a
    putStrLn "prop_fnv1aPrimitive"
    quickCheck prop_fnv1aPrimitive
    defaultMain
        [ bgroup "sipHash"
            [ sipBench "memory" (memorySipHash 17 17)
            , sipBench "internal" (H.hashByteString $ H.sipHash24 17 17)
            ]
        , bgroup "fnv1aHash"
            [ fnv1aBench "memory" memoryFnv1a
            , fnv1aBench "internal" (H.hashByteString H.fnv1a_64)
            , fnv1aBench "primitive" primitiveFnv1a
            ]
        ]

-- -------------------------------------------------------------------------- --
-- SipHash

memorySipHash :: BA.ByteArrayAccess p => Word64 -> Word64 -> p -> Word64
memorySipHash w0 w1 x = let BA.SipHash r = BA.sipHash (BA.SipKey w0 w1) x in r
{-# INLINE memorySipHash #-}

prop_sip :: Word64 -> Word64 -> [Word8] -> Property
prop_sip w0 w1 b =
    memorySipHash w0 w1 (B.pack b) === H.hashByteString (H.sipHash24 w0 w1) (B.pack b)

sipBench :: String -> (B.ByteString -> Word64) -> Benchmark
sipBench l f = bgroup l $ go <$> benchStrings
  where
    go i = bench (show (B.length i)) $ whnf f i

benchStrings :: [B.ByteString]
benchStrings = str <$> [0, 1, 5, 67, 300, 2000, 20000]
  where
    str (i :: Int) = B.pack $ fromIntegral <$> [0..i-1]

-- -------------------------------------------------------------------------- --
-- Fvn1Hash

memoryFnv1a :: B.ByteString -> Word64
memoryFnv1a b = let BA.FnvHash64 h = BA.fnv1a_64Hash b in h
{-# INLINE memoryFnv1a #-}

primitiveFnv1a :: B.ByteString -> Word64
primitiveFnv1a = H.hashByteString $ \(Ptr addr) n ->
    fromIntegral <$> H.fnv1a addr n
{-# INLINE primitiveFnv1a #-}

prop_fnv1a :: [Word8] -> Property
prop_fnv1a b = memoryFnv1a (B.pack b) === H.hashByteString H.fnv1a_64 (B.pack b)

prop_fnv1aPrimitive :: [Word8] -> Property
prop_fnv1aPrimitive b = primitiveFnv1a (B.pack b) === H.hashByteString H.fnv1a_64 (B.pack b)

fnv1aBench :: String -> (B.ByteString -> Word64) -> Benchmark
fnv1aBench l f = bgroup l $ go <$> benchStrings
  where
    go i = bench (show (B.length i)) $ whnf f i