{-# OPTIONS -cpp -fglasgow-exts #-}
module BenchUtils where
--
-- Benchmark tool.
-- Compare a function against equivalent code from other libraries for
-- space and time.
--
import Data.ByteString (ByteString)
import qualified Data.ByteString as P
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Lazy as L
-- import qualified Data.ByteString as L
import Data.List
import Data.Char
import Data.Word
import Data.Int
import System.Mem
import Control.Concurrent
import System.IO
import System.CPUTime
import System.IO.Unsafe
import Control.Monad
import Control.Exception
import Text.Printf
run c x tests = sequence_ $ zipWith (doit c x) [1..] tests
doit :: Int -> a -> Int -> (String, [F a]) -> IO ()
doit count x n (s,ls) = do
printf "%2d " n
fn ls
printf "\t# %-16s\n" (show s)
hFlush stdout
where fn xs = case xs of
[f,g] -> runN count f x >> putStr "\n "
>> runN count g x >> putStr "\t"
[f] -> runN count f x >> putStr "\t"
_ -> return ()
run f x = dirtyCache fps' >> performGC >> threadDelay 100 >> time f x
runN 0 f x = return ()
runN c f x = run f x >> runN (c-1) f x
dirtyCache x = evaluate (P.foldl1' (+) x)
{-# NOINLINE dirtyCache #-}
time :: F a -> a -> IO ()
time (F f) a = do
start <- getCPUTime
v <- force (f a)
case v of
B -> printf "--\t"
_ -> do
end <- getCPUTime
let diff = (fromIntegral (end - start)) / (10^12)
printf "%0.3f " (diff :: Double)
hFlush stdout
------------------------------------------------------------------------
--
-- an existential list
--
data F a = forall b . Forceable b => F (a -> b)
data Result = T | B
--
-- a bit deepSeqish
--
class Forceable a where
force :: a -> IO Result
force v = v `seq` return T
#if !defined(HEAD)
instance Forceable P.ByteString where
force v = P.length v `seq` return T
#endif
instance Forceable L.ByteString where
force v = L.length v `seq` return T
-- instance Forceable SPS.PackedString where
-- force v = SPS.length v `seq` return T
-- instance Forceable PS.PackedString where
-- force v = PS.lengthPS v `seq` return T
instance Forceable a => Forceable (Maybe a) where
force Nothing = return T
force (Just v) = force v `seq` return T
instance Forceable [a] where
force v = length v `seq` return T
instance (Forceable a, Forceable b) => Forceable (a,b) where
force (a,b) = force a >> force b
instance Forceable Int
instance Forceable Int64
instance Forceable Bool
instance Forceable Char
instance Forceable Word8
instance Forceable Ordering
-- used to signal undefinedness
instance Forceable () where force () = return B
------------------------------------------------------------------------
--
-- some large strings to play with
--
fps :: P.ByteString
fps = unsafePerformIO $ P.readFile dict
{-# NOINLINE fps #-}
fps' :: P.ByteString
fps' = unsafePerformIO $ P.readFile dict'
{-# NOINLINE fps' #-}
lps :: L.ByteString
lps = unsafePerformIO $ do L.readFile dict
-- h <- openFile dict ReadMode
-- L.hGetContentsN CHUNK h
{-# NOINLINE lps #-}
lps' :: L.ByteString
lps' = unsafePerformIO $ do L.readFile dict'
-- h <- openFile dict' ReadMode
-- L.hGetContentsN CHUNK h
{-# NOINLINE lps' #-}
dict = "bigdata"
dict' = "data"
-- Some short hand.
type X = Int
type W = Word8
type P = P.ByteString
type B = L.ByteString