on master help sign in
Revert to using a separate GroupConsume state
dd8bd7dHarendra Kumar
design/optimization-guidelines.md+4
@@ -101,6 +101,10 @@ Step function of a stream or unfold:
101 it is called. More states means more jumps and may affect code locality, and
101 it is called. More states means more jumps and may affect code locality, and
102 efficiency of low level code (e.g. register allocation) because of
102 efficiency of low level code (e.g. register allocation) because of
103 independent placement of the code blocks in different states.
103 independent placement of the code blocks in different states.
104+
105+ In some cases we may have to go against the above guideline and introduce a
106+ separate state even though it is not necessary. See the GroupConsume state in
107+ foldMany for an example.
104* Keep minimum possible data in state. More variables in state may lead
108* Keep minimum possible data in state. More variables in state may lead
105 to poor performance because the state may not fit into registers and the
109 to poor performance because the state may not fit into registers and the
106 spill may cause allocations on each iteration of the loop. Mutable state
110 spill may cause allocations on each iteration of the loop. Mutable state
src/Streamly/Internal/Data/Stream/StreamD/Type.hs+19−19
@@ -588,6 +588,7 @@ take n (Stream step state) = n `seq` Stream step' (state, 0)
588{-# ANN type GroupState Fuse #-}
588{-# ANN type GroupState Fuse #-}
589data GroupState s fs b a
589data GroupState s fs b a
590 = GroupStart s
590 = GroupStart s
591+ | GroupConsume s fs a
591 | GroupBuffer s fs
592 | GroupBuffer s fs
592 | GroupYield b (GroupState s fs b a)
593 | GroupYield b (GroupState s fs b a)
593 | GroupFinish
594 | GroupFinish
@@ -604,16 +605,17 @@ foldMany (Fold fstep initial extract) (Stream step state) =
604 -- fs = fold state
605 -- fs = fold state
605 fs <- initial
606 fs <- initial
606 return $ Skip (GroupBuffer st fs)
607 return $ Skip (GroupBuffer st fs)
608+ -- This state is not strictly required but it helps the compiler fuse the
609+ -- code.
610+ step' _ (GroupConsume st fs x) = do
611+ fs' <- fstep fs x
612+ case fs' of
613+ FL.Done b -> return $ Skip (GroupYield b (GroupStart st))
614+ FL.Partial ps -> return $ Skip (GroupBuffer st ps)
607 step' gst (GroupBuffer st fs) = do
615 step' gst (GroupBuffer st fs) = do
608 r <- step (adaptState gst) st
616 r <- step (adaptState gst) st
609 case r of
617 case r of
610− Yield x s -> do
618+ Yield x s -> return $ Skip $ GroupConsume s fs x
611− res <- fstep fs x
612− return
613− $ Skip
614− $ case res of
615− FL.Done b -> GroupYield b (GroupStart s)
616− FL.Partial ps -> GroupBuffer s ps
617 Skip s -> return $ Skip (GroupBuffer s fs)
619 Skip s -> return $ Skip (GroupBuffer s fs)
618 Stop -> do
620 Stop -> do
619 b <- extract fs
621 b <- extract fs
@@ -628,26 +630,24 @@ foldMany1 (Fold fstep initial extract) (Stream step state) =
628
630
629 where
631 where
630
632
631− {-# INLINE consume #-}
632− consume x s fs = do
633− res <- fstep fs x
634− return
635− $ Skip
636− $ case res of
637− FL.Done b -> GroupYield b (GroupStart s)
638− FL.Partial ps -> GroupBuffer s ps
639−
640 {-# INLINE_LATE step' #-}
633 {-# INLINE_LATE step' #-}
641 step' gst (GroupStart st) = do
634 step' gst (GroupStart st) = do
642 r <- step (adaptState gst) st
635 r <- step (adaptState gst) st
643 case r of
636 case r of
644− Yield x s -> initial >>= consume x s
637+ Yield x s -> do
638+ fi <- initial
639+ return $ Skip $ GroupConsume s fi x
645 Skip s -> return $ Skip (GroupStart s)
640 Skip s -> return $ Skip (GroupStart s)
646− Stop -> return Stop
641+ Stop -> return $ Stop
642+ step' _ (GroupConsume st fs x) = do
643+ fs' <- fstep fs x
644+ case fs' of
645+ FL.Done b -> return $ Skip (GroupYield b (GroupStart st))
646+ FL.Partial ps -> return $ Skip (GroupBuffer st ps)
647 step' gst (GroupBuffer st fs) = do
647 step' gst (GroupBuffer st fs) = do
648 r <- step (adaptState gst) st
648 r <- step (adaptState gst) st
649 case r of
649 case r of
650− Yield x s -> consume x s fs
650+ Yield x s -> return $ Skip $ GroupConsume s fs x
651 Skip s -> return $ Skip (GroupBuffer s fs)
651 Skip s -> return $ Skip (GroupBuffer s fs)
652 Stop -> do
652 Stop -> do
653 b <- extract fs
653 b <- extract fs