Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

285 lines (250 sloc) 10.62 kB
{-# LANGUAGE CPP, GADTs #-}
module Main where
import Control.DeepSeq
import Control.Exception (evaluate)
import Control.Monad.Trans (liftIO)
import Criterion.Config
import Criterion.Main
import Data.Bits ((.&.))
import Data.Hashable (Hashable)
import qualified Data.ByteString as BS
import qualified Data.HashMap.Strict as HM
import qualified Data.IntMap as IM
import qualified Data.Map as M
import Data.List (foldl')
import Data.Maybe (fromMaybe)
import Prelude hiding (lookup)
import qualified Util.ByteString as UBS
import qualified Util.Int as UI
import qualified Util.String as US
instance NFData BS.ByteString
data B where
B :: NFData a => a -> B
instance NFData B where
rnf (B b) = rnf b
main :: IO ()
main = do
let hm = HM.fromList elems :: HM.HashMap String Int
hmbs = HM.fromList elemsBS :: HM.HashMap BS.ByteString Int
hmi = HM.fromList elemsI :: HM.HashMap Int Int
hmi2 = HM.fromList elemsI2 :: HM.HashMap Int Int
m = M.fromList elems :: M.Map String Int
mbs = M.fromList elemsBS :: M.Map BS.ByteString Int
im = IM.fromList elemsI :: IM.IntMap Int
defaultMainWith defaultConfig
(liftIO . evaluate $ rnf [B m, B mbs, B hm, B hmbs, B hmi, B im])
[
-- * Comparison to other data structures
-- ** Map
bgroup "Map"
[ bgroup "lookup"
[ bench "String" $ whnf (lookupM keys) m
, bench "ByteString" $ whnf (lookupM keysBS) mbs
]
, bgroup "lookup-miss"
[ bench "String" $ whnf (lookupM keys') m
, bench "ByteString" $ whnf (lookupM keysBS') mbs
]
, bgroup "insert"
[ bench "String" $ whnf (insertM elems) M.empty
, bench "ByteStringString" $ whnf (insertM elemsBS) M.empty
]
, bgroup "insert-dup"
[ bench "String" $ whnf (insertM elems) m
, bench "ByteStringString" $ whnf (insertM elemsBS) mbs
]
, bgroup "delete"
[ bench "String" $ whnf (deleteM keys) m
, bench "ByteString" $ whnf (deleteM keysBS) mbs
]
, bgroup "delete-miss"
[ bench "String" $ whnf (deleteM keys') m
, bench "ByteString" $ whnf (deleteM keysBS') mbs
]
, bgroup "size"
[ bench "String" $ whnf M.size m
, bench "ByteString" $ whnf M.size mbs
]
, bgroup "fromList"
[ bench "String" $ whnf M.fromList elems
, bench "ByteString" $ whnf M.fromList elemsBS
]
]
-- ** IntMap
, bgroup "IntMap"
[ bench "lookup" $ whnf (lookupIM keysI) im
, bench "lookup-miss" $ whnf (lookupIM keysI') im
, bench "insert" $ whnf (insertIM elemsI) IM.empty
, bench "insert-dup" $ whnf (insertIM elemsI) im
, bench "delete" $ whnf (deleteIM keysI) im
, bench "delete-miss" $ whnf (deleteIM keysI') im
, bench "size" $ whnf IM.size im
, bench "fromList" $ whnf IM.fromList elemsI
]
-- * Basic interface
, bgroup "lookup"
[ bench "String" $ whnf (lookup keys) hm
, bench "ByteString" $ whnf (lookup keysBS) hmbs
, bench "Int" $ whnf (lookup keysI) hmi
]
, bgroup "lookup-miss"
[ bench "String" $ whnf (lookup keys') hm
, bench "ByteString" $ whnf (lookup keysBS') hmbs
, bench "Int" $ whnf (lookup keysI') hmi
]
, bgroup "insert"
[ bench "String" $ whnf (insert elems) HM.empty
, bench "ByteString" $ whnf (insert elemsBS) HM.empty
, bench "Int" $ whnf (insert elemsI) HM.empty
]
, bgroup "insert-dup"
[ bench "String" $ whnf (insert elems) hm
, bench "ByteString" $ whnf (insert elemsBS) hmbs
, bench "Int" $ whnf (insert elemsI) hmi
]
, bgroup "delete"
[ bench "String" $ whnf (delete keys) hm
, bench "ByteString" $ whnf (delete keysBS) hmbs
, bench "Int" $ whnf (delete keysI) hmi
]
, bgroup "delete-miss"
[ bench "String" $ whnf (delete keys') hm
, bench "ByteString" $ whnf (delete keysBS') hmbs
, bench "Int" $ whnf (delete keysI') hmi
]
-- Combine
, bench "union" $ whnf (HM.union hmi) hmi2
-- Transformations
, bench "map" $ whnf (HM.map (\ v -> v + 1)) hmi
-- * Difference and intersection
, bench "difference" $ whnf (HM.difference hmi) hmi2
, bench "intersection" $ whnf (HM.intersection hmi) hmi2
-- Folds
, bench "foldl'" $ whnf (HM.foldl' (+) 0) hmi
, bench "foldr" $ nf (HM.foldr (:) []) hmi
-- Filter
, bench "filter" $ whnf (HM.filter (\ v -> v .&. 1 == 0)) hmi
, bench "filterWithKey" $ whnf (HM.filterWithKey (\ k _ -> k .&. 1 == 0)) hmi
-- Size
, bgroup "size"
[ bench "String" $ whnf HM.size hm
, bench "ByteString" $ whnf HM.size hmbs
, bench "Int" $ whnf HM.size hmi
]
-- fromList
, bgroup "fromList"
[ bgroup name
[ bgroup "long"
[ bench "String" $ whnf fl1 elems
, bench "ByteString" $ whnf fl2 elemsBS
, bench "Int" $ whnf fl3 elemsI
]
, bgroup "short"
[ bench "String" $ whnf fl1 elemsDup
, bench "ByteString" $ whnf fl2 elemsDupBS
, bench "Int" $ whnf fl3 elemsDupI
]
]
| (name,fl1,fl2,fl3)
<- [("Base",HM.fromList,HM.fromList,HM.fromList)
,("insert",fromList_insert,fromList_insert,fromList_insert)]
]
-- fromList
, bgroup "fromListWith"
[ bgroup name
[ bgroup "long"
[ bench "String" $ whnf (fl1 (+)) elems
, bench "ByteString" $ whnf (fl2 (+)) elemsBS
, bench "Int" $ whnf (fl3 (+)) elemsI
]
, bgroup "short"
[ bench "String" $ whnf (fl1 (+)) elemsDup
, bench "ByteString" $ whnf (fl2 (+)) elemsDupBS
, bench "Int" $ whnf (fl3 (+)) elemsDupI
]
]
| (name,fl1,fl2,fl3)
<- [("Base",HM.fromListWith,HM.fromListWith,HM.fromListWith)
,("insert",fromListWith_insert,fromListWith_insert,fromListWith_insert)]
]
]
where
n :: Int
n = 2^(12 :: Int)
elems = zip keys [1..n]
keys = US.rnd 8 n
elemsBS = zip keysBS [1..n]
keysBS = UBS.rnd 8 n
elemsI = zip keysI [1..n]
keysI = UI.rnd (n+n) n
elemsI2 = zip [n `div` 2..n + (n `div` 2)] [1..n] -- for union
keys' = US.rnd' 8 n
keysBS' = UBS.rnd' 8 n
keysI' = UI.rnd' (n+n) n
keysDup = US.rnd 2 n
keysDupBS = UBS.rnd 2 n
keysDupI = UI.rnd (n`div`4) n
elemsDup = zip keysDup [1..n]
elemsDupBS = zip keysDupBS [1..n]
elemsDupI = zip keysDupI [1..n]
------------------------------------------------------------------------
-- * HashMap
lookup :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> Int
lookup xs m = foldl' (\z k -> fromMaybe z (HM.lookup k m)) 0 xs
{-# SPECIALIZE lookup :: [Int] -> HM.HashMap Int Int -> Int #-}
{-# SPECIALIZE lookup :: [String] -> HM.HashMap String Int -> Int #-}
{-# SPECIALIZE lookup :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
-> Int #-}
insert :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int
-> HM.HashMap k Int
insert xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
{-# SPECIALIZE insert :: [(Int, Int)] -> HM.HashMap Int Int
-> HM.HashMap Int Int #-}
{-# SPECIALIZE insert :: [(String, Int)] -> HM.HashMap String Int
-> HM.HashMap String Int #-}
{-# SPECIALIZE insert :: [(BS.ByteString, Int)] -> HM.HashMap BS.ByteString Int
-> HM.HashMap BS.ByteString Int #-}
delete :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> HM.HashMap k Int
delete xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
{-# SPECIALIZE delete :: [Int] -> HM.HashMap Int Int -> HM.HashMap Int Int #-}
{-# SPECIALIZE delete :: [String] -> HM.HashMap String Int
-> HM.HashMap String Int #-}
{-# SPECIALIZE delete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
-> HM.HashMap BS.ByteString Int #-}
------------------------------------------------------------------------
-- * 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 :: [BS.ByteString] -> M.Map BS.ByteString 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 :: [(BS.ByteString, Int)] -> M.Map BS.ByteString Int
-> M.Map BS.ByteString 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 :: [BS.ByteString] -> M.Map BS.ByteString Int
-> M.Map BS.ByteString Int #-}
------------------------------------------------------------------------
-- * 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
------------------------------------------------------------------------
-- * Reference implementations
fromList_insert :: (Eq k, Hashable k) => [(k, v)] -> HM.HashMap k v
fromList_insert = foldl' (\ m (k, v) -> HM.insert k v m) HM.empty
#if __GLASGOW_HASKELL__ >= 700
{-# INLINABLE fromList_insert #-}
#endif
fromListWith_insert :: (Eq k, Hashable k) => (v -> v -> v) -> [(k, v)] -> HM.HashMap k v
fromListWith_insert f = foldl' (\ m (k, v) -> HM.insertWith f k v m) HM.empty
#if __GLASGOW_HASKELL__ >= 700
{-# INLINABLE fromListWith_insert #-}
#endif
Jump to Line
Something went wrong with that request. Please try again.