Skip to content

Commit ae65bf5

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 53385dd commit ae65bf5

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, hash)
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
@@ -273,6 +302,51 @@ main = do
273302
, bench "Int" $ whnf (alterFDelete keysI') hmi
274303
]
275304

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

@@ -337,6 +411,18 @@ lookup xs m = foldl' (\z k -> fromMaybe z (HM.lookup k m)) 0 xs
337411
{-# SPECIALIZE lookup :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
338412
-> Int #-}
339413

414+
lookupC :: (Eq k, Hashable k, Traversable f) => [k] -> f (HM.HashMap k Int) -> f Int
415+
lookupC = fmap . lookup
416+
{-# SPECIALIZE lookupC :: [Int] -> [HM.HashMap Int Int] -> [Int] #-}
417+
{-# SPECIALIZE lookupC :: [Int] -> V.Vector (HM.HashMap Int Int)
418+
-> V.Vector Int #-}
419+
420+
lookupHS :: [Int] -> HS.HashSet (HM.HashMap Int Int) -> HS.HashSet Int
421+
lookupHS = HS.map . lookup
422+
423+
lookupS :: [Int] -> S.Set (HM.HashMap Int Int) -> S.Set Int
424+
lookupS = S.map . lookup
425+
340426
insert :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int
341427
-> HM.HashMap k Int
342428
insert xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
@@ -347,6 +433,21 @@ insert xs m0 = foldl' (\m (k, v) -> HM.insert k v m) m0 xs
347433
{-# SPECIALIZE insert :: [(BS.ByteString, Int)] -> HM.HashMap BS.ByteString Int
348434
-> HM.HashMap BS.ByteString Int #-}
349435

436+
insertC :: (Eq k, Hashable k, Traversable f) => [(k, Int)] -> f (HM.HashMap k Int)
437+
-> f (HM.HashMap k Int)
438+
insertC l = fmap (insert l)
439+
{-# SPECIALIZE insertC :: [(Int, Int)] -> [HM.HashMap Int Int]
440+
-> [HM.HashMap Int Int] #-}
441+
{-# SPECIALIZE insertC :: [(Int, Int)] -> V.Vector (HM.HashMap Int Int)
442+
-> V.Vector (HM.HashMap Int Int) #-}
443+
444+
insertHS :: [(Int, Int)] -> HS.HashSet (HM.HashMap Int Int)
445+
-> HS.HashSet (HM.HashMap Int Int)
446+
insertHS l = HS.map (insert l)
447+
448+
insertS :: [(Int, Int)] -> S.Set (HM.HashMap Int Int) -> S.Set (HM.HashMap Int Int)
449+
insertS l = S.map (insert l)
450+
350451
delete :: (Eq k, Hashable k) => [k] -> HM.HashMap k Int -> HM.HashMap k Int
351452
delete xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
352453
{-# SPECIALIZE delete :: [Int] -> HM.HashMap Int Int -> HM.HashMap Int Int #-}
@@ -355,6 +456,21 @@ delete xs m0 = foldl' (\m k -> HM.delete k m) m0 xs
355456
{-# SPECIALIZE delete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
356457
-> HM.HashMap BS.ByteString Int #-}
357458

459+
deleteC :: (Eq k, Hashable k, Functor f) => [k] -> f (HM.HashMap k Int)
460+
-> f (HM.HashMap k Int)
461+
deleteC = fmap . delete
462+
{-# SPECIALIZE deleteC :: [Int] -> [HM.HashMap Int Int]
463+
-> [HM.HashMap Int Int] #-}
464+
{-# SPECIALIZE deleteC :: [Int] -> V.Vector (HM.HashMap Int Int)
465+
-> V.Vector (HM.HashMap Int Int) #-}
466+
467+
deleteHS :: [Int] -> HS.HashSet (HM.HashMap Int Int)
468+
-> HS.HashSet (HM.HashMap Int Int)
469+
deleteHS = HS.map . delete
470+
471+
deleteS :: [Int] -> S.Set (HM.HashMap Int Int) -> S.Set (HM.HashMap Int Int)
472+
deleteS = S.map . delete
473+
358474
alterInsert :: (Eq k, Hashable k) => [(k, Int)] -> HM.HashMap k Int
359475
-> HM.HashMap k Int
360476
alterInsert xs m0 =
@@ -399,6 +515,52 @@ alterFDelete xs m0 =
399515
{-# SPECIALIZE alterFDelete :: [BS.ByteString] -> HM.HashMap BS.ByteString Int
400516
-> HM.HashMap BS.ByteString Int #-}
401517

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

benchmarks/unordered-containers-benchmarks.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ executable unordered-containers-benchmarks
2424
bytestring,
2525
containers,
2626
gauge,
27+
vector,
2728
deepseq,
2829
deepseq-generics,
2930
hashmap,

0 commit comments

Comments
 (0)