ttrie-0.1.0.0: benchmarks/Common.hs
{-# LANGUAGE DeriveGeneric #-}
module Common where
import BenchGen
import Control.Applicative
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Concurrent.STM.Stats
import Control.DeepSeq
import Control.Monad
import Criterion.Main
import qualified Data.Map as Map
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics
import System.Random.MWC
import System.Random.MWC.CondensedTable
import Text.Printf
import qualified Control.Concurrent.STM.Map as TTrie
import qualified STMContainers.Map as STMCont
import qualified Data.HashMap.Strict as HashMap
------------------------------------------------------------------------------
data Op = Lookup | Insert | Delete
deriving (Eq, Show, Generic)
instance NFData Op
key :: Generator IO k Text
key = do
n <- liftGen $ genFromTable length
T.pack <$> replicateM n (liftGen $ genFromTable alphabet)
where
length = mkTable $ zip [7..20] (repeat 1)
alphabet = mkTable $ zip ['a'..'z'] (repeat 1)
------------------------------------------------------------------------------
runAll :: [Int] -> Int -> CondensedTableV Int -> Config IO Op Text -> IO ()
runAll numThreads numTransactions sizes config = do
txs <- genTransactions numTransactions sizes config
runBenchmarks txs numTransactions numThreads
collectRetryStats txs numTransactions numThreads
genTransactions :: Int -> CondensedTableV Int -> Config IO Op Text -> IO [[(Op, Text)]]
genTransactions numTransactions sizes config = do
printf "Generating %d random transactions...\n" numTransactions
gen <- create
runGenerator gen $ do
replicateM numTransactions $ do
size <- liftGen $ genFromTable sizes
generateOperations config size
runBenchmarks :: [[(Op, Text)]] -> Int -> [Int] -> IO ()
runBenchmarks txs numTransactions numThreads =
defaultMain $! flip map numThreads
$ \n -> env (return $! split (numTransactions `div` n) txs)
$ \ ~ops -> bgroup (printf "%d/%d" n (numTransactions `div` n))
[ bench "unordered-containers" $ whnfIO $ run ops hashmapEval =<< newTVarIO HashMap.empty
, bench "unordered-containers2" $ whnfIO $ run ops hashmapEval2 =<< newTVarIO HashMap.empty
, bench "stm-containers" $ whnfIO $ run ops stmcontEval =<< STMCont.newIO
, bench "ttrie" $ whnfIO $ run ops ttrieEval =<< atomically TTrie.empty
]
where
run ops f c = mapConcurrently (mapM_ txEval) ops
where txEval = atomically . mapM_ (\(op,k) -> f op k c)
collectRetryStats :: [[(Op, Text)]] -> Int -> [Int] -> IO ()
collectRetryStats txs numTransactions numThreads =
flip mapM_ numThreads $ \n -> do
let ops = split (numTransactions `div` n) txs
str = printf "%d/%d" n (numTransactions `div` n)
run (str++"/unordered-containers") ops hashmapEval =<< newTVarIO HashMap.empty
run (str++"/unordered-containers2") ops hashmapEval2 =<< newTVarIO HashMap.empty
run (str++"/stm-containers") ops stmcontEval =<< STMCont.newIO
run (str++"/ttrie") ops ttrieEval =<< atomically TTrie.empty
where
run name ops f c = do
printf "collecting retry statistics for %s\n" name
mapConcurrently (mapM_ txEval) ops
printStats name
where
txEval = atomically' name . mapM_ (\(op,k) -> f op k c)
atomically' = trackSTMConf defaultTrackSTMConf
{ tryThreshold = Nothing
, globalTheshold = Nothing
}
printStats name = do
stats <- getSTMStats
let Just (commits, retries) = Map.lookup name stats
printf "Commits\t%d\nRetries\t%d\n\n" commits retries
split n [] = []
split n xs = let (ys,zs) = splitAt n xs in ys : split n zs
------------------------------------------------------------------------------
-- Evaluation functions
ttrieEval Lookup k = void . TTrie.lookup k
ttrieEval Insert k = TTrie.insert k ()
ttrieEval Delete k = TTrie.delete k
stmcontEval Lookup k = void . STMCont.lookup k
stmcontEval Insert k = STMCont.insert () k
stmcontEval Delete k = STMCont.delete k
hashmapEval Lookup k m = do
v <- HashMap.lookup k <$> readTVar m
case v of
Nothing -> return ()
Just v -> readTVar v >> return ()
hashmapEval Insert k m = do
v <- newTVar ()
modifyTVar' m (HashMap.insert k v)
hashmapEval Delete k m = modifyTVar' m (HashMap.delete k)
hashmapEval2 Lookup k m = HashMap.lookup k <$> readTVar m >> return ()
hashmapEval2 Insert k m = modifyTVar' m (HashMap.insert k ())
hashmapEval2 Delete k m = modifyTVar' m (HashMap.delete k)