packages feed

shortbytestring-0.1.0.0: bench/Short/BenchAll.hs

-- |
-- Copyright   : (c) 2011 Simon Meier
-- License     : BSD3-style (see LICENSE)
--
-- Maintainer  : Simon Meier <iridcode@gmail.com>
-- Stability   : experimental
-- Portability : tested on GHC only
--

{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE PackageImports      #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MagicHash           #-}

module Short.BenchAll (benchmarks) where

import Short.BenchIndices

import           Data.Monoid
import           Data.String
import           Test.Tasty.Bench
import           Prelude                               hiding (words)

import qualified "bytestring" Data.ByteString.Char8                 as S8
import "shortbytestring" Data.ByteString.Short                 ( ShortByteString )
import qualified "shortbytestring" Data.ByteString.Short             as S


import           Foreign

import System.Random



------------------------------------------------------------------------------
-- Benchmark
------------------------------------------------------------------------------

-- input data (NOINLINE to ensure memoization)
----------------------------------------------

-- | Few-enough repetitions to avoid making GC too expensive.
nRepl :: Int
nRepl = 10000

{-# NOINLINE intData #-}
intData :: [Int]
intData = [1..nRepl]

{-# NOINLINE byteStringData #-}
byteStringData :: ShortByteString
byteStringData = S.pack $ map fromIntegral intData

-- benchmark wrappers
---------------------

{-# INLINE benchB' #-}
benchB' :: String -> a -> (a -> ShortByteString) -> Benchmark
benchB' name x b = bench name $ whnf (S.length . b) x


hashInt :: Int -> Int
hashInt x = iterate step x !! 10
  where
    step a = e
      where b = (a `xor` 61) `xor` (a `shiftR` 16)
            c = b + (b `shiftL` 3)
            d = c `xor` (c `shiftR` 4)
            e = d * 0x27d4eb2d

w :: Int -> Word8
w = fromIntegral

hashWord8 :: Word8 -> Word8
hashWord8 = fromIntegral . hashInt . fromIntegral

partitionStrict :: (Word8 -> Bool) -> Benchmarkable
partitionStrict p = nf (S.partition p) . randomStrict $ mkStdGen 98423098
  where randomStrict = fst . S.unfoldrN 10000 (Just . random)


-- benchmarks
-------------


foldInputs :: [ShortByteString]
foldInputs = map (\k -> S.pack $ if (k :: Int) <= 6 then take (2 ^ k) [32..95] else concat (replicate (2 ^ (k - 6)) [32..95])) [0..16]

largeTraversalInput :: ShortByteString
largeTraversalInput = S.concat (replicate 10 byteStringData)

smallTraversalInput :: ShortByteString
smallTraversalInput = S.toShort . S8.unlines $ map S8.pack ["The quick brown fox"]

benchmarks :: [ Benchmark ]
benchmarks =
    [ bgroup "AFP.Data.ByteString.Short"
      [ bgroup "Small payload"
        [ benchB' "mempty"        ()  (const mempty)
        , benchB' "UTF-8 String (naive)" "hello world\0" fromString
        , benchB' "String (naive)" "hello world!" fromString
        ]
      ]

    , bgroup "partition"
      [
        bgroup "strict"
        [
          bench "mostlyTrueFast"  $ partitionStrict (< (w 225))
        , bench "mostlyFalseFast" $ partitionStrict (< (w 10))
        , bench "balancedFast"    $ partitionStrict (< (w 128))

        , bench "mostlyTrueSlow"  $ partitionStrict (\x -> hashWord8 x < w 225)
        , bench "mostlyFalseSlow" $ partitionStrict (\x -> hashWord8 x < w 10)
        , bench "balancedSlow"    $ partitionStrict (\x -> hashWord8 x < w 128)
        ]
      ]
    , bgroup "folds"
      [ bgroup "foldl'" $ map (\s -> bench (show $ S.length s) $
          nf (S.foldl' (\acc x -> acc + fromIntegral x) (0 :: Int)) s) foldInputs
      , bgroup "foldr'" $ map (\s -> bench (show $ S.length s) $
          nf (S.foldr' (\x acc -> fromIntegral x + acc) (0 :: Int)) s) foldInputs
      , bgroup "filter" $ map (\s -> bench (show $ S.length s) $
          nf (S.filter odd) s) foldInputs
      ]
    , bgroup "findIndex_"
      [ bench "find"           $ nf (S.find (>= 198)) byteStringData
      ]
    , bgroup "traversals"
      [ bench "map (+1) large" $ nf (S.map (+ 1)) largeTraversalInput
      , bench "map (+1) small" $ nf (S.map (+ 1)) smallTraversalInput
      ]
    , benchIndices
    ]