Skip to content

Commit 85ee3ba

Browse files
authored
Rewrite internals for performance improvements (#66)
* Rewrite internals for performance improvements Rewrites internals to use a height-balanced AVL tree (same as containers in Haskell) with an eye for performance. Most operations are 2-3x faster than the previous implementations, but specifically this targets set operations which were previously sub-optimal. * Update test command * Expose gc for bench * Share benchmark init for faster startup * Rearrange eq checks * Fix eq test * Update CHANGELOG
1 parent f149d50 commit 85ee3ba

File tree

7 files changed

+1457
-522
lines changed

7 files changed

+1457
-522
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Bugfixes:
1212

1313
Other improvements:
1414
- Speed up `difference` by using 1 fold instead of 2 (#64 by @JordanMartinez)
15+
- Rewrite internals for performance improvements (#66 by @natefaubion)
1516

1617
## [v3.0.0](https://github.com/purescript/purescript-ordered-collections/releases/tag/v3.0.0) - 2022-04-27
1718

bench/Bench/Data/Map.purs

Lines changed: 70 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Prelude
44

55
import Data.List as L
66
import Data.Map as M
7-
import Bench.Data.Map2a0bff as Map2a0bff
7+
import Bench.Data.Mapf149d5 as Mapf149d5
88
import Data.Foldable as F
99
import Data.FoldableWithIndex as FI
1010
import Data.Tuple (Tuple(..))
@@ -20,6 +20,12 @@ benchMap = do
2020

2121
log ""
2222

23+
log "eq"
24+
log "------------"
25+
benchEq
26+
27+
log ""
28+
2329
log "fromFoldable"
2430
log "------------"
2531
benchFromFoldable
@@ -48,126 +54,104 @@ benchMap = do
4854
log "---------------"
4955
benchKeys
5056

57+
log ""
58+
5159
log "difference"
5260
log "---------------"
5361
benchDifference
5462

5563
where
64+
nats = L.range 0 999999
65+
nats2 = L.range 999999 1999999
66+
natPairs = (flip Tuple) unit <$> nats
67+
natPairs2 = (flip Tuple) unit <$> nats2
68+
bigMap = Mapf149d5.fromFoldable $ natPairs
69+
bigMap2 = Mapf149d5.fromFoldable $ natPairs2
70+
bigMap' = M.fromFoldable $ natPairs
71+
bigMap2' = M.fromFoldable $ natPairs2
72+
singletonMap = M.singleton 0 unit
73+
smallMap = Mapf149d5.fromFoldable $ L.take 100 natPairs
74+
smallMap' = M.fromFoldable $ L.take 100 natPairs
75+
midMap = Mapf149d5.fromFoldable $ L.take 10000 natPairs
76+
midMap' = M.fromFoldable $ L.take 10000 natPairs
77+
size = Mapf149d5.size bigMap
78+
size' = M.size bigMap'
5679

5780
benchUnion = do
58-
let nats = L.range 0 999999
59-
nats2 = L.range 999999 1999999
60-
natPairs = (flip Tuple) unit <$> nats
61-
natPairs2 = (flip Tuple) unit <$> nats2
62-
bigMap = Map2a0bff.fromFoldable $ natPairs
63-
bigMap2 = Map2a0bff.fromFoldable $ natPairs2
64-
bigMap' = M.fromFoldable $ natPairs
65-
bigMap2' = M.fromFoldable $ natPairs2
66-
size = Map2a0bff.size bigMap
67-
size' = M.size bigMap'
68-
69-
log $ "Map2a0bff.union: big map (" <> show size <> ")"
70-
benchWith 10 \_ -> Map2a0bff.union bigMap bigMap2
81+
log $ "Mapf149d5.union: big map (" <> show size <> ")"
82+
benchWith 10 \_ -> Mapf149d5.union bigMap bigMap2
7183

7284
log $ "M.union: big map (" <> show size' <> ")"
7385
benchWith 10 \_ -> M.union bigMap' bigMap2'
7486

7587
benchValues = do
76-
let nats = L.range 0 999999
77-
natPairs = (flip Tuple) unit <$> nats
78-
bigMap = Map2a0bff.fromFoldable $ natPairs
79-
bigMap' = M.fromFoldable $ natPairs
80-
size = Map2a0bff.size bigMap
81-
size' = M.size bigMap'
82-
83-
log $ "Map2a0bff.values: big map (" <> show size <> ")"
84-
benchWith 10 \_ -> Map2a0bff.values bigMap
88+
log $ "Mapf149d5.values: big map (" <> show size <> ")"
89+
benchWith 10 \_ -> Mapf149d5.values bigMap
8590

8691
log $ "M.values: big map (" <> show size' <> ")"
8792
benchWith 10 \_ -> M.values bigMap'
8893

8994
benchKeys = do
90-
let nats = L.range 0 999999
91-
natPairs = (flip Tuple) unit <$> nats
92-
bigMap = Map2a0bff.fromFoldable $ natPairs
93-
bigMap' = M.fromFoldable $ natPairs
94-
size = Map2a0bff.size bigMap
95-
size' = M.size bigMap'
96-
97-
log $ "Map2a0bff.keys: big map (" <> show size <> ")"
98-
benchWith 10 \_ -> Map2a0bff.keys bigMap
95+
log $ "Mapf149d5.keys: big map (" <> show size <> ")"
96+
benchWith 10 \_ -> Mapf149d5.keys bigMap
9997

10098
log $ "M.keys: big map (" <> show size' <> ")"
10199
benchWith 10 \_ -> M.keys bigMap'
102100

103101
benchSize = do
104-
let nats = L.range 0 999999
105-
natPairs = (flip Tuple) unit <$> nats
106-
singletonMap = M.singleton 0 unit
107-
smallMap = M.fromFoldable $ L.take 100 natPairs
108-
midMap = M.fromFoldable $ L.take 10000 natPairs
109-
bigMap = M.fromFoldable $ natPairs
110-
111102
log "size: singleton map"
112103
bench \_ -> M.size singletonMap
113104

114-
log $ "size: small map (" <> show (M.size smallMap) <> ")"
115-
bench \_ -> M.size smallMap
105+
log $ "size: small map (" <> show (M.size smallMap') <> ")"
106+
bench \_ -> M.size smallMap'
116107

117-
log $ "size: midsize map (" <> show (M.size midMap) <> ")"
118-
benchWith 100 \_ -> M.size midMap
108+
log $ "size: midsize map (" <> show (M.size midMap') <> ")"
109+
benchWith 100 \_ -> M.size midMap'
119110

120-
log $ "size: big map (" <> show (M.size bigMap) <> ")"
121-
benchWith 10 \_ -> M.size bigMap
111+
log $ "size: big map (" <> show (M.size bigMap') <> ")"
112+
benchWith 10 \_ -> M.size bigMap'
122113

123114
benchFoldable = do
124-
let nats = L.range 0 999999
125-
natPairs = (flip Tuple) unit <$> nats
126-
bigMap = Map2a0bff.fromFoldable $ natPairs
127-
bigMap' = M.fromFoldable $ natPairs
128-
size = Map2a0bff.size bigMap
129-
size' = M.size bigMap'
130-
131-
log $ "Map2a0bff.foldr big map (" <> show size <> ")"
115+
log $ "Mapf149d5.foldr big map (" <> show size <> ")"
132116
benchWith 10 \_ -> F.foldr (\_ _ -> unit) unit bigMap
133117

134118
log $ "M.foldr big map (" <> show size' <> ")"
135119
benchWith 10 \_ -> F.foldr (\_ _ -> unit) unit bigMap'
136120

137-
log $ "Map2a0bff.foldl big map (" <> show size <> ")"
121+
log $ "Mapf149d5.foldl big map (" <> show size <> ")"
138122
benchWith 10 \_ -> F.foldl (\_ _ -> unit) unit bigMap
139123

140124
log $ "M.foldl big map (" <> show size' <> ")"
141125
benchWith 10 \_ -> F.foldl (\_ _ -> unit) unit bigMap'
142126

143-
log $ "Map2a0bff.foldMap big map (" <> show size <> ")"
127+
log $ "Mapf149d5.foldMap big map (" <> show size <> ")"
144128
benchWith 10 \_ -> F.foldMap (\_ -> unit) bigMap
145129

146130
log $ "M.foldMap big map (" <> show size' <> ")"
147131
benchWith 10 \_ -> F.foldMap (\_ -> unit) bigMap'
148132

149-
log $ "Map2a0bff.foldrWithIndex big map (" <> show size <> ")"
133+
log $ "Mapf149d5.foldrWithIndex big map (" <> show size <> ")"
150134
benchWith 10 \_ -> FI.foldrWithIndex (\_ _ _ -> unit) unit bigMap
151135

152136
log $ "M.foldrWithIndex big map (" <> show size' <> ")"
153137
benchWith 10 \_ -> FI.foldrWithIndex (\_ _ _ -> unit) unit bigMap'
154138

155-
log $ "Map2a0bff.foldlWithIndex big map (" <> show size <> ")"
139+
log $ "Mapf149d5.foldlWithIndex big map (" <> show size <> ")"
156140
benchWith 10 \_ -> FI.foldlWithIndex (\_ _ _ -> unit) unit bigMap
157141

158142
log $ "M.foldlWithIndex big map (" <> show size' <> ")"
159143
benchWith 10 \_ -> FI.foldlWithIndex (\_ _ _ -> unit) unit bigMap'
160144

161-
log $ "Map2a0bff.foldMapWithIndex big map (" <> show size <> ")"
145+
log $ "Mapf149d5.foldMapWithIndex big map (" <> show size <> ")"
162146
benchWith 10 \_ -> FI.foldMapWithIndex (\_ _ -> unit) bigMap
163147

164148
log $ "M.foldMapWithIndex big map (" <> show size' <> ")"
165149
benchWith 10 \_ -> FI.foldMapWithIndex (\_ _ -> unit) bigMap'
166150

167151
benchFromFoldable = do
168-
let natStrs = show <$> L.range 0 99999
169-
natPairs = (flip Tuple) unit <$> natStrs
170-
shortPairList = L.take 10000 natPairs
152+
let natStrs = show <$> nats
153+
natStrsPairs = (flip Tuple) unit <$> natStrs
154+
shortPairList = L.take 10000 natStrsPairs
171155

172156
log $ "fromFoldable (" <> show (L.length shortPairList) <> ")"
173157
benchWith 100 \_ -> M.fromFoldable shortPairList
@@ -176,30 +160,39 @@ benchMap = do
176160
benchWith 10 \_ -> M.fromFoldable natPairs
177161

178162
benchDifference = do
179-
let nats = L.range 0 999999
180-
natPairs = (flip Tuple) unit <$> nats
181-
singletonMap = M.singleton 0 unit
182-
smallMap = Map2a0bff.fromFoldable $ L.take 100 natPairs
183-
smallMap' = M.fromFoldable $ L.take 100 natPairs
184-
midMap = Map2a0bff.fromFoldable $ L.take 10000 natPairs
185-
midMap' = M.fromFoldable $ L.take 10000 natPairs
186-
bigMap = Map2a0bff.fromFoldable $ natPairs
187-
bigMap' = M.fromFoldable $ natPairs
188-
189-
log $ "Map2a0bff.difference: small map (" <> show (Map2a0bff.size smallMap) <> ")"
190-
bench \_ -> Map2a0bff.difference smallMap midMap
163+
log $ "Mapf149d5.difference: small map (" <> show (Mapf149d5.size smallMap) <> ")"
164+
bench \_ -> Mapf149d5.difference smallMap midMap
191165

192166
log $ "M.difference: small map (" <> show (M.size smallMap') <> ")"
193167
bench \_ -> M.difference smallMap' midMap'
194168

195-
log $ "Map2a0bff.difference: midsize map (" <> show (Map2a0bff.size midMap) <> ")"
196-
benchWith 100 \_ -> Map2a0bff.difference midMap midMap
169+
log $ "Mapf149d5.difference: midsize map (" <> show (Mapf149d5.size midMap) <> ")"
170+
benchWith 100 \_ -> Mapf149d5.difference midMap midMap
197171

198172
log $ "M.difference: midsize map (" <> show (M.size midMap') <> ")"
199173
benchWith 100 \_ -> M.difference midMap' midMap'
200174

201-
log $ "Map2a0bff.difference: big map (" <> show (Map2a0bff.size bigMap) <> ")"
202-
benchWith 10 \_ -> Map2a0bff.difference bigMap midMap
175+
log $ "Mapf149d5.difference: big map (" <> show (Mapf149d5.size bigMap) <> ")"
176+
benchWith 10 \_ -> Mapf149d5.difference bigMap midMap
203177

204178
log $ "M.difference: big map (" <> show (M.size bigMap') <> ")"
205179
benchWith 10 \_ -> M.difference bigMap' midMap'
180+
181+
benchEq = do
182+
log $ "Mapf149d5.eq: small map (" <> show (Mapf149d5.size smallMap) <> ")"
183+
bench \_ -> smallMap == smallMap
184+
185+
log $ "M.eq: small map (" <> show (M.size smallMap') <> ")"
186+
bench \_ -> smallMap' == smallMap'
187+
188+
log $ "Mapf149d5.eq: midsize map (" <> show (Mapf149d5.size midMap) <> ")"
189+
benchWith 100 \_ -> midMap == midMap
190+
191+
log $ "M.eq: midsize map (" <> show (M.size midMap') <> ")"
192+
benchWith 100 \_ -> midMap' == midMap'
193+
194+
log $ "Mapf149d5.eq: big map (" <> show (Mapf149d5.size bigMap) <> ")"
195+
benchWith 10 \_ -> bigMap == bigMap
196+
197+
log $ "M.eq: big map (" <> show (M.size bigMap') <> ")"
198+
benchWith 10 \_ -> bigMap' == bigMap'

0 commit comments

Comments
 (0)