packages feed

ctrie-0.1.0.2: benchmarks/Sequential.hs

module Main where

import Control.Applicative ((<$>))
import Control.DeepSeq
import Control.Exception (evaluate)
import Control.Monad.IO.Class (liftIO)
import Criterion.Main
import Data.Hashable
import Data.List (foldl')
import Data.Foldable (foldlM)
import Data.Maybe
import System.Random
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


-- like with the tests, a lot of this is cribbed from unordered-containers

-- TODO: make Ctrie a proper NFData instance
instance (NFData k, NFData v) => NFData (CM.Map k v) where
    rnf m = rnf $ unsafePerformIO $ CM.unsafeToList m

main :: IO ()
main = do
    let n = 2^12
        keysS = rndS 8 n
        keysI = rndI (n+n) n
        elemsS = zip keysS [1..n]
        elemsI = zip keysI [1..n]

    let mkConcMap = do
        cmS <- CM.fromList elemsS :: IO (CM.Map String Int)
        cmI <- CM.fromList elemsI :: IO (CM.Map Int Int)
        return (keysS, elemsS, cmS, keysI, elemsI, cmI)

    let mkMap = do
        let mS = M.fromList elemsS :: M.Map String Int
            mI = M.fromList elemsI :: M.Map Int Int
        return (keysS, elemsS, mS, keysI, elemsI, mI)

    let mkHashMap = do
        let hmS = HM.fromList elemsS :: HM.HashMap String Int
            hmI = HM.fromList elemsI :: HM.HashMap Int Int
        return (keysS, elemsS, hmS, keysI, elemsI, hmI)

    let mkIntMap = do
        let imI = IM.fromList elemsI :: IM.IntMap Int
        return (keysI, elemsI, imI)

    defaultMain [
          env mkConcMap $ \ ~(keysS, elemsS, cmS, keysI, elemsI, cmI) ->
          bgroup "Control.Concurrent.Map"
            [ bgroup "lookup"
                [ bench "String" $ whnfIO $ lookupCM keysS cmS
                , bench "Int" $ whnfIO $ lookupCM keysI $ cmI
                ]
            , bgroup "insert"
                [ bench "String" $ whnfIO $ insertCM elemsS =<< CM.empty
                , bench "Int" $ whnfIO $ insertCM elemsI =<< CM.empty
                ]
            , bgroup "delete"
                [ bench "String" $ whnfIO $ deleteCM keysS cmS
                , bench "Int" $ whnfIO $ deleteCM keysI cmI
                ]
            ]

        , env mkMap $ \ ~(keysS, elemsS, mS, keysI, elemsI, mI) ->
          bgroup "Data.Map"
            [ bgroup "lookup"
                [ bench "String" $ whnf (lookupM keysS) mS
                , bench "Int" $ whnf (lookupM keysI) mI
                ]
            , bgroup "insert"
                [ bench "String" $ whnf (insertM elemsS) M.empty
                , bench "Int" $ whnf (insertM elemsI) M.empty
                ]
            , bgroup "delete"
                [ bench "String" $ whnf (deleteM keysS) mS
                , bench "Int" $ whnf (deleteM keysI) mI
                ]
            ]

        , env mkHashMap $ \ ~(keysS, elemsS, hmS, keysI, elemsI, hmI) ->
          bgroup "Data.HashMap"
            [ bgroup "lookup"
                [ bench "String" $ whnf (lookupHM keysS) hmS
                , bench "Int" $ whnf (lookupHM keysI) hmI
                ]
            , bgroup "insert"
                [ bench "String" $ whnf (insertHM elemsS) HM.empty
                , bench "Int" $ whnf (insertHM elemsI) HM.empty
                ]
            , bgroup "delete"
                [ bench "String" $ whnf (deleteHM keysS) hmS
                , bench "Int" $ whnf (deleteHM keysI) hmI
                ]
            ]

        , env mkIntMap $ \ ~(keysI, elemsI, imI) ->
          bgroup "Data.IntMap"
            [ bgroup "lookup"
                [ bench "Int" $ whnf (lookupIM keysI) imI ]
            , bgroup "insert"
                [ bench "Int" $ whnf (insertIM elemsI) IM.empty ]
            , bgroup "delete"
                [ bench "Int" $ whnf (deleteIM keysI) imI ]
            ]
        ]



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

-----------------------------------------------------------------------
-- Control.Concurrent.Map

lookupCM :: (Eq k, Hashable k) => [k] -> CM.Map k Int -> IO Int
lookupCM xs m = foldlM (\z k -> fromMaybe z <$> (CM.lookup k m)) 0 xs
{-# SPECIALIZE lookupCM :: [String] -> CM.Map String Int -> IO Int #-}
{-# SPECIALIZE lookupCM :: [Int] -> CM.Map Int Int -> IO Int #-}

insertCM :: (Eq k, Hashable k) => [(k, Int)] -> CM.Map k Int -> IO ()
insertCM xs m = mapM_ (\(k,v) -> CM.insert k v m) xs
{-# SPECIALIZE insertCM :: [(Int, Int)] -> CM.Map Int Int -> IO () #-}
{-# SPECIALIZE insertCM :: [(String, Int)] -> CM.Map String Int -> IO () #-}

deleteCM :: (Eq k, Hashable k) => [k] -> CM.Map k Int -> IO ()
deleteCM xs m = mapM_ (\k -> CM.delete k m) xs
{-# SPECIALIZE deleteCM :: [Int] -> CM.Map Int Int -> IO () #-}
{-# SPECIALIZE deleteCM :: [String] -> CM.Map String Int -> IO () #-}

-----------------------------------------------------------------------
-- Data.Map

lookupM :: Ord k => [k] -> M.Map k Int -> Int
lookupM xs m = foldl' (\z k -> fromMaybe z (M.lookup k m)) 0 xs
{-# SPECIALIZE lookupM :: [String] -> M.Map String Int -> Int #-}
{-# SPECIALIZE lookupM :: [Int] -> M.Map Int Int -> Int #-}

insertM :: Ord k => [(k, Int)] -> M.Map k Int -> M.Map k Int
insertM xs m0 = foldl' (\m (k, v) -> M.insert k v m) m0 xs
{-# SPECIALIZE insertM :: [(String, Int)] -> M.Map String Int -> M.Map String Int #-}
{-# SPECIALIZE insertM :: [(Int, Int)] -> M.Map Int Int -> M.Map Int Int #-}

deleteM :: Ord k => [k] -> M.Map k Int -> M.Map k Int
deleteM xs m0 = foldl' (\m k -> M.delete k m) m0 xs
{-# SPECIALIZE deleteM :: [String] -> M.Map String Int -> M.Map String Int #-}
{-# SPECIALIZE deleteM :: [Int] -> M.Map Int Int -> M.Map Int Int #-}

-----------------------------------------------------------------------
-- Data.HashMap

lookupHM :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> Int
lookupHM xs m = foldl' (\z k -> fromMaybe z (HM.lookup k m)) 0 xs
{-# SPECIALIZE lookupHM :: [String] -> HM.HashMap String Int -> Int #-}
{-# SPECIALIZE lookupHM :: [Int] -> HM.HashMap Int Int -> Int #-}

insertHM :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int -> HM.HashMap k Int
insertHM xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
{-# SPECIALIZE insertHM :: [(Int, Int)] -> HM.HashMap Int Int -> HM.HashMap Int Int #-}
{-# SPECIALIZE insertHM :: [(String, Int)] -> HM.HashMap String Int -> HM.HashMap String Int #-}

deleteHM :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> HM.HashMap k Int
deleteHM xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
{-# SPECIALIZE deleteHM :: [Int] -> HM.HashMap Int Int -> HM.HashMap Int Int #-}
{-# SPECIALIZE deleteHM :: [String] -> HM.HashMap String Int -> HM.HashMap String Int #-}


-----------------------------------------------------------------------
-- Data.IntMap

lookupIM :: [Int] -> IM.IntMap Int -> Int
lookupIM xs m = foldl' (\z k -> fromMaybe z (IM.lookup k m)) 0 xs

insertIM :: [(Int, Int)] -> IM.IntMap Int -> IM.IntMap Int
insertIM xs m0 = foldl' (\m (k, v) -> IM.insert k v m) m0 xs

deleteIM :: [Int] -> IM.IntMap Int -> IM.IntMap Int
deleteIM xs m0 = foldl' (\m k -> IM.delete k m) m0 xs