ctrie-0.1.0.0: benchmarks/Concurrent.hs
{-# LANGUAGE BangPatterns #-}
module Main where
import Control.Applicative ((<$>))
import Control.Concurrent.Async
import Control.Concurrent.MVar
import Control.DeepSeq
import Control.Exception (evaluate)
import Control.Monad
import Control.Monad.IO.Class (liftIO)
import Criterion.Main
import Criterion.Config
import Data.Hashable
import Data.List (foldl')
import Data.Foldable (foldlM)
import Data.Maybe
import System.Random
import System.Random.Shuffle
import System.IO.Unsafe
import qualified Control.Concurrent.Map as CM
import qualified Data.Map as M
import qualified Data.IntMap as IM
import qualified Data.HashMap.Strict as HM
main :: IO ()
main = do
let hmS = HM.fromList elemsS :: HM.HashMap String Int
hmS_mvar <- newMVar hmS
let hmS_ops241_8 = hmOps hmS_mvar elemsS 8 n (2,4,1)
let hmS_ops621_n10_8 = hmOps hmS_mvar elemsS 8 (n*10) (6,2,1)
cmS <- CM.fromList elemsS :: IO (CM.Map String Int)
let cmS_ops241_8 = cmOps cmS elemsS 8 n (2,4,1)
let cmS_ops621_n10_8 = cmOps cmS elemsS 8 (n*10) (6,2,1)
putStrLn $ "n=" ++ show n
defaultMainWith defaultConfig
(liftIO $ do
evaluate $ rnf hmS
evaluate $ sum $ map length hmS_ops241_8
evaluate $ sum $ map length hmS_ops621_n10_8
evaluate $ rnf $ unsafePerformIO $ CM.unsafeToList cmS
evaluate $ sum $ map length cmS_ops241_8
evaluate $ sum $ map length cmS_ops621_n10_8
return ()
)
[
bgroup "Data.HashMap (MVar)"
[ bgroup "String"
[ bench "8 threads, n, 2:4:1" $ runAll hmS_ops241_8
, bench "8 threads, 10n, 6:2:1" $ runAll hmS_ops621_n10_8
]
]
,
bgroup "Control.Concurrent.Map"
[ bgroup "String"
[ bench "8 threads, n, 2:4:1" $ runAll cmS_ops241_8
, bench "8 threads, 10n, 6:2:1" $ runAll cmS_ops621_n10_8
]
]
]
where
n = 2^12
elemsS = zip keysS [1..n]
elemsI = zip keysI [1..n]
keysS = rndS 8 n
keysI = rndI (n+n) n
rndS :: Int -> Int -> [String]
rndS strlen num = take num $ split $ randomRs ('a', 'z') $ mkStdGen 1234
where
split cs = case splitAt strlen cs of (str, cs') -> str : split cs'
rndI :: Int -> Int -> [Int]
rndI upper num = take num $ randomRs (0, upper) $ mkStdGen 1234
runAll :: [[IO ()]] -> IO ()
runAll ops = do
as <- mapM (async . sequence_) ops
mapM_ wait as
mkOps :: (k -> m -> IO ()) -- lookup function
-> (k -> v -> m -> IO ()) -- insert function
-> (k -> m -> IO ()) -- delete function
-> m -> [(k,v)] -- the map & the elements from which to draw
-> Int -- the number of threads
-> Int -- the number of operations per thread
-> (Int, Int, Int) -- ratio of lookups : insertions : deletions
-> [[IO ()]]
mkOps lookup insert delete m elems nThreads nOps (rl,ri,rd) =
let tot = fromIntegral $ rl + ri + rd
numLookups = ceiling $ fromIntegral nOps * (fromIntegral rl / tot)
numInserts = ceiling $ fromIntegral nOps * (fromIntegral ri / tot)
numDeletes = ceiling $ fromIntegral nOps * (fromIntegral rd / tot)
lookupElems = shuffle' (take nOps $ cycle elems) nOps (mkStdGen 1234)
insertElems = shuffle' (take nOps $ cycle elems) nOps (mkStdGen 5678)
deleteElems = shuffle' (take nOps $ cycle elems) nOps (mkStdGen 9012)
ops0 = [lookup k m | (k,_) <- take numLookups lookupElems]
++ [insert k v m | (k,v) <- take numInserts insertElems]
++ [delete k m | (k,_) <- take numDeletes deleteElems]
ops = take nThreads
$ iterate (\ops -> shuffle' ops nOps (mkStdGen 1234))
$ take nOps ops0
in ops
-----------------------------------------------------------------------
-- Control.Concurrent.Map
cmOps = mkOps cm_lookup CM.insert CM.delete
cm_lookup :: (Eq k, Hashable k) => k -> CM.Map k v -> IO ()
cm_lookup k m = do
let v = CM.lookup k m
v `seq` return ()
{-# SPECIALIZE cm_lookup :: String -> CM.Map String Int -> IO () #-}
{-# SPECIALIZE cm_lookup :: Int -> CM.Map Int Int -> IO () #-}
-----------------------------------------------------------------------
-- Data.HashMap
hmOps = mkOps hm_lookup hm_insert hm_delete
hm_lookup :: (Eq k, Hashable k) => k -> MVar (HM.HashMap k v) -> IO ()
hm_lookup k mvar = do
--return undefined
m <- takeMVar mvar
putMVar mvar m
let v = HM.lookup k m
v `seq` return ()
{-# SPECIALIZE hm_lookup :: String -> MVar (HM.HashMap String Int) -> IO () #-}
{-# SPECIALIZE hm_lookup :: Int -> MVar (HM.HashMap Int Int) -> IO () #-}
hm_insert :: (Eq k, Hashable k) => k -> v -> MVar (HM.HashMap k v) -> IO ()
hm_insert k v mvar = do
--return ()
m <- takeMVar mvar
putMVar mvar $! HM.insert k v m
{-# SPECIALIZE hm_insert :: String -> Int -> MVar (HM.HashMap String Int) -> IO () #-}
{-# SPECIALIZE hm_insert :: Int -> Int -> MVar (HM.HashMap Int Int) -> IO () #-}
hm_delete :: (Eq k, Hashable k) => k -> MVar (HM.HashMap k v) -> IO ()
hm_delete k mvar = do
--return ()
m <- takeMVar mvar
putMVar mvar $! HM.delete k m
{-# SPECIALIZE hm_delete :: String -> MVar (HM.HashMap String Int) -> IO () #-}
{-# SPECIALIZE hm_delete :: Int -> MVar (HM.HashMap Int Int) -> IO () #-}