-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can we improve fromDistinctAscList for IntSet and IntMap #654
Comments
@int-e I know you were involved in writing this code many years ago; I wonder if you might be interested in revisiting it. |
The reason this came up: #653 seems to make |
I wouldn't expect a huge speedup... most of the speedup of fromDistinctAscList1 :: [(Key,a)] -> IntMap a
fromDistinctAscList1 [] = Nil
fromDistinctAscList1 ((kx,vx) : zs0) = addAll kx (Tip kx vx) zs0
where
-- invariant for `addAll` and `addMany`: `kx` is a key in the map `tx`.
addAll !kx !tx []
= tx
addAll !kx !tx ((ky,vy) : zs)
| m <- branchMask kx ky
, Inserted ty zs' <- addMany m ky (Tip ky vy) zs
= addAll kx (link ky ty kx tx) zs'
-- addMany adds all elements that have the same prefix as `kx` w.r.t.
-- the branch mask `m` to `tx`.
addMany !m !kx tx []
= Inserted tx []
addMany !m !kx tx zs0@((ky,vy) : zs)
| mask kx m /= mask ky m
= Inserted tx zs0
| Inserted ty zs' <- addMany (branchMask kx ky) ky (Tip ky vy) zs
= addMany m kx (link ky ty kx tx) zs'
data Inserted a = Inserted !(IntMap a) ![(Key,a)] There is some wasted effort here, since most of the time, one can predict which way the For Finally, regarding |
I would imagine that CPU branch prediction could handle the |
You write
That doesn't sound right, since you call |
Would it be worth writing a separate version for the special case where the first element is non-negative? That is a pretty common scenario. |
That was unintended. In fact, any value that agrees with the prefix of the tree |
Hmm, actually the fromDistinctAscList1a :: [(Key,a)] -> IntMap a
fromDistinctAscList1a [] = Nil
fromDistinctAscList1a ((kx,vx) : zs0) = addAll kx (Tip kx vx) zs0
where
-- invariant for `addAll` and `addMany`: `kx` is a key in the map `tx`.
addAll !kx tx []
= tx
addAll !kx tx ((ky,vy) : zs)
| m <- branchMask kx ky
, Inserted ty zs' <- addMany m ky (Tip ky vy) zs
= addAll kx (link ky ty kx tx) zs'
-- addMany adds all elements that have the same prefix as `kx` w.r.t.
-- the branch mask `m` to `tx`.
addMany !m !kx tx []
= Inserted tx []
addMany !m !kx tx zs0@((ky,vy) : zs)
| mask kx m /= mask ky m
= Inserted tx zs0
| m' <- branchMask kx ky
, Inserted ty zs' <- addMany m' ky (Tip ky vy) zs
= addMany m kx (Bin (mask kx m') m' tx ty) zs' However, I don't see a speedup compared to main = do
print $ foldl' (+) 0 $ Prelude.map size $ do
sz <- [2^i | i <- [0..10]]
shift <- [v * 2^i | i <- [0..20], v <- [-1,1]]
mult <- [1..100]
[fromDistinctAscList1 [(shift + mult * i, ()) | i <- [0..sz]]] Btw, it's interesting to ponder when |
I'm working on this. Here are some detailed benchmarks obtained using containers/containers/src/Data/IntMap/Internal.hs Lines 3080 to 3084 in 9231fd7
|
Have you tried with non-contiguous keys at all? |
It would also be good to get larger sizes in the mix. |
As already mentioned in #658, I have more benchmark results here: https://gist.github.com/int-e/36578cb04d0a187252c366b0b45ddcb6. These include sparse lists (the second test parameter is the distance between consecutive keys). Sparse lists make a huge difference for I've tested maps with 1M entries, but |
The control flow of
fromDistinctAscList
forIntSet
andIntMap
is rather ... opaque. It operates using an explicit stack that seems to represent a sort of zipper for the tree being constructed. That stack is, of course, allocated on the heap, which doesn't seem ideal. The fact that the code is just a bit more complicated than I can really understand is unfortunate. My guess is that it's probably possible to shift that explicit stack onto GHC's native reduction stack, which seems likely to make the code less unreadable and more efficient.The text was updated successfully, but these errors were encountered: