{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeApplications #-}
import Gauge.Main
import Type.Reflection (typeRep,TypeRep)
import Data.Primitive (ByteArray(..),PrimArray(..),Prim)
import Control.Monad.ST (ST,runST)
import Data.Int
import Data.Word
import System.Random (mkStdGen,randoms,Random)
import GHC.Prim (proxy#, Proxy#)
import qualified GHC.OldList as L
import qualified Data.Primitive as P
import qualified Data.Primitive.Sort
import qualified GHC.Exts as E
main :: IO ()
main = defaultMain
[ bgroup "contiguous"
[ benchType (typeRep :: TypeRep Int8) (primArrayToByteArray . Data.Primitive.Sort.sort @PrimArray @Int8 . byteArrayToPrimArray)
, benchType (typeRep :: TypeRep Word) (primArrayToByteArray . Data.Primitive.Sort.sort @PrimArray @Word . byteArrayToPrimArray)
]
, bgroup "tagged-unique"
[ bench "mini" (whnf (\(k,v) -> evalPair (Data.Primitive.Sort.sortUniqueTagged k v)) (sizedInts Mini, sizedInts Mini))
, bench "tiny" (whnf (\(k,v) -> evalPair (Data.Primitive.Sort.sortUniqueTagged k v)) (sizedInts Tiny, sizedInts Tiny))
, bench "small" (whnf (\(k,v) -> evalPair (Data.Primitive.Sort.sortUniqueTagged k v)) (sizedInts Small, sizedInts Small))
]
]
evalPair :: (PrimArray a, PrimArray b) -> ()
evalPair (!_,!_) = ()
primArrayToByteArray :: PrimArray a -> ByteArray
primArrayToByteArray (PrimArray x) = ByteArray x
byteArrayToPrimArray :: ByteArray -> PrimArray a
byteArrayToPrimArray (ByteArray x) = PrimArray x
data Size = Mini | Tiny | Small | Medium | Large | Gigantic
deriving (Enum,Bounded)
data Arrangement = Unsorted | Presorted | Reversed
deriving (Enum,Bounded)
allSizes :: [Size]
allSizes = [minBound..maxBound]
allArrangements :: [Arrangement]
allArrangements = [minBound..maxBound]
showSize :: Size -> String
showSize x = case x of
Mini -> "mini"
Tiny -> "tiny"
Small -> "small"
Medium -> "medium"
Large -> "large"
Gigantic -> "gigantic"
numSize :: Size -> Int
numSize x = case x of
Mini -> 10
Tiny -> 100
Small -> 1000
Medium -> 10000
Large -> 100000
Gigantic -> 1000000
sizedInts :: Size -> PrimArray Int
sizedInts x = case x of
Mini -> intsMini
Tiny -> intsTiny
Small -> intsSmall
Medium -> intsMedium
Large -> intsLarge
Gigantic -> intsGigantic
intsMini,intsTiny,intsSmall,intsMedium,intsLarge,intsGigantic :: PrimArray Int
intsMini = E.fromList (L.take 10 (randoms (mkStdGen 23) :: [Int]))
intsTiny = E.fromList (L.take 100 (randoms (mkStdGen 87) :: [Int]))
intsSmall = E.fromList (L.take 1000 (randoms (mkStdGen 19) :: [Int]))
intsMedium = E.fromList (L.take 10000 (randoms (mkStdGen 47) :: [Int]))
intsLarge = E.fromList (L.take 100000 (randoms (mkStdGen 53) :: [Int]))
intsGigantic = E.fromList (L.take 1000000 (randoms (mkStdGen 12) :: [Int]))
showArrangement :: Arrangement -> String
showArrangement x = case x of
Unsorted -> "unsorted"
Presorted -> "presorted"
Reversed -> "reversed"
buildArrangement :: (Prim a, Num a, Random a, Enum a, Bounded a)
=> Arrangement -> TypeRep a -> Int -> ByteArray
buildArrangement x = case x of
Unsorted -> unsorted
Presorted -> presorted
Reversed -> reversed
benchType :: (Prim a, Num a, Random a, Enum a, Bounded a)
=> TypeRep a -> (ByteArray -> ByteArray) -> Benchmark
benchType rep sort = bgroup
(show rep)
(map (\arrange -> benchArrangement rep arrange sort) allArrangements)
benchArrangement :: (Prim a, Num a, Random a, Enum a, Bounded a)
=> TypeRep a -> Arrangement -> (ByteArray -> ByteArray) -> Benchmark
benchArrangement rep arrange sort = bgroup
(showArrangement arrange)
(map (\sz -> let arr = buildArrangement arrange rep (numSize sz) in benchSize arr sz sort) allSizes)
benchSize :: ByteArray -> Size -> (ByteArray -> ByteArray) -> Benchmark
benchSize arr sz sort =
bench (showSize sz) (whnf sort arr)
unsorted :: forall a. (Prim a, Random a) => TypeRep a -> Int -> ByteArray
unsorted typ n = byteArrayFromList
(L.take n (randoms (mkStdGen 42) :: [a]))
presorted :: forall a. (Prim a, Num a, Enum a, Bounded a) => TypeRep a -> Int -> ByteArray
presorted typ n = byteArrayFromList
(L.take n (iterate (+1) (minBound :: a)))
reversed :: forall a. (Prim a, Num a, Enum a, Bounded a)
=> TypeRep a -> Int -> ByteArray
reversed typ n = byteArrayFromList
(L.take n (iterate (subtract 1) (maxBound :: a)))
byteArrayFromList :: Prim a => [a] -> ByteArray
byteArrayFromList xs = byteArrayFromListN (L.length xs) xs
byteArrayFromListN :: forall a. Prim a => Int -> [a] -> ByteArray
byteArrayFromListN len vs = runST run where
run :: forall s. ST s ByteArray
run = do
arr <- P.newByteArray (len * P.sizeOf (undefined :: a))
let go :: [a] -> Int -> ST s ()
go !xs !ix = case xs of
[] -> return ()
a : as -> do
P.writeByteArray arr ix a
go as (ix + 1)
go vs 0
P.unsafeFreezeByteArray arr