Skip to content

Commit a928518

Browse files
committed
Add benchmarks to hashmap operations inside containers
* because 'HashMap' is now a wrapper and may/may not get unboxed during a program's execution, benchmarks to operations on sets of hashmaps inside different kinds of containers were added;
1 parent e5adbf5 commit a928518

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

benchmarks/Benchmarks.hs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import Data.Hashable (Hashable)
1111
import qualified Data.ByteString as BS
1212
import qualified "hashmap" Data.HashMap as IHM
1313
import qualified Data.HashMap.Strict as HM
14+
import qualified Data.HashSet as HS
1415
import qualified Data.IntMap as IM
1516
import qualified Data.Map as M
17+
import qualified Data.Set as S
18+
import qualified Data.Vector as V
1619
import Data.List (foldl')
1720
import Data.Maybe (fromMaybe)
1821
import GHC.Generics (Generic)
@@ -37,6 +40,8 @@ instance NFData B where
3740
data Env = Env {
3841
n :: !Int,
3942

43+
csz :: !Int, -- container size
44+
4045
elems :: ![(String, Int)],
4146
keys :: ![String],
4247
elemsBS :: ![(BS.ByteString, Int)],
@@ -49,6 +54,11 @@ data Env = Env {
4954
keysBS' :: ![BS.ByteString],
5055
keysI' :: ![Int],
5156

57+
listOfHMs :: ![HM.HashMap Int Int],
58+
vecOfHMs :: !(V.Vector (HM.HashMap Int Int)),
59+
hsetOfHMs :: !(HS.HashSet (HM.HashMap Int Int)),
60+
setOfHMs :: !(S.Set (HM.HashMap Int Int)),
61+
5262
keysDup :: ![String],
5363
keysDupBS :: ![BS.ByteString],
5464
keysDupI :: ![Int],
@@ -73,6 +83,20 @@ setupEnv :: IO Env
7383
setupEnv = do
7484
let n = 2^(12 :: Int)
7585

86+
-- When building a container of hashmaps, 'cn' will be the size of each.
87+
cn = n `div` 16
88+
-- 'csz' is the size of the container of hashmaps.
89+
csz = 2^(7 :: Int)
90+
91+
values = [1..csz*cn]
92+
93+
chop _ [] = []
94+
chop k l =
95+
let (taken, left) = splitAt k l
96+
in taken : chop k left
97+
98+
vals = chop cn values
99+
76100
elems = zip keys [1..n]
77101
keys = US.rnd 8 n
78102
elemsBS = zip keysBS [1..n]
@@ -85,6 +109,11 @@ setupEnv = do
85109
keysBS' = UBS.rnd' 8 n
86110
keysI' = UI.rnd' (n+n) n
87111

112+
listOfHMs = zipWith (\x y -> HM.fromList (zip x y)) (repeat keysI) vals
113+
vecOfHMs = V.fromList listOfHMs
114+
hsetOfHMs = HS.fromList listOfHMs
115+
setOfHMs = S.fromList listOfHMs
116+
88117
keysDup = US.rnd 2 n
89118
keysDupBS = UBS.rnd 2 n
90119
keysDupI = UI.rnd (n`div`4) n
@@ -269,6 +298,51 @@ main = do
269298
, bench "Int" $ whnf (alterFDelete keysI') hmi
270299
]
271300

301+
, bgroup "containerized"
302+
[ bgroup "lookup"
303+
[ bench "List" $ nf (lookupC keysI) listOfHMs
304+
, bench "Vector" $ nf (lookupC keysI) vecOfHMs
305+
, bench "HashSet" $ nf (lookupHS keysI) hsetOfHMs
306+
, bench "Set" $ nf (lookupS keysI) setOfHMs
307+
]
308+
, bgroup "insert"
309+
[ bench "List" $ nf (insertC elemsI) listOfHMs
310+
, bench "Vector" $ nf (insertC elemsI) vecOfHMs
311+
, bench "HashSet" $ nf (insertHS elemsI) hsetOfHMs
312+
, bench "Set" $ nf (insertS elemsI) setOfHMs
313+
]
314+
, bgroup "delete"
315+
[ bench "List" $ nf (deleteC keysI) listOfHMs
316+
, bench "Vector" $ nf (deleteC keysI) vecOfHMs
317+
, bench "HashSet" $ nf (deleteHS keysI) hsetOfHMs
318+
, bench "Set" $ nf (deleteS keysI) setOfHMs
319+
]
320+
, bgroup "union"
321+
[ bench "List" $ whnf unionC listOfHMs
322+
, bench "Vector" $ whnf unionC vecOfHMs
323+
, bench "HashSet" $ whnf unionC hsetOfHMs
324+
, bench "Set" $ whnf unionC setOfHMs
325+
]
326+
, bgroup "map"
327+
[ bench "List" $ nf (mapC (\ v -> v + 1)) listOfHMs
328+
, bench "Vector" $ nf (mapC (\ v -> v + 1)) vecOfHMs
329+
, bench "HashSet" $ nf (mapHS (\ v -> v + 1)) hsetOfHMs
330+
, bench "Set" $ nf (mapS (\ v -> v + 1)) setOfHMs
331+
]
332+
, bgroup "intersection"
333+
[ bench "List" $ whnf intersectionC listOfHMs
334+
, bench "Vector" $ whnf intersectionC vecOfHMs
335+
, bench "HashSet" $ whnf intersectionC hsetOfHMs
336+
, bench "Set" $ whnf intersectionC setOfHMs
337+
]
338+
, bgroup "size"
339+
[ bench "List" $ nf sizeC listOfHMs
340+
, bench "Vector" $ nf sizeC vecOfHMs
341+
, bench "HashSet" $ nf sizeHS hsetOfHMs
342+
, bench "Set" $ nf sizeS setOfHMs
343+
]
344+
]
345+
272346
-- Combine
273347
, bench "union" $ whnf (HM.union hmi) hmi2
274348

@@ -333,6 +407,18 @@ lookup xs m = foldl' (\z k -> fromMaybe z (HM.lookup k m)) 0 xs
333407
{-# SPECIALIZE lookup :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
334408
-> Int #-}
335409

410+
lookupC :: (Eq k, Hashable k, Traversable f) => [k] -> f (HM.HashMap k Int) -> f Int
411+
lookupC = fmap . lookup
412+
{-# SPECIALIZE lookupC :: [Int] -> [HM.HashMap Int Int] -> [Int] #-}
413+
{-# SPECIALIZE lookupC :: [Int] -> V.Vector (HM.HashMap Int Int)
414+
-> V.Vector Int #-}
415+
416+
lookupHS :: [Int] -> HS.HashSet (HM.HashMap Int Int) -> HS.HashSet Int
417+
lookupHS = HS.map . lookup
418+
419+
lookupS :: [Int] -> S.Set (HM.HashMap Int Int) -> S.Set Int
420+
lookupS = S.map . lookup
421+
336422
insert :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int
337423
-> HM.HashMap k Int
338424
insert xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
@@ -343,6 +429,21 @@ insert xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
343429
{-# SPECIALIZE insert :: [(BS.ByteString, Int)] -> HM.HashMap BS.ByteString Int
344430
-> HM.HashMap BS.ByteString Int #-}
345431

432+
insertC :: (Eq k, Hashable k, Traversable f) => [(k, Int)] -> f (HM.HashMap k Int)
433+
-> f (HM.HashMap k Int)
434+
insertC l = fmap (insert l)
435+
{-# SPECIALIZE insertC :: [(Int, Int)] -> [HM.HashMap Int Int]
436+
-> [HM.HashMap Int Int] #-}
437+
{-# SPECIALIZE insertC :: [(Int, Int)] -> V.Vector (HM.HashMap Int Int)
438+
-> V.Vector (HM.HashMap Int Int) #-}
439+
440+
insertHS :: [(Int, Int)] -> HS.HashSet (HM.HashMap Int Int)
441+
-> HS.HashSet (HM.HashMap Int Int)
442+
insertHS l = HS.map (insert l)
443+
444+
insertS :: [(Int, Int)] -> S.Set (HM.HashMap Int Int) -> S.Set (HM.HashMap Int Int)
445+
insertS l = S.map (insert l)
446+
346447
delete :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> HM.HashMap k Int
347448
delete xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
348449
{-# SPECIALIZE delete :: [Int] -> HM.HashMap Int Int -> HM.HashMap Int Int #-}
@@ -351,6 +452,21 @@ delete xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
351452
{-# SPECIALIZE delete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
352453
-> HM.HashMap BS.ByteString Int #-}
353454

455+
deleteC :: (Eq k, Hashable k, Functor f) => [k] -> f (HM.HashMap k Int)
456+
-> f (HM.HashMap k Int)
457+
deleteC = fmap . delete
458+
{-# SPECIALIZE deleteC :: [Int] -> [HM.HashMap Int Int]
459+
-> [HM.HashMap Int Int] #-}
460+
{-# SPECIALIZE deleteC :: [Int] -> V.Vector (HM.HashMap Int Int)
461+
-> V.Vector (HM.HashMap Int Int) #-}
462+
463+
deleteHS :: [Int] -> HS.HashSet (HM.HashMap Int Int)
464+
-> HS.HashSet (HM.HashMap Int Int)
465+
deleteHS = HS.map . delete
466+
467+
deleteS :: [Int] -> S.Set (HM.HashMap Int Int) -> S.Set (HM.HashMap Int Int)
468+
deleteS = S.map . delete
469+
354470
alterInsert :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int
355471
-> HM.HashMap k Int
356472
alterInsert xs m0 =
@@ -395,6 +511,52 @@ alterFDelete xs m0 =
395511
{-# SPECIALIZE alterFDelete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
396512
-> HM.HashMap BS.ByteString Int #-}
397513

514+
unionC :: (Eq k, Hashable k, Foldable f) => f (HM.HashMap k Int)
515+
-> HM.HashMap k Int
516+
unionC = foldl' HM.union mempty
517+
{-# SPECIALIZE unionC :: [HM.HashMap Int Int] -> HM.HashMap Int Int #-}
518+
{-# SPECIALIZE unionC :: V.Vector (HM.HashMap Int Int) -> HM.HashMap Int Int #-}
519+
{-# SPECIALIZE unionC :: HS.HashSet (HM.HashMap Int Int) -> HM.HashMap Int Int #-}
520+
{-# SPECIALIZE unionC :: S.Set (HM.HashMap Int Int) -> HM.HashMap Int Int #-}
521+
522+
mapC :: (Eq k, Hashable k, Functor f) => (Int -> Int) -> f (HM.HashMap k Int)
523+
-> f (HM.HashMap k Int)
524+
mapC f = fmap (HM.map f)
525+
{-# SPECIALIZE mapC :: (Int -> Int) -> [HM.HashMap Int Int]
526+
-> [HM.HashMap Int Int] #-}
527+
{-# SPECIALIZE mapC :: (Int -> Int) -> V.Vector (HM.HashMap Int Int)
528+
-> V.Vector (HM.HashMap Int Int) #-}
529+
530+
mapHS :: (Int -> Int) -> HS.HashSet (HM.HashMap Int Int)
531+
-> HS.HashSet (HM.HashMap Int Int)
532+
mapHS f = HS.map (HM.map f)
533+
534+
mapS :: (Int -> Int) -> S.Set (HM.HashMap Int Int) -> S.Set (HM.HashMap Int Int)
535+
mapS f = S.map (HM.map f)
536+
537+
intersectionC :: (Eq k, Hashable k, Foldable f) => f (HM.HashMap k Int)
538+
-> HM.HashMap k Int
539+
intersectionC = foldl' HM.intersection mempty
540+
{-# SPECIALIZE intersectionC :: [HM.HashMap Int Int]
541+
-> HM.HashMap Int Int #-}
542+
{-# SPECIALIZE intersectionC :: V.Vector (HM.HashMap Int Int)
543+
-> HM.HashMap Int Int #-}
544+
{-# SPECIALIZE intersectionC :: HS.HashSet (HM.HashMap Int Int)
545+
-> HM.HashMap Int Int #-}
546+
{-# SPECIALIZE intersectionC :: S.Set (HM.HashMap Int Int)
547+
-> HM.HashMap Int Int #-}
548+
549+
sizeC :: (Eq k, Hashable k, Functor f) => f (HM.HashMap k Int) -> f Int
550+
sizeC = fmap HM.size
551+
{-# SPECIALIZE sizeC :: [HM.HashMap Int Int] -> [Int] #-}
552+
{-# SPECIALIZE sizeC :: V.Vector (HM.HashMap Int Int) -> V.Vector Int #-}
553+
554+
sizeHS :: HS.HashSet (HM.HashMap Int Int) -> HS.HashSet Int
555+
sizeHS = HS.map HM.size
556+
557+
sizeS :: S.Set (HM.HashMap Int Int) -> S.Set Int
558+
sizeS = S.map HM.size
559+
398560
------------------------------------------------------------------------
399561
-- * Map
400562

benchmarks/unordered-containers-benchmarks.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ executable unordered-containers-benchmarks
2323
base,
2424
bytestring,
2525
containers,
26+
vector,
2627
criterion,
2728
deepseq,
2829
deepseq-generics,

0 commit comments

Comments
 (0)