Repository navigation
dropWhile is slow #141
Description
Activity
This was commented a bit in #108.
- added a commit that references this issue
on Dec 22, 2016 So, I feel like this is an example of a broader problem.
In your example, you will have a big vector materialized in memory. Streaming this to drop some elements and then making a new vector is a lot of work compared to changing the offset/length and reusing the underlying array.
However, another use case of vector is stream fusion, and if stream fusion is happening, this new implementation (in pull request #146) actually breaks it up in sub-optimal ways. And it's kind of accidental that
dropdoes not do streaming, too.However, I think that maybe the generalized stream fusion can do something better than it is doing right now.
dropWhileMin the bundle fusion is just forcing the full stream. However, I think it could actually be a bundle modification that modifies the three things in the bundle differently, and puts off the decision of whether to stream or reuse the vector to other things in the fusion pipeline. This would hopefully give the best answer for both use cases.I think this was the point of the generalized fusion, so I don't really understand why it wasn't used here, or in lots of other places (
takeWhilewould be similarly bad in an example like yours, I think). I'll see if I can make the generalized fusion implement something that runs well for your example, but is also good (or, better, at least) for streaming before merging #146.Yeah, sharing vs slicing is a tricky trade off !
I see. So ideally we would have
dropWhile fuse sharing anddropWhile f . map g(or similar) use stream fusion.Thanks for the insight by the way. Up to this point I did not understand what Bundle does -- apparently it is for exactly this purpose of choosing whether to stream or slice?
That's sort of the idea, yes. A simpler example than bundle is that you can use the type:
data CoYo f a = forall e. CY (e -> a) (f e)
to fuse up
fmapcalls on aFunctor fby collecting them into the stored function and only applying the function once onextract :: CoYo f a -> f a. However, this actually does extra work (in the form offmap id) for 0 composed functions. So you can fix this by instead using:data BundleYo f a = forall e. BY (e -> a) (f e) (f a)
Where the extra
f afield stores the originalf aat first (so no additional work is done), and whenfmapis used, we put what we would extract at that point there. Due to laziness, only the final result actually gets used, so we never do (much) more work thanCoYo.The only tricky part I can think of is that the selection of algorithms kind of flows one way in bundles. So, I think
map g . dropWhile pwill use streamingdropWhile(becausemapwill always choose to stream), whereas whatdropWhile p . map gdoes would be determined on how the bundle it produces is consumed, even though streaming is again probably the best option (because you can't do much better when amapis involved). Maybe there's some mechanism that allows a better selection, though. I'm not sure.For this matter, why don't we just have
dropWhilebe like the current implementations ofindex,headortail? That is, we could definedropWhile f = snd . span fwithINLINE_FUSEDand have a ruledropWhile f (new (New.unstream s)) = new (New.unstream (Bundle.dropWhile f s))
I'm soon gonna submit a pull request for this.
- Sounds wonderful!…On Fri, Jun 5, 2020 at 12:05 PM Genki Sato ***@***.***> wrote: For this matter, why don't we just have dropWhile be like current implementation index or head or tail ? That is, we could define dropWhile f = snd . span f with INLINE_FUSED and have a rule dropWhile f (unstream s) = unstream (Bundle.dropWhile f s) I'm soon gonna submit a pull request for this. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#141 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAABBQSXVIWTV2R7BHMW67DRVEJVVANCNFSM4CTQSUWQ> .
I've submitted a pull request for this, finally! #327
- added a commit that references this issue
on Aug 13, 2020 Fixed by #327
- added a commit that references this issue
on Jan 16, 2021
the following example shows
dropWhilebeing roughly 60x slower thanfindIndexfollowed bydrop nwith-O3-- and roughly 560x slower without-O3!https://github.com/charles-cooper/vector-perf