diff --git a/Benchmarks.hs b/Benchmarks.hs
deleted file mode 100644
--- a/Benchmarks.hs
+++ /dev/null
@@ -1,134 +0,0 @@
--- |
--- Module      : Main
--- Copyright   : (c) 2018 Harendra Kumar
---
--- License     : MIT
--- Maintainer  : harendra.kumar@gmail.com
-
-{-# LANGUAGE TemplateHaskell #-}
-
-module Main (main) where
-
-import Data.List ((\\))
-import Gauge
-
-import Benchmarks.BenchmarkTH
-
-import qualified Benchmarks.VectorStreams as VectorStreams
-import qualified Benchmarks.Streamly as Streamly
-import qualified Benchmarks.StreamlyPure as StreamlyPure
-import qualified Benchmarks.Streaming as Streaming
-import qualified Benchmarks.Machines as Machines
-import qualified Benchmarks.Pipes as Pipes
-import qualified Benchmarks.Conduit as Conduit
-import qualified Benchmarks.Drinkery as Drinkery
-import qualified Benchmarks.List as List
-import qualified Benchmarks.ByteString as ByteString
-import qualified Benchmarks.ByteStringLazy as ByteStringLazy
-import qualified Benchmarks.Text as Text
-import qualified Benchmarks.DList as DList
-import qualified Benchmarks.Sequence as Sequence
-import qualified Benchmarks.Vector as Vector
-import qualified Benchmarks.StreamlyArray as StreamlyArray
--- import qualified Benchmarks.LogicT as LogicT
--- import qualified Benchmarks.ListT as ListT
--- import qualified Benchmarks.ListTransformer as ListTransformer
-
-main :: IO ()
-main = do
-  defaultMain
-    [ bgroup "elimination"
-      [ $(createBgroupSink (benchMods ++ ["DList"]) "drain" "toNull")
-      , $(createBgroupSink ((benchMods \\ ["List"]) ++ ["DList"]) "toList" "toList")
-      , $(createBgroupSink (benchMods ++ ["DList"]) "foldl'" "foldl")
-      , $(createBgroupSink benchMods "last" "last")
-      , $(createBgroupSrc (["Streamly", "List", "VectorStreams"])
-            "enumInt" "sourceIntFromThenTo")
-      ]
-    , bgroup "transformation"
-      [ $(createBgroupSinkN (benchMods \\ ["Sequence"]) "scan" "scan" 1)
-      , $(createBgroupSinkN (benchMods ++ ["DList"]) "map" "map" 1)
-      , $(createBgroupSinkN benchMods "mapM" "mapM" 1)
-      ]
-    , bgroup "transformationX4"
-      [ $(createBgroupSinkN (benchMods \\ ["Sequence"]) "scan x 4" "scan" 4)
-      , $(createBgroupSinkN (benchMods ++ ["DList"]) "map x 4" "map" 4)
-      , $(createBgroupSinkN benchMods "mapM x 4" "mapM" 4)
-      ]
-    , bgroup "filtering"
-      [ $(createBgroupSinkN benchMods "filter-all-out" "filterAllOut" 1)
-      , $(createBgroupSinkN benchMods "filter-all-in" "filterAllIn" 1)
-      , $(createBgroupSinkN benchMods "drop-all" "dropAll" 1)
-      , $(createBgroupSinkN benchMods "takeWhile-true" "takeWhileTrue" 1)
-      , $(createBgroupSinkN benchMods "filter-even" "filterEven" 1)
-      , $(createBgroupSinkN benchMods "take-all" "takeAll" 1)
-      , $(createBgroupSinkN benchMods "drop-one" "dropOne" 1)
-      , $(createBgroupSinkN benchMods "dropWhile-true" "dropWhileTrue" 1)
-      , $(createBgroupSinkN benchMods "dropWhile-false" "dropWhileFalse" 1)
-      ]
-      -- drop-all/dropWhile-true/filter-all-out x 4 would be the same as
-      -- drop-all/dropWhile-true/filter-all-out x 1 as they would already
-      -- drop all elements and do nothing in the next iterations
-    , bgroup "filteringX4"
-      [ $(createBgroupSinkN benchMods "filter-even x 4" "filterEven" 4)
-      -- , $(createBgroupSinkN benchMods "filter-all-out x 4" "filterAllOut" 4)
-      , $(createBgroupSinkN benchMods "filter-all-in x 4" "filterAllIn" 4)
-      , $(createBgroupSinkN benchMods "take-all x 4" "takeAll" 4)
-      , $(createBgroupSinkN benchMods "takeWhile-true x 4" "takeWhileTrue" 4)
-      , $(createBgroupSinkN benchMods "drop-one x 4" "dropOne" 4)
-      -- , $(createBgroupSinkN benchMods "drop-all x 4" "dropAll" 4)
-      -- , $(createBgroupSinkN benchMods "dropWhile-true x 4" "dropWhileTrue" 4)
-      , $(createBgroupSinkN benchMods "dropWhile-false x 4" "dropWhileFalse" 4)
-      ]
-    , bgroup "mixedX4"
-      [ $(createBgroupSinkN (benchMods \\ ["Sequence"]) "scan-map x 4" "scanMap" 4)
-      , $(createBgroupSinkN (benchMods \\ ["Sequence"]) "drop-scan x 4" "dropScan" 4)
-      , $(createBgroupSinkN (benchMods \\ ["Sequence"]) "take-scan x 4" "takeScan" 4)
-      , $(createBgroupSinkN (benchMods \\ ["Sequence"]) "filter-scan x 4" "filterScan" 4)
-      , $(createBgroupSinkN benchMods "drop-map x 4" "dropMap" 4)
-      , $(createBgroupSinkN benchMods "take-drop x 4" "takeDrop" 4)
-      , $(createBgroupSinkN benchMods "take-map x 4" "takeMap" 4)
-      , $(createBgroupSinkN benchMods "filter-drop x 4" "filterDrop" 4)
-      , $(createBgroupSinkN benchMods "filter-take x 4" "filterTake" 4)
-      , $(createBgroupSinkN benchMods "filter-map x 4" "filterMap" 4)
-      ]
-    , $(createBgroupSink (benchMods \\ ["StreamlyArray", "StreamlyPure"]) "zip" "zip")
-    -- XXX use 4x250k concatMap for a comparative idea of cost wrt other ops
-    , $(createBgroupSink (
-        [ "List"
-        , "Streamly"
-        , "StreamlyPure"
-        , "Vector"
-        , "VectorStreams"
-        , "ByteString"
-        , "ByteStringLazy"
-        , "Text"
-        ]) "concatMap" "concatMap")
-    , $(createBgroupSink (benchMods \\
-            [ "List"
-            , "Streamly"
-            , "StreamlyPure"
-            , "Vector"
-            , "VectorStreams"
-            , "ByteString"
-            , "ByteStringLazy"
-            , "Sequence"
-            , "StreamlyArray"
-            , "Text"
-            ]) "concatMapFoldable" "concatMapFoldable")
-
-    , $(createBgroupSrc ((benchMods ++ ["DList"]) \\
-            ["Drinkery", "StreamlyArray"]) "appendR[10000]" "appendSourceR")
-    , $(createBgroupSrc ["DList", "Conduit"] "appendL[10000]" "appendSourceL")
-
-      -- Perform 100,000 mapM recursively over a stream of length 10
-    , bgroup "iterated"
-      [ $(createBgroupSrc (iterMods \\ pureMods) "mapM (iter)" "iterateMapM")
-      , $(createBgroupSrc (iterMods \\ ["Sequence"]) "scan[10000] (iter)" "iterateScan")
-      , $(createBgroupSrc iterMods "filterEven (iter)" "iterateFilterEven")
-      , $(createBgroupSrc iterMods "takeAll (iter)" "iterateTakeAll")
-      , $(createBgroupSrc iterMods "dropOne (iter)" "iterateDropOne")
-      , $(createBgroupSrc iterMods "dropWhileFalse[10000] (iter)" "iterateDropWhileFalse")
-      , $(createBgroupSrc iterMods "dropWhileTrue (iter)" "iterateDropWhileTrue")
-      ]
-   ]
diff --git a/Benchmarks/BenchTH.hs b/Benchmarks/BenchTH.hs
deleted file mode 100644
--- a/Benchmarks/BenchTH.hs
+++ /dev/null
@@ -1,95 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module Benchmarks.BenchTH
-    ( mkBench
-    , mkBenchN
-    , purePackages
-    , monadicPackages
-    , monadicArrays
-    , allPackages
-    ) where
-
-import Benchmarks.Common (benchIO, benchPure, benchIOArray)
-import Language.Haskell.TH.Syntax (Q, Exp, mkName)
-import Language.Haskell.TH.Lib (varE)
-
--- First item in the tuple is the module name and the second one is the
--- corresponding benchmark group name.
---
-monadicPackages :: [(String, String)]
-monadicPackages =
-    [ ("Streamly", "streamly")
-    , ("VectorStreams", "streams-vector")
-    , ("Streaming", "streaming")
-    , ("Machines", "machines")
-    , ("Pipes", "pipes")
-    , ("Conduit", "conduit")
-    , ("Drinkery", "drinkery")
-    ]
-
-purePackages :: [(String, String)]
-purePackages =
-    [ ("List", "list")
-    , ("DList", "dlist")
-    , ("ByteString", "bytestring")
-    , ("ByteStringLazy", "lazy-bytestring")
-    , ("Text", "text")
-    , ("Sequence", "sequence")
-    , ("StreamlyPure", "pure-streamly")
-    , ("Vector", "vector")
-    ]
-
-monadicArrays :: [(String, String)]
-monadicArrays = [("StreamlyArray", "array-streamly")]
-
-allPackages :: [(String, String)]
-allPackages =
-       purePackages
-    ++ monadicPackages
-    ++ monadicArrays
-
--- mkBench <stream producer func> <stream consumer func> <module name>
-mkBench :: String -> String -> String -> Q Exp
-mkBench f x mdl =
-    case lookup mdl purePackages of
-        Nothing -> case lookup mdl monadicPackages of
-            Just pkg ->
-                [| benchIO pkg $(varE (mkName (mdl ++ "." ++ f)))
-                               $(varE (mkName (mdl ++ "." ++ x)))
-                |]
-            Nothing ->
-                if mdl == "StreamlyArray"
-                then
-                    [| benchIOArray "array-streamly"
-                            $(varE (mkName (mdl ++ "." ++ f)))
-                            $(varE (mkName (mdl ++ "." ++ x)))
-                    |]
-                else error $
-                    "module " ++ show mdl ++ " not found in module list"
-        Just pkg ->
-                [| benchPure pkg $(varE (mkName (mdl ++ "." ++ f)))
-                                 $(varE (mkName (mdl ++ "." ++ x)))
-                |]
-
-mkBenchN :: String -> String -> Int -> String -> Q Exp
-mkBenchN f x n mdl =
-    case lookup mdl purePackages of
-        Nothing -> case lookup mdl monadicPackages of
-            Just pkg ->
-                [| benchIO pkg $(varE (mkName (mdl ++ "." ++ f)))
-                               ($(varE (mkName (mdl ++ "." ++ x))) n)
-                |]
-            Nothing ->
-                if mdl == "StreamlyArray"
-                then
-                    [| benchIOArray "array-streamly"
-                            $(varE (mkName (mdl ++ "." ++ f)))
-                            ($(varE (mkName (mdl ++ "." ++ x))) n)
-                    |]
-                else
-                    error $
-                        "module " ++ show mdl ++ " not found in module list"
-        Just pkg ->
-                [| benchPure pkg $(varE (mkName (mdl ++ "." ++ f)))
-                               ($(varE (mkName (mdl ++ "." ++ x))) n)
-                |]
diff --git a/Benchmarks/BenchmarkTH.hs b/Benchmarks/BenchmarkTH.hs
deleted file mode 100644
--- a/Benchmarks/BenchmarkTH.hs
+++ /dev/null
@@ -1,57 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module Benchmarks.BenchmarkTH
-    ( createBgroupSink
-    , createBgroupSinkN
-    , createBgroupSrc
-    , pureMods
-    , monadicMods
-    , allMods
-    , benchMods
-    , iterMods
-    ) where
-
-import Data.List ((\\))
-import Language.Haskell.TH.Syntax (Q, Exp)
-import Language.Haskell.TH.Lib (listE)
-
-import Benchmarks.BenchTH
-
-benchMods, iterMods, pureMods, monadicMods, monadicArrayMods, allMods :: [String]
-pureMods    = map fst purePackages
-monadicMods = map fst monadicPackages
-monadicArrayMods = map fst monadicArrays
-allMods     = pureMods ++ monadicMods ++ monadicArrayMods
-benchMods   = allMods \\ ["DList"]
-iterMods = allMods \\
-    [ "DList"
-    , "Streaming"
-    , "Machines"
-    , "Pipes"
-    , "Conduit"
-    , "Drinkery"
-    ]
-
--- | createBgroupSink <module names> <benchmark name>
---                    <stream consumer function name>
-createBgroupSink :: [String] -> String -> String -> Q Exp
-createBgroupSink mods name fname =
-    [|
-        bgroup name $(listE (map (mkBench "source" fname) mods))
-    |]
-
--- | createBgroupSink <module names> <benchmark name>
---                    <stream consumer function name> <number of iterations>
-createBgroupSinkN :: [String] -> String -> String -> Int -> Q Exp
-createBgroupSinkN mods name fname n =
-    [|
-        bgroup name $(listE (map (mkBenchN "source" fname n) mods))
-    |]
-
--- | createBgroupSink <module names> <benchmark name>
---                    <stream producer function name>
-createBgroupSrc :: [String] -> String -> String -> Q Exp
-createBgroupSrc mods name fname =
-    [|
-        bgroup name $(listE (map (mkBench fname "toNull") mods))
-    |]
diff --git a/Benchmarks/ByteString.hs b/Benchmarks/ByteString.hs
--- a/Benchmarks/ByteString.hs
+++ b/Benchmarks/ByteString.hs
@@ -6,9 +6,11 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.ByteString where
 
+import Benchmarks.DefaultMain (defaultMain)
 -- import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
                 maxBound, Maybe(..))
@@ -50,12 +52,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Element
-appendSourceR n = P.foldr (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Element
-appendSourceL n = P.foldl (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -171,15 +175,14 @@
 iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Element
 
--- this is quadratic
 -- XXX using scanl instead of scanl'
-iterateScan n = iterateSource (S.scanl (+) 0) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxElem)) (maxIters `P.div` 100) n
-
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl (+) 0) maxIters n
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take nElements) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxElem)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxElem)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -224,3 +227,6 @@
 {-# INLINE concatMap #-}
 concatMap :: Stream Element -> ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "ByteString")
diff --git a/Benchmarks/ByteStringLazy.hs b/Benchmarks/ByteStringLazy.hs
--- a/Benchmarks/ByteStringLazy.hs
+++ b/Benchmarks/ByteStringLazy.hs
@@ -6,11 +6,13 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.ByteStringLazy where
 
+import Benchmarks.DefaultMain (defaultMain)
 -- import Benchmarks.Common (value, maxValue, appendValue)
-import Prelude (Int, (+), id, ($), (.), even, (>), (<=), subtract, undefined,
+import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
                 maxBound, Maybe(..))
 import qualified Prelude as P
 import Data.Word (Word8)
@@ -52,12 +54,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Element
-appendSourceR n = P.foldr (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Element
-appendSourceL n = P.foldl (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.append) S.empty (P.map (S.singleton . P.fromIntegral) [n..n+nAppends])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -112,7 +116,6 @@
         4 -> transform . f . f . f . f
         _ -> undefined
 
-{-# INLINE scan #-}
 {-# INLINE map #-}
 {-# INLINE mapM #-}
 {-# INLINE filterEven #-}
@@ -125,7 +128,7 @@
 {-# INLINE dropAll #-}
 {-# INLINE dropWhileTrue #-}
 {-# INLINE dropWhileFalse #-}
-scan, map, mapM,
+map, mapM,
     filterEven, filterAllOut, filterAllIn,
     takeOne, takeAll, takeWhileTrue,
     dropOne, dropAll, dropWhileTrue, dropWhileFalse
@@ -133,8 +136,11 @@
 
 -- XXX there is no scanl'
 -- XXX All scan ops hang for lazy bytestring, disabled for now
--- scan           n = composeN n $ S.scanl (+) 0
-scan           n = composeN n $ id
+{-
+{-# INLINE scan #-}
+scan :: Int -> Stream Int -> ()
+scan           n = composeN n $ S.scanl (+) 0
+-}
 map            n = composeN n $ S.map (+1)
 mapM             = map
 filterEven     n = composeN n $ S.filter even
@@ -166,56 +172,59 @@
         f (0 :: Int) m = g m
         f x m = g (f (x P.- 1) m)
 
-{-# INLINE iterateScan #-}
 {-# INLINE iterateFilterEven #-}
 {-# INLINE iterateTakeAll #-}
 {-# INLINE iterateDropOne #-}
 {-# INLINE iterateDropWhileFalse #-}
 {-# INLINE iterateDropWhileTrue #-}
-iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
+iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Element
 
 -- this is quadratic
 -- XXX using scanl instead of scanl'
 -- XXX All scan ops hang for lazy bytestring, disabled for now
-iterateScan n = iterateSource id (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxElem)) (maxIters `P.div` 100) n
-
+{-
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+{-# INLINE iterateScan #-}
+iterateScan :: Int -> Stream Element
+iterateScan n = iterateSource (error "hangs") maxIters n
+-}
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take nElements) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxElem)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxElem)) maxIters n
 
 -------------------------------------------------------------------------------
 -- Mixed Composition
 -------------------------------------------------------------------------------
 
-{-# INLINE scanMap #-}
 {-# INLINE dropMap #-}
-{-# INLINE dropScan #-}
 {-# INLINE takeDrop #-}
-{-# INLINE takeScan #-}
 {-# INLINE takeMap #-}
 {-# INLINE filterDrop #-}
 {-# INLINE filterTake #-}
-{-# INLINE filterScan #-}
 {-# INLINE filterMap #-}
-scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
-    filterTake, filterScan, filterMap
+dropMap, takeDrop, takeMap, filterDrop,
+    filterTake, filterMap
     :: Int -> Stream Element -> ()
 
 -- XXX using scanl instead of scanl'
 -- XXX All scan ops hang for lazy bytestring, disabled for now
-scanMap    n = composeN n $ id
+-- {-# INLINE scanMap #-}
+-- scanMap    n = composeN n $ id
 dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
-dropScan   n = composeN n $ id
+-- {-# INLINE dropScan #-}
+-- dropScan   n = composeN n $ id
 takeDrop   n = composeN n $ S.drop 1 . S.take nElements
-takeScan   n = composeN n $ id
+-- {-# INLINE takeScan #-}
+-- takeScan   n = composeN n $ id
 takeMap    n = composeN n $ S.map (subtract 1) . S.take nElements
 filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxElem)
 filterTake n = composeN n $ S.take nElements . S.filter (<= maxElem)
-filterScan n = composeN n $ id
+-- {-# INLINE filterScan #-}
+-- filterScan n = composeN n $ id
 filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxElem)
 
 -------------------------------------------------------------------------------
@@ -230,3 +239,6 @@
 {-# INLINE concatMap #-}
 concatMap :: Stream Element -> ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "ByteStringLazy")
diff --git a/Benchmarks/Common.hs b/Benchmarks/Common.hs
deleted file mode 100644
--- a/Benchmarks/Common.hs
+++ /dev/null
@@ -1,44 +0,0 @@
--- |
--- Module      : Benchmarks.Common
--- Copyright   : (c) 2018 Harendra Kumar
---
--- License     : MIT
--- Maintainer  : harendra.kumar@gmail.com
-
-module Benchmarks.Common
-    ( value
-    , maxValue
-    , appendValue
-    , benchIO
-    , benchIOArray
-    , benchId
-    , benchPure
-    ) where
-
-import Control.DeepSeq (NFData)
-import Data.Functor.Identity (Identity, runIdentity)
-import System.Random (randomRIO)
-
-import Gauge
-
-value, maxValue,appendValue :: Int
-value = 1000000
-maxValue = value + 1000
-appendValue = 10000
-
-{-# INLINE benchIO #-}
-benchIO :: (NFData b) => String -> (Int -> a) -> (a -> IO b) -> Benchmark
-benchIO name src f = bench name $ nfIO $ randomRIO (1,1) >>= f . src
-
-{-# INLINE benchId #-}
-benchId :: (NFData b) => String -> (Int -> a) -> (a -> Identity b) -> Benchmark
-benchId name src f = bench name $ nf (runIdentity . f) (src 10)
-
-{-# INLINE benchPure #-}
-benchPure :: (NFData b) => String -> (Int -> a) -> (a -> b) -> Benchmark
-benchPure name src f = bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
-
-{-# INLINE benchIOArray #-}
-benchIOArray :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
-benchIOArray name src f = bench name $ nfIO $
-    randomRIO (1,1) >>= src >>= f
diff --git a/Benchmarks/Conduit.hs b/Benchmarks/Conduit.hs
--- a/Benchmarks/Conduit.hs
+++ b/Benchmarks/Conduit.hs
@@ -5,8 +5,11 @@
 -- License     : MIT
 -- Maintainer  : harendra.kumar@gmail.com
 
+{-# LANGUAGE TemplateHaskell #-}
+
 module Benchmarks.Conduit where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude
        (Monad, Int, (+), ($), return, even, (>), (<=),
@@ -43,13 +46,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Monad m => Int -> Source m () Int
-appendSourceR n = foldMap (S.yieldM . return) [n..n+appendValue]
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    toNull $ foldMap (S.yieldM . return) [n..n+appendValue]
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Monad m => Int -> Source m () Int
+appendSourceL :: Int -> P.IO ()
 appendSourceL n =
-    P.foldl (<>) P.mempty (P.map (S.yieldM . return) [n..n+appendValue])
+    toNull $ P.foldl (<>) P.mempty (P.map (S.yieldM . return) [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -185,3 +189,6 @@
 {-# INLINE concatMapFoldable #-}
 concatMapFoldable :: Monad m => Source m () Int -> m ()
 concatMapFoldable = transform (S.map (replicate 3) S..| S.concat)
+
+main :: P.IO ()
+main = $(defaultMain "Conduit")
diff --git a/Benchmarks/DList.hs b/Benchmarks/DList.hs
--- a/Benchmarks/DList.hs
+++ b/Benchmarks/DList.hs
@@ -6,13 +6,19 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 
 module Benchmarks.DList where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, appendValue)
 import Prelude (Int, (+), ($), (.), (>), undefined, Maybe(..))
 import qualified Prelude as P
+
+#if !MIN_VERSION_base(4,20,0)
 import qualified Data.Foldable as P
+#endif
 
 import qualified Data.DList          as S
 
@@ -47,12 +53,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Int
-appendSourceR n = P.foldr S.append S.empty (P.map S.singleton [n..n+appendValue])
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr S.append S.empty (P.map S.singleton [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Int
-appendSourceL n = P.foldl S.append S.empty (P.map S.singleton [n..n+appendValue])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl S.append S.empty (P.map S.singleton [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -210,3 +218,6 @@
 {-# INLINE concat #-}
 concat :: Stream Int -> ()
 concat _src    = undefined
+
+main :: P.IO ()
+main = $(defaultMain "DList")
diff --git a/Benchmarks/Drinkery.hs b/Benchmarks/Drinkery.hs
--- a/Benchmarks/Drinkery.hs
+++ b/Benchmarks/Drinkery.hs
@@ -1,11 +1,15 @@
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TemplateHaskell #-}
+
 module Benchmarks.Drinkery where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue)
 import Control.Monad (void)
 import Prelude
        (Monad, Int, Maybe(..), (+), ($), return, even, (>), (<=),
-        subtract, undefined, replicate, (<$>), (<*>), fst, id, const, maxBound)
+        subtract, undefined, replicate, (<$>), (<*>), fst, id, const,
+        maxBound, IO)
 
 import qualified Data.Drinkery as S
 import qualified Data.Drinkery.Finite as S
@@ -144,3 +148,6 @@
 {-# INLINE concatMapFoldable #-}
 concatMapFoldable :: Monad m => Source m () Int -> m ()
 concatMapFoldable = transform $ S.map (replicate 3) S.++$ S.concatMap id
+
+main :: IO ()
+main = $(defaultMain "Drinkery")
diff --git a/Benchmarks/List.hs b/Benchmarks/List.hs
--- a/Benchmarks/List.hs
+++ b/Benchmarks/List.hs
@@ -6,9 +6,11 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.List where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
                 maxBound, Maybe(..))
@@ -51,12 +53,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Int
-appendSourceR n = P.foldr (S.++) [] (P.map (: []) [n..n+appendValue])
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr (S.++) [] (P.map (: []) [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Int
-appendSourceL n = P.foldl (S.++) [] (P.map (: []) [n..n+appendValue])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.++) [] (P.map (: []) [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -157,14 +161,13 @@
 iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Int
 
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `P.div` 100) n
-
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl' (+) 0) maxIters n
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxValue)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -208,3 +211,6 @@
 {-# INLINE concatMap #-}
 concatMap :: Stream Int -> ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "List")
diff --git a/Benchmarks/Machines.hs b/Benchmarks/Machines.hs
--- a/Benchmarks/Machines.hs
+++ b/Benchmarks/Machines.hs
@@ -6,9 +6,12 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TemplateHaskell #-}
 {-# OPTIONS_GHC -Wno-incomplete-patterns #-}
+
 module Benchmarks.Machines where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude
        (Monad, Int, (.), (+), ($), return, even, (>), (<=),
@@ -39,13 +42,15 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Monad m => Int -> Source m Int
-appendSourceR n = foldMap (S.construct . S.yield) [n..n+appendValue]
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    toNull $ foldMap (S.construct . S.yield) [n..n+appendValue]
 
 -- XXX use S.prepended instead?
 {-# INLINE appendSourceL #-}
-appendSourceL :: Monad m => Int -> Source m Int
-appendSourceL n = P.foldl (<>) P.mempty (P.map (S.construct . S.yield) [n..n+appendValue])
+appendSourceL :: Int -> P.IO ()
+appendSourceL n =
+    toNull $ P.foldl (<>) P.mempty (P.map (S.construct . S.yield) [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -159,3 +164,6 @@
 {-# INLINE concatMapFoldable #-}
 concatMapFoldable :: Monad m => S.MachineT m k Int -> m ()
 concatMapFoldable = transform (S.mapping (replicate 3) S.~> S.asParts)
+
+main :: P.IO ()
+main = $(defaultMain "Machines")
diff --git a/Benchmarks/Pipes.hs b/Benchmarks/Pipes.hs
--- a/Benchmarks/Pipes.hs
+++ b/Benchmarks/Pipes.hs
@@ -6,9 +6,11 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.Pipes where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Data.Void (Void)
 import Prelude
@@ -43,12 +45,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Monad m => Int -> Source m () Int
-appendSourceR n = foldMap S.yield [n..n+appendValue]
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    toNull $ foldMap S.yield [n..n+appendValue]
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Monad m => Int -> Source m () Int
-appendSourceL n = P.foldl (<>) P.mempty (P.map S.yield [n..n+appendValue])
+appendSourceL :: Int -> P.IO ()
+appendSourceL n =
+    toNull $ P.foldl (<>) P.mempty (P.map S.yield [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -159,3 +163,6 @@
 {-# INLINE concatMapFoldable #-}
 concatMapFoldable :: Monad m => Source m () Int -> m ()
 concatMapFoldable = transform (S.map (replicate 3) S.>-> S.concat)
+
+main :: P.IO ()
+main = $(defaultMain "Pipes")
diff --git a/Benchmarks/Sequence.hs b/Benchmarks/Sequence.hs
--- a/Benchmarks/Sequence.hs
+++ b/Benchmarks/Sequence.hs
@@ -6,9 +6,12 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE CPP #-}
 
 module Benchmarks.Sequence where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
                 Maybe(..))
@@ -48,13 +51,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Int
+appendSourceR :: Int -> ()
 appendSourceR n =
-    P.foldr (S.><) S.empty (P.map S.singleton [n..n+appendValue])
+    toNull $ P.foldr (S.><) S.empty (P.map S.singleton [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Int
-appendSourceL n = P.foldl (S.><) S.empty (P.map S.singleton [n..n+appendValue])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.><) S.empty (P.map S.singleton [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -159,14 +163,11 @@
 iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Int
 
--- this is quadratic
 iterateScan  = undefined
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhileL (> maxValue)) (maxIters `P.div` 100) n
-
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhileL (> maxValue)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhileL (<= maxValue)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -209,3 +210,6 @@
 {-# INLINE concat #-}
 concat :: Stream Int -> Stream Int
 concat _src    = undefined -- transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "Sequence")
diff --git a/Benchmarks/Streaming.hs b/Benchmarks/Streaming.hs
--- a/Benchmarks/Streaming.hs
+++ b/Benchmarks/Streaming.hs
@@ -5,10 +5,12 @@
 -- License     : MIT
 -- Maintainer  : harendra.kumar@gmail.com
 
+{-# LANGUAGE TemplateHaskell #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module Benchmarks.Streaming where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Control.DeepSeq (NFData)
 import Prelude
@@ -44,12 +46,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Monad m => Int -> Stream m Int
-appendSourceR n = foldMap S.yield [n..n+appendValue]
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    toNull $ foldMap S.yield [n..n+appendValue]
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Monad m => Int -> Stream m Int
-appendSourceL n = P.foldl (<>) P.mempty (P.map S.yield [n..n+appendValue])
+appendSourceL :: Int -> P.IO ()
+appendSourceL n =
+    toNull $ P.foldl (<>) P.mempty (P.map S.yield [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -166,3 +170,6 @@
 {-# INLINE concatMapFoldable #-}
 concatMapFoldable :: Monad m => Stream m Int -> m ()
 concatMapFoldable src = runStream $ (S.concat $ S.map (P.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "Streaming")
diff --git a/Benchmarks/Streamly.hs b/Benchmarks/Streamly.hs
--- a/Benchmarks/Streamly.hs
+++ b/Benchmarks/Streamly.hs
@@ -7,32 +7,52 @@
 
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -Wno-identities #-}
 
 module Benchmarks.Streamly where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude
-       (Monad, Int, (+), ($), (.), return, even, (>), (<=), div,
-        subtract, undefined, Maybe(..), foldMap, maxBound)
+       (Monad, Int, (+), ($), (.), return, even, (>), (<=),
+        subtract, undefined, Maybe(..), maxBound, fmap)
 import qualified Prelude as P
 
-import qualified Streamly.Prelude  as S
+import qualified Streamly.Data.Fold as Fold
+import qualified Streamly.Data.Scanl as Scanl
+import qualified Streamly.Data.Stream as S
+import qualified Streamly.Data.StreamK as K
 
+-- import Data.Word (Word8)
+
+-- To compare with ByteString we use an element of type Word8
+-- It does not seem to make any perceptible difference though
+type Element = Int
+-- type Element = Word8
+
+nElements :: Int
+nElements = maxValue
+
+maxElem :: Element
+maxElem = maxBound
+
 -------------------------------------------------------------------------------
 -- Stream generation
 -------------------------------------------------------------------------------
 
-type Stream m a = S.SerialT m a
+type Stream m a = S.Stream m a
+type StreamK m a = K.StreamK m a
 
 {-# INLINE source #-}
-source :: S.MonadAsync m => Int -> Stream m Int
+source :: Monad m => Int -> Stream m Element
 -- source n = S.fromFoldable [n..n+value]
 source n = S.unfoldrM step n
     where
     step cnt =
         if cnt > n + value
         then return Nothing
-        else return (Just (cnt, cnt + 1))
+        else return (Just (P.fromIntegral cnt, cnt + 1))
         {-
 source n = S.unfoldr step n
     where
@@ -43,29 +63,32 @@
             -}
 
 {-# INLINE sourceN #-}
-sourceN :: S.MonadAsync m => Int -> Int -> Stream m Int
-sourceN count begin = S.unfoldrM step begin
+sourceN :: Monad m => Int -> Int -> StreamK m Element
+sourceN count begin = K.fromStream $ S.unfoldrM step begin
     where
     step i =
         if i > begin + count
         then return Nothing
-        else return (Just (i, i + 1))
+        else return (Just (P.fromIntegral i, i + 1))
 
 {-# INLINE sourceIntFromThenTo #-}
-sourceIntFromThenTo :: (Monad m, S.IsStream t) => Int -> t m Int
-sourceIntFromThenTo n = S.enumerateFromThenTo n (n + 1) (n + value)
+sourceIntFromThenTo :: Monad m => Int -> Stream m Element
+sourceIntFromThenTo n =
+    fmap P.fromIntegral $ S.enumerateFromThenTo n (n + 1) (n + value)
 
 -------------------------------------------------------------------------------
 -- Append
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream m Int
-appendSourceR n = foldMap S.fromPure [n..n+appendValue]
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    K.drain $ P.foldr K.append K.nil (P.map K.fromPure [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream m Int
-appendSourceL n = P.foldl (P.<>) S.nil (P.map S.fromPure [n..n+appendValue])
+appendSourceL :: Int -> P.IO ()
+appendSourceL n =
+    K.drain $ P.foldl K.append K.nil (P.map K.fromPure [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -73,21 +96,21 @@
 
 {-# INLINE runStream #-}
 runStream :: Monad m => Stream m a -> m ()
-runStream = S.drain
+runStream = S.fold Fold.drain
 
 {-# INLINE toNull #-}
 {-# INLINE toList #-}
 {-# INLINE foldl #-}
 {-# INLINE last #-}
-toNull :: Monad m => Stream m Int -> m ()
-toList :: Monad m => Stream m Int -> m [Int]
-foldl  :: Monad m => Stream m Int -> m Int
-last   :: Monad m => Stream m Int -> m (Maybe Int)
+toNull :: Monad m => Stream m Element -> m ()
+toList :: Monad m => Stream m Element -> m [Element]
+foldl  :: Monad m => Stream m Element -> m Element
+last   :: Monad m => Stream m Element -> m (Maybe Element)
 
 toNull = runStream
 toList = S.toList
-foldl  = S.foldl' (+) 0
-last   = S.last
+foldl  = S.fold (Fold.foldl' (+) 0)
+last   = S.fold Fold.latest
 
 -------------------------------------------------------------------------------
 -- Transformation
@@ -100,7 +123,7 @@
 {-# INLINE composeN #-}
 composeN
     :: Monad m
-    => Int -> (Stream m Int -> Stream m Int) -> Stream m Int -> m ()
+    => Int -> (Stream m Element -> Stream m Element) -> Stream m Element -> m ()
 composeN n f =
     case n of
         1 -> transform . f
@@ -126,23 +149,23 @@
     filterEven, filterAllOut, filterAllIn,
     takeOne, takeAll, takeWhileTrue,
     dropOne, dropAll, dropWhileTrue, dropWhileFalse
-    :: Monad m => Int -> Stream m Int -> m ()
+    :: Monad m => Int -> Stream m Element -> m ()
 
-mapM :: S.MonadAsync m => Int -> Stream m Int -> m ()
+mapM :: Monad m => Int -> Stream m Element -> m ()
 
-scan           n = composeN n $ S.scanl' (+) 0
-map            n = composeN n $ S.map (+1)
+scan           n = composeN n $ S.scanl (Scanl.mkScanl (+) 0)
+map            n = composeN n $ fmap (+1)
 mapM           n = composeN n $ S.mapM return
 filterEven     n = composeN n $ S.filter even
-filterAllOut   n = composeN n $ S.filter (> maxValue)
-filterAllIn    n = composeN n $ S.filter (<= maxValue)
+filterAllOut   n = composeN n $ S.filter (> maxElem)
+filterAllIn    n = composeN n $ S.filter (<= maxElem)
 takeOne        n = composeN n $ S.take 1
-takeAll        n = composeN n $ S.take maxValue
-takeWhileTrue  n = composeN n $ S.takeWhile (<= maxValue)
+takeAll        n = composeN n $ S.take nElements
+takeWhileTrue  n = composeN n $ S.takeWhile (<= maxElem)
 dropOne        n = composeN n $ S.drop 1
-dropAll        n = composeN n $ S.drop maxValue
-dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
-dropWhileTrue  n = composeN n $ S.dropWhile (<= maxValue)
+dropAll        n = composeN n $ S.drop nElements
+dropWhileFalse n = composeN n $ S.dropWhile (> maxElem)
+dropWhileTrue  n = composeN n $ S.dropWhile (<= maxElem)
 
 -------------------------------------------------------------------------------
 -- Iteration
@@ -154,34 +177,45 @@
 
 {-# INLINE iterateSource #-}
 iterateSource
-    :: S.MonadAsync m
-    => (Stream m Int -> Stream m Int) -> Int -> Int -> Stream m Int
+    :: Monad m
+    => (StreamK m Element -> StreamK m Element)
+    -> Int
+    -> Int
+    -> StreamK m Element
 iterateSource g i n = f i (sourceN iterStreamLen n)
+
     where
-        f (0 :: Int) m = g m
-        f x m = g (f (x P.- 1) m)
 
-{-# INLINE iterateMapM #-}
-{-# INLINE iterateScan #-}
-{-# INLINE iterateFilterEven #-}
-{-# INLINE iterateTakeAll #-}
-{-# INLINE iterateDropOne #-}
-{-# INLINE iterateDropWhileFalse #-}
-{-# INLINE iterateDropWhileTrue #-}
+    f (0 :: Int) m = g m
+    f x m = g (f (x P.- 1) m)
+
 iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
-    iterateDropWhileFalse, iterateDropWhileTrue :: S.MonadAsync m => Int -> Stream m Int
+    iterateDropWhileFalse, iterateDropWhileTrue :: Monad m => Int -> Stream m Element
 
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `div` 100) n
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = K.toStream $ iterateSource (K.fromStream . S.drop 1 . S.scanl (Scanl.mkScanl (+) 0) . K.toStream) maxIters n
+-- iterateScan n = K.toStream $ iterateSource (K.drop 1 . K.scanl' (+) 0) maxIters n
 
-iterateMapM n = iterateSource (S.mapM return) maxIters n
-iterateFilterEven n = iterateSource (S.filter even) maxIters n
-iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
-iterateDropOne n = iterateSource (S.drop 1) maxIters n
-iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
+-- iterateMapM n = K.toStream $ iterateSource (K.fromStream . S.mapM return . K.toStream) maxIters n
+iterateMapM n = K.toStream $ iterateSource (K.mapM return) maxIters n
 
+-- The D version is very slow, investigate why.
+-- iterateDropWhileFalse n = K.toStream $ iterateSource (K.fromStream . S.dropWhile (> maxElem) . K.toStream) maxIters n
+iterateDropWhileFalse n = K.toStream $ iterateSource (K.dropWhile (> maxElem)) maxIters n
+
+-- iterateTakeAll n = K.toStream $ iterateSource (K.fromStream . S.take nElements . K.toStream) maxIters n
+iterateTakeAll n = K.toStream $ iterateSource (K.take nElements) maxIters n
+
+iterateFilterEven n = K.toStream $ iterateSource (K.fromStream . S.filter even . K.toStream) maxIters n
+-- iterateFilterEven n = K.toStream $ iterateSource (K.filter even) maxIters n
+
+iterateDropOne n = K.toStream $ iterateSource (K.fromStream . S.drop 1 . K.toStream) maxIters n
+-- iterateDropOne n = K.toStream $ iterateSource (K.drop 1) maxIters n
+
+-- iterateDropWhileTrue n = K.toStream $ iterateSource (K.fromStream . S.dropWhile (<= maxElem) . K.toStream) maxIters n
+iterateDropWhileTrue n = K.toStream $ iterateSource (K.dropWhile (<= maxElem)) maxIters n
+
 -------------------------------------------------------------------------------
 -- Mixed Composition
 -------------------------------------------------------------------------------
@@ -198,29 +232,32 @@
 {-# INLINE filterMap #-}
 scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
     filterTake, filterScan, filterMap
-    :: Monad m => Int -> Stream m Int -> m ()
+    :: Monad m => Int -> Stream m Element -> m ()
 
-scanMap    n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
-dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
-dropScan   n = composeN n $ S.scanl' (+) 0 . S.drop 1
-takeDrop   n = composeN n $ S.drop 1 . S.take maxValue
-takeScan   n = composeN n $ S.scanl' (+) 0 . S.take maxValue
-takeMap    n = composeN n $ S.map (subtract 1) . S.take maxValue
-filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
-filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
-filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
-filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
+scanMap    n = composeN n $ fmap (subtract 1) . S.scanl (Scanl.mkScanl (+) 0)
+dropMap    n = composeN n $ fmap (subtract 1) . S.drop 1
+dropScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.drop 1
+takeDrop   n = composeN n $ S.drop 1 . S.take nElements
+takeScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.take nElements
+takeMap    n = composeN n $ fmap (subtract 1) . S.take nElements
+filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxElem)
+filterTake n = composeN n $ S.take maxValue . S.filter (<= maxElem)
+filterScan n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.filter (<= maxElem)
+filterMap  n = composeN n $ fmap (subtract 1) . S.filter (<= maxElem)
 
 -------------------------------------------------------------------------------
 -- Zipping and concat
 -------------------------------------------------------------------------------
 
 {-# INLINE zip #-}
-zip :: S.MonadAsync m => Stream m Int -> m ()
+zip :: Monad m => Stream m Element -> m ()
 zip src = transform $ (S.zipWith (,) src src)
 
 {-# INLINE concatMap #-}
-concatMap :: Monad m => Stream m Int -> m ()
+concatMap :: Monad m => Stream m Element -> m ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
 
 -- XXX composed zip and concat
+
+main :: P.IO ()
+main = $(defaultMain "Streamly")
diff --git a/Benchmarks/StreamlyArray.hs b/Benchmarks/StreamlyArray.hs
--- a/Benchmarks/StreamlyArray.hs
+++ b/Benchmarks/StreamlyArray.hs
@@ -7,20 +7,29 @@
 
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
 
 module Benchmarks.StreamlyArray where
 
+import Control.DeepSeq (NFData(..))
 import Control.Monad.IO.Class (MonadIO(..))
 import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
-                maxBound, Maybe(..))
+                maxBound, Maybe(..), fmap, div)
 import qualified Prelude as P
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue) -- , appendValue)
 
-import qualified Streamly.Prelude  as S
-import qualified Streamly.Data.Array.Foreign as A
-import qualified Streamly.Internal.Data.Fold as Fold
+import qualified Streamly.Data.Stream  as S
+import qualified Streamly.Data.Array as A
+import qualified Streamly.Data.Fold as Fold
+import qualified Streamly.Data.Scanl as Scanl
 
+instance NFData (A.Array a) where
+    {-# INLINE rnf #-}
+    rnf _ = ()
+
 -------------------------------------------------------------------------------
 -- Stream generation and elimination
 -------------------------------------------------------------------------------
@@ -29,7 +38,7 @@
 
 {-# INLINE source #-}
 source :: MonadIO m => Int -> m (Stream Int)
-source n = S.fold (A.writeN value) (S.unfoldr step n)
+source n = S.fold (A.createOf value) (S.unfoldr step n)
     where
     step cnt =
         if cnt > n + value
@@ -38,7 +47,7 @@
 
 {-# INLINE sourceN #-}
 sourceN :: MonadIO m => Int -> Int -> m (Stream Int)
-sourceN count begin = S.fold (A.writeN value) (S.unfoldr step begin)
+sourceN count begin = S.fold (A.createOf value) (S.unfoldr step begin)
     where
     step i =
         if i > begin + count
@@ -74,11 +83,11 @@
 
 {-# INLINE foldl #-}
 foldl :: MonadIO m => Stream Int -> m Int
-foldl = S.fold Fold.sum . S.unfold A.read
+foldl = S.fold Fold.sum . S.unfold A.reader
 
 {-# INLINE last #-}
 last :: P.Monad m => Stream Int -> m (Maybe Int)
-last arr = P.return (A.getIndex arr (A.length arr P.- 1))
+last arr = P.return (A.getIndex (A.length arr P.- 1) arr)
 
 -------------------------------------------------------------------------------
 -- Transformation
@@ -92,17 +101,17 @@
 
 {-# INLINE composeN #-}
 composeN
-    :: S.MonadAsync m
+    :: MonadIO m
     => Int
-    -> (S.SerialT m Int -> S.SerialT m Int)
+    -> (S.Stream m Int -> S.Stream m Int)
     -> Stream Int
     -> m (Stream Int)
 composeN n f x =
     case n of
-        1 -> S.fold A.write $ f $ S.unfold A.read x
-        2 -> S.fold A.write $ f . f $ S.unfold A.read x
-        3 -> S.fold A.write $ f . f . f $ S.unfold A.read x
-        4 -> S.fold A.write $ f . f . f . f $ S.unfold A.read x
+        1 -> S.fold A.create $ f $ S.unfold A.reader x
+        2 -> S.fold A.create $ f . f $ S.unfold A.reader x
+        3 -> S.fold A.create $ f . f . f $ S.unfold A.reader x
+        4 -> S.fold A.create $ f . f . f . f $ S.unfold A.reader x
         _ -> undefined
 
 {-# INLINE scan #-}
@@ -122,10 +131,10 @@
     filterEven, filterAllOut, filterAllIn,
     takeOne, takeAll, takeWhileTrue,
     dropOne, dropAll, dropWhileTrue, dropWhileFalse
-    :: S.MonadAsync m => Int -> Stream Int -> m (Stream Int)
+    :: MonadIO m => Int -> Stream Int -> m (Stream Int)
 
-scan           n = composeN n $ S.scanl' (+) 0
-map            n = composeN n $ S.map (+1)
+scan           n = composeN n $ S.scanl (Scanl.mkScanl (+) 0)
+map            n = composeN n $ fmap (+1)
 mapM           n = composeN n $ S.mapM (\x -> P.return $ x + 1)
 filterEven     n = composeN n $ S.filter even
 filterAllOut   n = composeN n $ S.filter (> maxValue)
@@ -148,9 +157,9 @@
 
 {-# INLINE iterateSource #-}
 iterateSource :: MonadIO m
-    => (S.SerialT m Int -> S.SerialT m Int) -> Int -> Int -> m (Stream Int)
+    => (S.Stream m Int -> S.Stream m Int) -> Int -> Int -> m (Stream Int)
 iterateSource g i n =
-    sourceN iterStreamLen n P.>>= \a -> S.fold A.write (f i $ S.unfold A.read a)
+    sourceN iterStreamLen n P.>>= \a -> S.fold A.create (f i $ S.unfold A.reader a)
     where
         f (0 :: Int) m = g m
         f x m = g (f (x P.- 1) m)
@@ -164,17 +173,16 @@
 {-# INLINE iterateDropWhileTrue #-}
 iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue ::
-        S.MonadAsync m => Int -> m (Stream Int)
-
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `P.div` 100) n
+        MonadIO m => Int -> m (Stream Int)
 
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl (Scanl.mkScanl (+) 0)) (maxIters `div` 100) n
 iterateMapM n = iterateSource (S.mapM P.return) maxIters n
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxValue)) (maxIters `div` 100) n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -193,18 +201,18 @@
 {-# INLINE filterMap #-}
 scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
     filterTake, filterScan, filterMap
-    :: S.MonadAsync m => Int -> Stream Int -> m (Stream Int)
+    :: MonadIO m => Int -> Stream Int -> m (Stream Int)
 
-scanMap    n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
-dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
-dropScan   n = composeN n $ S.scanl' (+) 0 . S.drop 1
+scanMap    n = composeN n $ fmap (subtract 1) . S.scanl (Scanl.mkScanl (+) 0)
+dropMap    n = composeN n $ fmap (subtract 1) . S.drop 1
+dropScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.drop 1
 takeDrop   n = composeN n $ S.drop 1 . S.take maxValue
-takeScan   n = composeN n $ S.scanl' (+) 0 . S.take maxValue
-takeMap    n = composeN n $ S.map (subtract 1) . S.take maxValue
+takeScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.take maxValue
+takeMap    n = composeN n $ fmap (subtract 1) . S.take maxValue
 filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
 filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
-filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
-filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
+filterScan n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.filter (<= maxBound)
+filterMap  n = composeN n $ fmap (subtract 1) . S.filter (<= maxValue)
 
 -------------------------------------------------------------------------------
 -- Zipping and concat
@@ -220,3 +228,6 @@
 concat :: Stream Int -> ()
 concat src    = transform $ (S.concatMap (S.replicate 3) src)
 -}
+
+main :: P.IO ()
+main = $(defaultMain "StreamlyArray")
diff --git a/Benchmarks/StreamlyPure.hs b/Benchmarks/StreamlyPure.hs
--- a/Benchmarks/StreamlyPure.hs
+++ b/Benchmarks/StreamlyPure.hs
@@ -8,27 +8,35 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.StreamlyPure where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Data.Functor.Identity (Identity, runIdentity)
 import Prelude
        (Int, (+), ($), (.), even, (>), (<=),
-        subtract, undefined, Maybe(..), foldMap, maxBound)
+        subtract, undefined, Maybe(..), maxBound, fmap)
 import qualified Prelude as P
 
-import qualified Streamly.Prelude  as S
+import qualified Streamly.Data.Fold as Fold
+import qualified Streamly.Data.Scanl as Scanl
+import qualified Streamly.Data.Stream as S
+import qualified Streamly.Data.StreamK as K
 
 -------------------------------------------------------------------------------
 -- Stream generation
 -------------------------------------------------------------------------------
 
-type Stream = S.SerialT Identity
+type Stream = S.Stream Identity
+type StreamK = K.StreamK Identity
 
+maxElem :: Int
+maxElem = maxBound
+
 {-# INLINE source #-}
 source :: Int -> Stream Int
-
 source n = S.unfoldr step n
     where
     step cnt =
@@ -37,8 +45,8 @@
         else (Just (cnt, cnt + 1))
 
 {-# INLINE sourceN #-}
-sourceN :: Int -> Int -> Stream Int
-sourceN count begin = S.unfoldr step begin
+sourceN :: Int -> Int -> StreamK Int
+sourceN count begin = K.fromStream $ S.unfoldr step begin
     where
     step i =
         if i > begin + count
@@ -50,12 +58,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Int
-appendSourceR n = foldMap S.fromPure [n..n+appendValue]
+appendSourceR :: Int -> Identity ()
+appendSourceR n =
+    K.drain $ P.foldr K.append K.nil (P.map K.fromPure [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Int
-appendSourceL n = P.foldl (P.<>) S.nil (P.map S.fromPure [n..n+appendValue])
+appendSourceL :: Int -> Identity ()
+appendSourceL n =
+    K.drain $ P.foldl K.append K.nil (P.map K.fromPure [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -82,12 +92,12 @@
 toList = evalF . runIdentity . S.toList
 
 {-# INLINE foldl #-}
-foldl  :: Stream Int -> Int
-foldl  = runIdentity . S.foldl' (+) 0
+foldl :: Stream Int -> Int
+foldl = runIdentity . S.fold (Fold.foldl' (+) 0)
 
 {-# INLINE last #-}
-last   :: Stream Int -> Maybe Int
-last   = runIdentity . S.last
+last :: Stream Int -> Maybe Int
+last = runIdentity . S.fold Fold.latest
 
 -------------------------------------------------------------------------------
 -- Transformation
@@ -127,8 +137,8 @@
     dropOne, dropAll, dropWhileTrue, dropWhileFalse
     :: Int -> Stream Int -> ()
 
-scan           n = composeN n $ S.scanl' (+) 0
-map            n = composeN n $ S.map (+1)
+scan           n = composeN n $ S.scanl (Scanl.mkScanl (+) 0)
+map            n = composeN n $ fmap (+1)
 mapM             = map
 filterEven     n = composeN n $ S.filter even
 filterAllOut   n = composeN n $ S.filter (> maxValue)
@@ -150,31 +160,45 @@
 maxIters = 100000
 
 {-# INLINE iterateSource #-}
-iterateSource :: (Stream Int -> Stream Int) -> Int -> Int -> Stream Int
+iterateSource
+    :: (StreamK Int -> StreamK Int)
+    -> Int
+    -> Int
+    -> StreamK Int
 iterateSource g i n = f i (sourceN iterStreamLen n)
+
     where
-        f (0 :: Int) m = g m
-        f x m = g (f (x P.- 1) m)
 
-{-# INLINE iterateScan #-}
-{-# INLINE iterateFilterEven #-}
-{-# INLINE iterateTakeAll #-}
-{-# INLINE iterateDropOne #-}
-{-# INLINE iterateDropWhileFalse #-}
-{-# INLINE iterateDropWhileTrue #-}
-iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
+    f (0 :: Int) m = g m
+    f x m = g (f (x P.- 1) m)
+
+iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Int
 
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `P.div` 100) n
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = K.toStream $ iterateSource (K.fromStream . S.drop 1 . S.scanl (Scanl.mkScanl (+) 0) . K.toStream) (maxIters `P.div` 100) n
+-- iterateScan n = K.toStream $ iterateSource (K.scanl' (+) 0) (maxIters `div` 100) n
 
-iterateFilterEven n = iterateSource (S.filter even) maxIters n
-iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
-iterateDropOne n = iterateSource (S.drop 1) maxIters n
-iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
+-- iterateMapM n = K.toStream $ iterateSource (K.fromStream . S.mapM return . K.toStream) maxIters n
+iterateMapM n = K.toStream $ iterateSource (K.mapM P.return) maxIters n
 
+-- The D version is very slow, investigate why.
+-- iterateDropWhileFalse n = K.toStream $ iterateSource (K.fromStream . S.dropWhile (> maxElem) . K.toStream) maxIters n
+iterateDropWhileFalse n = K.toStream $ iterateSource (K.dropWhile (> maxElem)) maxIters n
+
+-- iterateTakeAll n = K.toStream $ iterateSource (K.fromStream . S.take maxValue . K.toStream) maxIters n
+iterateTakeAll n = K.toStream $ iterateSource (K.take maxValue) maxIters n
+
+iterateFilterEven n = K.toStream $ iterateSource (K.fromStream . S.filter even . K.toStream) maxIters n
+-- iterateFilterEven n = K.toStream $ iterateSource (K.filter even) maxIters n
+
+iterateDropOne n = K.toStream $ iterateSource (K.fromStream . S.drop 1 . K.toStream) maxIters n
+-- iterateDropOne n = K.toStream $ iterateSource (K.drop 1) maxIters n
+
+-- iterateDropWhileTrue n = K.toStream $ iterateSource (K.fromStream . S.dropWhile (<= maxElem) . K.toStream) maxIters n
+iterateDropWhileTrue n = K.toStream $ iterateSource (K.dropWhile (<= maxElem)) maxIters n
+
 -------------------------------------------------------------------------------
 -- Mixed Composition
 -------------------------------------------------------------------------------
@@ -193,26 +217,29 @@
     filterTake, filterScan, filterMap
     :: Int -> Stream Int -> ()
 
-scanMap    n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
-dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
-dropScan   n = composeN n $ S.scanl' (+) 0 . S.drop 1
+scanMap    n = composeN n $ fmap (subtract 1) . S.scanl (Scanl.mkScanl (+) 0)
+dropMap    n = composeN n $ fmap (subtract 1) . S.drop 1
+dropScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.drop 1
 takeDrop   n = composeN n $ S.drop 1 . S.take maxValue
-takeScan   n = composeN n $ S.scanl' (+) 0 . S.take maxValue
-takeMap    n = composeN n $ S.map (subtract 1) . S.take maxValue
+takeScan   n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.take maxValue
+takeMap    n = composeN n $ fmap (subtract 1) . S.take maxValue
 filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
 filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
-filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
-filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
+filterScan n = composeN n $ S.scanl (Scanl.mkScanl (+) 0) . S.filter (<= maxBound)
+filterMap  n = composeN n $ fmap (subtract 1) . S.filter (<= maxValue)
 
 -------------------------------------------------------------------------------
 -- Zipping and concat
 -------------------------------------------------------------------------------
 
--- {-# INLINE zip #-}
--- zip :: Stream Int -> ()
--- zip src = runIdentity $ S.foldr (\(x,y) xs -> P.seq x (P.seq y xs)) ()
---     $ S.zipWith (,) src src
+{-# INLINE zip #-}
+zip :: Stream Int -> ()
+zip src = runIdentity $ S.foldr (\(x,y) xs -> P.seq x (P.seq y xs)) ()
+    $ S.zipWith (,) src src
 
 {-# INLINE concatMap #-}
 concatMap :: Stream Int -> ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "StreamlyPure")
diff --git a/Benchmarks/Text.hs b/Benchmarks/Text.hs
--- a/Benchmarks/Text.hs
+++ b/Benchmarks/Text.hs
@@ -6,9 +6,11 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.Text where
 
+import Benchmarks.DefaultMain (defaultMain)
 -- import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude (Int, (+), ($), (.), even, (>), (<=), undefined,
                 Maybe(..), Char)
@@ -50,12 +52,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Element
-appendSourceR n = P.foldr (S.append) S.empty (P.map (S.singleton . chr) [n..n+nAppends])
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr (S.append) S.empty (P.map (S.singleton . chr) [n..n+nAppends])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Element
-appendSourceL n = P.foldl (S.append) S.empty (P.map (S.singleton . chr) [n..n+nAppends])
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.append) S.empty (P.map (S.singleton . chr) [n..n+nAppends])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -174,15 +178,14 @@
 iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Element
 
--- this is quadratic
 -- XXX using scanl instead of scanl'
-iterateScan n = iterateSource (S.scanl plus (chr 0)) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxElem)) (maxIters `P.div` 100) n
-
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl plus (chr 0)) maxIters n
 iterateFilterEven n = iterateSource (S.filter (even . ord)) maxIters n
 iterateTakeAll n = iterateSource (S.take nElements) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxElem)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxElem)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -226,3 +229,6 @@
 {-# INLINE concatMap #-}
 concatMap :: Stream Element -> ()
 concatMap src = transform $ (S.concatMap (S.pack . P.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "Text")
diff --git a/Benchmarks/Vector.hs b/Benchmarks/Vector.hs
--- a/Benchmarks/Vector.hs
+++ b/Benchmarks/Vector.hs
@@ -7,219 +7,13 @@
 
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.Vector where
 
-import Foreign.Storable (Storable)
-import Benchmarks.Common (value, maxValue, appendValue)
-import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
-                maxBound, Maybe(..))
-import qualified Prelude as P
-
--- import qualified Data.Vector as S
-import qualified Data.Vector.Storable as S
--- import qualified Data.Vector.Unboxed as S
-
--------------------------------------------------------------------------------
--- Stream generation and elimination
--------------------------------------------------------------------------------
-
-type Stream = S.Vector
-
-{-# INLINE source #-}
-source :: Int -> Stream Int
--- source v = S.fromList [v..v+value]
-
-source n = S.unfoldr step n
-    where
-    step cnt =
-        if cnt > n + value
-        then Nothing
-        else (Just (cnt, cnt + 1))
-
-{-# INLINE sourceN #-}
-sourceN :: Int -> Int -> Stream Int
-sourceN count begin = S.unfoldr step begin
-    where
-    step i =
-        if i > begin + count
-        then Nothing
-        else (Just (i, i + 1))
-
--------------------------------------------------------------------------------
--- Append
--------------------------------------------------------------------------------
-
-{-# INLINE appendSourceR #-}
-appendSourceR :: Int -> Stream Int
-appendSourceR n =
-    P.foldr (S.++) S.empty (P.map S.singleton [n..n+appendValue])
-
-{-# INLINE appendSourceL #-}
-appendSourceL :: Int -> Stream Int
-appendSourceL n = P.foldl (S.++) S.empty (P.map S.singleton [n..n+appendValue])
-
--------------------------------------------------------------------------------
--- Elimination
--------------------------------------------------------------------------------
-
--- Using NFData for evaluation may be fraught with problems because of a
--- non-optimal implementation of NFData instance. So we just evaluate each
--- element of the stream using a fold.
-{-# INLINE eval #-}
-eval :: Storable a => Stream a -> ()
-eval = S.foldr P.seq ()
-
--- eval foldable
-{-# INLINE evalF #-}
-evalF :: P.Foldable t => t a -> ()
-evalF = P.foldr P.seq ()
-
-{-# INLINE toNull #-}
-toNull :: Stream Int -> ()
-toNull = eval
-
-{-# INLINE toList #-}
-toList :: Stream Int -> ()
-toList = evalF . S.toList
-
-{-# INLINE foldl #-}
-foldl :: Stream Int -> Int
-foldl  = S.foldl' (+) 0
-
-{-# INLINE last #-}
-last  :: Stream Int -> Int
-last   = S.last
-
--------------------------------------------------------------------------------
--- Transformation
--------------------------------------------------------------------------------
-
-{-# INLINE transform #-}
-transform :: Storable a => Stream a -> ()
-transform = eval
-
-{-# INLINE composeN #-}
-composeN :: Int -> (Stream Int -> Stream Int) -> Stream Int -> ()
-composeN n f =
-    case n of
-        1 -> transform . f
-        2 -> transform . f . f
-        3 -> transform . f . f . f
-        4 -> transform . f . f . f . f
-        _ -> undefined
-
-{-# INLINE scan #-}
-{-# INLINE map #-}
-{-# INLINE mapM #-}
-{-# INLINE filterEven #-}
-{-# INLINE filterAllOut #-}
-{-# INLINE filterAllIn #-}
-{-# INLINE takeOne #-}
-{-# INLINE takeAll #-}
-{-# INLINE takeWhileTrue #-}
-{-# INLINE dropOne #-}
-{-# INLINE dropAll #-}
-{-# INLINE dropWhileTrue #-}
-{-# INLINE dropWhileFalse #-}
-scan, map, mapM,
-    filterEven, filterAllOut, filterAllIn,
-    takeOne, takeAll, takeWhileTrue,
-    dropOne, dropAll, dropWhileTrue, dropWhileFalse
-    :: Int -> Stream Int -> ()
-
-scan           n = composeN n $ S.scanl' (+) 0
-map            n = composeN n $ S.map (+1)
-mapM             = map
-filterEven     n = composeN n $ S.filter even
-filterAllOut   n = composeN n $ S.filter (> maxValue)
-filterAllIn    n = composeN n $ S.filter (<= maxValue)
-takeOne        n = composeN n $ S.take 1
-takeAll        n = composeN n $ S.take maxValue
-takeWhileTrue  n = composeN n $ S.takeWhile (<= maxValue)
-dropOne        n = composeN n $ S.drop 1
-dropAll        n = composeN n $ S.drop maxValue
-dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
-dropWhileTrue  n = composeN n $ S.dropWhile (<= maxValue)
-
--------------------------------------------------------------------------------
--- Iteration
--------------------------------------------------------------------------------
-
-iterStreamLen, maxIters :: Int
-iterStreamLen = 10
-maxIters = 100000
-
-{-# INLINE iterateSource #-}
-iterateSource :: (Stream Int -> Stream Int) -> Int -> Int -> Stream Int
-iterateSource g i n = f i (sourceN iterStreamLen n)
-    where
-        f (0 :: Int) m = g m
-        f x m = g (f (x P.- 1) m)
-
-{-# INLINE iterateScan #-}
-{-# INLINE iterateFilterEven #-}
-{-# INLINE iterateTakeAll #-}
-{-# INLINE iterateDropOne #-}
-{-# INLINE iterateDropWhileFalse #-}
-{-# INLINE iterateDropWhileTrue #-}
-iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
-    iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Int
-
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `P.div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `P.div` 100) n
-
-iterateFilterEven n = iterateSource (S.filter even) maxIters n
-iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
-iterateDropOne n = iterateSource (S.drop 1) maxIters n
-iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
-
--------------------------------------------------------------------------------
--- Mixed Composition
--------------------------------------------------------------------------------
-
-{-# INLINE scanMap #-}
-{-# INLINE dropMap #-}
-{-# INLINE dropScan #-}
-{-# INLINE takeDrop #-}
-{-# INLINE takeScan #-}
-{-# INLINE takeMap #-}
-{-# INLINE filterDrop #-}
-{-# INLINE filterTake #-}
-{-# INLINE filterScan #-}
-{-# INLINE filterMap #-}
-scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
-    filterTake, filterScan, filterMap
-    :: Int -> Stream Int -> ()
-
-scanMap    n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
-dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
-dropScan   n = composeN n $ S.scanl' (+) 0 . S.drop 1
-takeDrop   n = composeN n $ S.drop 1 . S.take maxValue
-takeScan   n = composeN n $ S.scanl' (+) 0 . S.take maxValue
-takeMap    n = composeN n $ S.map (subtract 1) . S.take maxValue
-filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
-filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
-filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
-filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
-
--------------------------------------------------------------------------------
--- Zipping and concat
--------------------------------------------------------------------------------
-
-#define STORABLE_VECTOR
-{-# INLINE zip #-}
-#ifndef STORABLE_VECTOR
-zip :: Stream Int -> ()
-zip src = P.foldr (\(x,y) xs -> P.seq x (P.seq y xs)) ()
-    $ S.zipWith (,) src src
-#else
-zip :: Stream Int -> Stream Int
-zip src = S.zipWith (+) src src
-#endif
+import Benchmarks.DefaultMain (defaultMain)
+#define VECTOR_BOXED
+#include "VectorCommon.hs"
 
-{-# INLINE concatMap #-}
-concatMap :: Stream Int -> ()
-concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+main :: P.IO ()
+main = $(defaultMain "Vector")
diff --git a/Benchmarks/VectorCommon.hs b/Benchmarks/VectorCommon.hs
new file mode 100644
--- /dev/null
+++ b/Benchmarks/VectorCommon.hs
@@ -0,0 +1,230 @@
+-- |
+-- Module      : Benchmarks.Vector
+-- Copyright   : (c) 2018 Harendra Kumar
+--
+-- License     : MIT
+-- Maintainer  : harendra.kumar@gmail.com
+
+-- {-# LANGUAGE CPP #-}
+-- {-# LANGUAGE ScopedTypeVariables #-}
+
+import Benchmarks.Common (value, maxValue, appendValue)
+import Prelude (Int, (+), ($), (.), even, (>), (<=), subtract, undefined,
+                maxBound, Maybe(..))
+import qualified Prelude as P
+
+#ifdef VECTOR_BOXED
+import qualified Data.Vector as S
+#define CONSTRAINT(a)
+#elif defined (VECTOR_UNBOXED)
+#define CONSTRAINT(a) S.Unbox a =>
+import qualified Data.Vector.Unboxed as S
+#else
+#define CONSTRAINT(a) Storable a =>
+import Foreign.Storable (Storable)
+import qualified Data.Vector.Storable as S
+#endif
+
+-------------------------------------------------------------------------------
+-- Stream generation and elimination
+-------------------------------------------------------------------------------
+
+type Stream = S.Vector
+
+{-# INLINE source #-}
+source :: Int -> Stream Int
+-- source v = S.fromList [v..v+value]
+
+source n = let v = S.unfoldr step n in v S.++ S.singleton (S.unsafeLast v)
+    where
+    step cnt =
+        if cnt > n + value
+        then Nothing
+        else (Just (cnt, cnt + 1))
+
+{-# INLINE sourceN #-}
+sourceN :: Int -> Int -> Stream Int
+sourceN count begin = let v = S.unfoldr step begin in v S.++ S.singleton (S.unsafeLast v)
+    where
+    step i =
+        if i > begin + count
+        then Nothing
+        else (Just (i, i + 1))
+
+-------------------------------------------------------------------------------
+-- Append
+-------------------------------------------------------------------------------
+
+{-# INLINE appendSourceR #-}
+appendSourceR :: Int -> ()
+appendSourceR n =
+    toNull $ P.foldr (S.++) S.empty (P.map S.singleton [n..n+appendValue])
+
+{-# INLINE appendSourceL #-}
+appendSourceL :: Int -> ()
+appendSourceL n =
+    toNull $ P.foldl (S.++) S.empty (P.map S.singleton [n..n+appendValue])
+
+-------------------------------------------------------------------------------
+-- Elimination
+-------------------------------------------------------------------------------
+
+-- Using NFData for evaluation may be fraught with problems because of a
+-- non-optimal implementation of NFData instance. So we just evaluate each
+-- element of the stream using a fold.
+{-# INLINE eval #-}
+eval :: CONSTRAINT(a) Stream a -> ()
+eval = S.foldr P.seq ()
+
+-- eval foldable
+{-# INLINE evalF #-}
+evalF :: P.Foldable t => t a -> ()
+evalF = P.foldr P.seq ()
+
+{-# INLINE toNull #-}
+toNull :: Stream Int -> ()
+toNull = eval
+
+{-# INLINE toList #-}
+toList :: Stream Int -> ()
+toList = evalF . S.toList
+
+{-# INLINE foldl #-}
+foldl :: Stream Int -> Int
+foldl  = S.foldl' (+) 0
+
+{-# INLINE last #-}
+last  :: Stream Int -> Int
+last   = S.last
+
+-------------------------------------------------------------------------------
+-- Transformation
+-------------------------------------------------------------------------------
+
+{-# INLINE transform #-}
+transform :: CONSTRAINT(a) Stream a -> ()
+transform = eval
+
+{-# INLINE composeN #-}
+composeN :: Int -> (Stream Int -> Stream Int) -> Stream Int -> ()
+composeN n f x =
+    case n of
+        1 -> (transform . f) x
+        2 -> (transform . f . f) x
+        3 -> (transform . f . f . f) x
+        4 -> let v = (f . f . f . f) x in transform (v S.++ S.singleton (S.unsafeLast v))
+        _ -> undefined
+
+{-# INLINE scan #-}
+{-# INLINE map #-}
+{-# INLINE mapM #-}
+{-# INLINE filterEven #-}
+{-# INLINE filterAllOut #-}
+{-# INLINE filterAllIn #-}
+{-# INLINE takeOne #-}
+{-# INLINE takeAll #-}
+{-# INLINE takeWhileTrue #-}
+{-# INLINE dropOne #-}
+{-# INLINE dropAll #-}
+{-# INLINE dropWhileTrue #-}
+{-# INLINE dropWhileFalse #-}
+scan, map, mapM,
+    filterEven, filterAllOut, filterAllIn,
+    takeOne, takeAll, takeWhileTrue,
+    dropOne, dropAll, dropWhileTrue, dropWhileFalse
+    :: Int -> Stream Int -> ()
+
+scan           n = composeN n $ S.scanl' (+) 0
+map            n = composeN n $ S.map (+1)
+mapM             = map
+filterEven     n = composeN n $ S.filter even
+filterAllOut   n = composeN n $ S.filter (> maxValue)
+filterAllIn    n = composeN n $ S.filter (<= maxValue)
+takeOne        n = composeN n $ S.take 1
+takeAll        n = composeN n $ S.take maxValue
+takeWhileTrue  n = composeN n $ S.takeWhile (<= maxValue)
+dropOne        n = composeN n $ S.drop 1
+dropAll        n = composeN n $ S.drop maxValue
+dropWhileFalse n = composeN n $ S.dropWhile (> maxValue)
+dropWhileTrue  n = composeN n $ S.dropWhile (<= maxValue)
+
+-------------------------------------------------------------------------------
+-- Iteration
+-------------------------------------------------------------------------------
+
+iterStreamLen, maxIters :: Int
+iterStreamLen = 10
+maxIters = 100000
+
+{-# INLINE iterateSource #-}
+iterateSource :: (Stream Int -> Stream Int) -> Int -> Int -> Stream Int
+iterateSource g i n = f i (sourceN iterStreamLen n)
+    where
+        f (0 :: Int) m = g m
+        f x m = g (f (x P.- 1) m)
+
+{-# INLINE iterateScan #-}
+{-# INLINE iterateFilterEven #-}
+{-# INLINE iterateTakeAll #-}
+{-# INLINE iterateDropOne #-}
+{-# INLINE iterateDropWhileFalse #-}
+{-# INLINE iterateDropWhileTrue #-}
+iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
+    iterateDropWhileFalse, iterateDropWhileTrue :: Int -> Stream Int
+
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl' (+) 0) maxIters n
+iterateFilterEven n = iterateSource (S.filter even) maxIters n
+iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
+iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxValue)) maxIters n
+iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
+
+-------------------------------------------------------------------------------
+-- Mixed Composition
+-------------------------------------------------------------------------------
+
+{-# INLINE scanMap #-}
+{-# INLINE dropMap #-}
+{-# INLINE dropScan #-}
+{-# INLINE takeDrop #-}
+{-# INLINE takeScan #-}
+{-# INLINE takeMap #-}
+{-# INLINE filterDrop #-}
+{-# INLINE filterTake #-}
+{-# INLINE filterScan #-}
+{-# INLINE filterMap #-}
+scanMap, dropMap, dropScan, takeDrop, takeScan, takeMap, filterDrop,
+    filterTake, filterScan, filterMap
+    :: Int -> Stream Int -> ()
+
+scanMap    n = composeN n $ S.map (subtract 1) . S.scanl' (+) 0
+dropMap    n = composeN n $ S.map (subtract 1) . S.drop 1
+dropScan   n = composeN n $ S.scanl' (+) 0 . S.drop 1
+takeDrop   n = composeN n $ S.drop 1 . S.take maxValue
+takeScan   n = composeN n $ S.scanl' (+) 0 . S.take maxValue
+takeMap    n = composeN n $ S.map (subtract 1) . S.take maxValue
+filterDrop n = composeN n $ S.drop 1 . S.filter (<= maxValue)
+filterTake n = composeN n $ S.take maxValue . S.filter (<= maxValue)
+filterScan n = composeN n $ S.scanl' (+) 0 . S.filter (<= maxBound)
+filterMap  n = composeN n $ S.map (subtract 1) . S.filter (<= maxValue)
+
+-------------------------------------------------------------------------------
+-- Zipping and concat
+-------------------------------------------------------------------------------
+
+#define STORABLE_VECTOR
+{-# INLINE zip #-}
+#ifndef STORABLE_VECTOR
+zip :: Stream Int -> ()
+zip src = P.foldr (\(x,y) xs -> P.seq x (P.seq y xs)) ()
+    $ S.zipWith (,) src src
+#else
+zip :: Stream Int -> Stream Int
+zip src = S.zipWith (+) src src
+#endif
+
+{-# INLINE concatMap #-}
+concatMap :: Stream Int -> ()
+concatMap src = transform $ (S.concatMap (S.replicate 3) src)
diff --git a/Benchmarks/VectorStorable.hs b/Benchmarks/VectorStorable.hs
new file mode 100644
--- /dev/null
+++ b/Benchmarks/VectorStorable.hs
@@ -0,0 +1,18 @@
+-- |
+-- Module      : Benchmarks.Vector
+-- Copyright   : (c) 2018 Harendra Kumar
+--
+-- License     : MIT
+-- Maintainer  : harendra.kumar@gmail.com
+
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Benchmarks.VectorStorable where
+
+import Benchmarks.DefaultMain (defaultMain)
+#include "VectorCommon.hs"
+
+main :: P.IO ()
+main = $(defaultMain "VectorStorable")
diff --git a/Benchmarks/VectorStreams.hs b/Benchmarks/VectorStreams.hs
--- a/Benchmarks/VectorStreams.hs
+++ b/Benchmarks/VectorStreams.hs
@@ -7,12 +7,14 @@
 -- Maintainer  : harendra.kumar@gmail.com
 
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
 
 module Benchmarks.VectorStreams where
 
+import Benchmarks.DefaultMain (defaultMain)
 import Benchmarks.Common (value, maxValue, appendValue)
 import Prelude
-       (Monad, Int, (+), ($), (.), return, even, (>), (<=), div,
+       (Monad, Int, (+), ($), (.), return, even, (>), (<=),
         subtract, undefined, Maybe(..))
 import qualified Prelude as P
 
@@ -60,12 +62,14 @@
 -------------------------------------------------------------------------------
 
 {-# INLINE appendSourceR #-}
-appendSourceR :: Monad m => Int -> Stream m Int
-appendSourceR n = P.foldr (S.++) S.empty (P.map S.singleton [n..n+appendValue])
+appendSourceR :: Int -> P.IO ()
+appendSourceR n =
+    toNull $ P.foldr (S.++) S.empty (P.map S.singleton [n..n+appendValue])
 
 {-# INLINE appendSourceL #-}
-appendSourceL :: Monad m => Int -> Stream m Int
-appendSourceL n = P.foldl (S.++) S.empty (P.map S.singleton [n..n+appendValue])
+appendSourceL :: Int -> P.IO ()
+appendSourceL n =
+    toNull $ P.foldl (S.++) S.empty (P.map S.singleton [n..n+appendValue])
 
 -------------------------------------------------------------------------------
 -- Elimination
@@ -169,15 +173,14 @@
 iterateMapM, iterateScan, iterateFilterEven, iterateTakeAll, iterateDropOne,
     iterateDropWhileFalse, iterateDropWhileTrue :: Monad m => Int -> Stream m Int
 
--- this is quadratic
-iterateScan n = iterateSource (S.scanl' (+) 0) (maxIters `div` 100) n
-iterateDropWhileFalse n =
-    iterateSource (S.dropWhile (> maxValue)) (maxIters `div` 100) n
-
+-- Scan increases the size of the stream by 1, drop 1 to not blow up the size
+-- due to many iterations.
+iterateScan n = iterateSource (S.drop 1 . S.scanl' (+) 0) maxIters n
 iterateMapM n = iterateSource (S.mapM return) maxIters n
 iterateFilterEven n = iterateSource (S.filter even) maxIters n
 iterateTakeAll n = iterateSource (S.take maxValue) maxIters n
 iterateDropOne n = iterateSource (S.drop 1) maxIters n
+iterateDropWhileFalse n = iterateSource (S.dropWhile (> maxValue)) maxIters n
 iterateDropWhileTrue n = iterateSource (S.dropWhile (<= maxValue)) maxIters n
 
 -------------------------------------------------------------------------------
@@ -220,3 +223,6 @@
 {-# INLINE concatMap #-}
 concatMap :: Monad m => Stream m Int -> m ()
 concatMap src = transform $ (S.concatMap (S.replicate 3) src)
+
+main :: P.IO ()
+main = $(defaultMain "VectorStreams")
diff --git a/Benchmarks/VectorUnboxed.hs b/Benchmarks/VectorUnboxed.hs
new file mode 100644
--- /dev/null
+++ b/Benchmarks/VectorUnboxed.hs
@@ -0,0 +1,19 @@
+-- |
+-- Module      : Benchmarks.Vector
+-- Copyright   : (c) 2018 Harendra Kumar
+--
+-- License     : MIT
+-- Maintainer  : harendra.kumar@gmail.com
+
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Benchmarks.VectorUnboxed where
+
+import Benchmarks.DefaultMain (defaultMain)
+#define VECTOR_UNBOXED
+#include "VectorCommon.hs"
+
+main :: P.IO ()
+main = $(defaultMain "VectorUnboxed")
diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,13 @@
+## 0.4.1
+
+* Support streamly-core-0.3.0 and streamly-0.11.0
+
+## 0.4.0
+
+* Add different streaming libraries under individual flags
+* Use the external bench-report package and remove the shell scripts
+* User streamly-core package (streamly-0.9.0 changes)
+
 ## 0.3.0
 
 * Simplify the README, use text tables instead of graphs.
diff --git a/Charts.hs b/Charts.hs
deleted file mode 100644
--- a/Charts.hs
+++ /dev/null
@@ -1,283 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-
-module Main where
-
-import Control.Exception (catch, ErrorCall(..))
-import Data.Char (isSpace)
-import Data.List (reverse, sortOn, isPrefixOf)
--- import Data.List (stripPrefix)
-import Data.List.Split (splitOn)
-import Data.Maybe (catMaybes)
--- import Data.Maybe (fromJust)
-import System.Exit (ExitCode(..))
-import System.Process.Typed (readProcess)
-import BenchShow
-import WithCli (withCli)
-
-import Data.List
-
-import qualified Data.Text.Lazy as T
-import qualified Data.Text.Lazy.Encoding as T
-
--- pairs of benchmark group titles and corresponding list of benchmark
--- prefixes i.e. without the package name at the end.
-charts :: [(String, [String])]
-charts =
-    [
-    ( "Elimination Operations"
-      , [
-          "elimination/drain"
-        , "elimination/last"
-        , "elimination/foldl'"
-        ]
-      )
-    , ( "Transformation Operations"
-      , [ "transformation/map"
-        , "transformation/mapM"
-        , "transformation/scan"
-        ]
-      )
-    , ( "Transformation Operations x 4"
-      , [ "transformationX4/map x 4"
-        , "transformationX4/mapM x 4"
-        , "transformationX4/scan x 4"
-        ]
-      )
-    , ( "Filtering Operations"
-      , [
-          "filtering/filter-all-out"
-        , "filtering/filter-all-in"
-        , "filtering/drop-all"
-        , "filtering/takeWhile-true"
-        , "filtering/take-all"
-        , "filtering/dropWhile-true"
-        , "filtering/filter-even"
-        , "filtering/drop-one"
-        , "filtering/dropWhile-false"
-        ]
-      )
-    , ( "Filtering Operations x 4"
-      , [
-          "filteringX4/filter-all-out x 4"
-        , "filteringX4/takeWhile-true x 4"
-        , "filteringX4/filter-all-in x 4"
-        , "filteringX4/take-all x 4"
-        , "filteringX4/filter-even x 4"
-        , "filteringX4/drop-all x 4"
-        , "filteringX4/dropWhile-true x 4"
-        , "filteringX4/dropWhile-false x 4"
-        , "filteringX4/drop-one x 4"
-        ]
-      )
-    , ( "Mixed Operations x 4"
-      , [ "mixedX4/filter-map x 4"
-        , "mixedX4/take-map x 4"
-        , "mixedX4/drop-map x 4"
-        , "mixedX4/filter-drop x 4"
-        , "mixedX4/filter-take x 4"
-        , "mixedX4/take-drop x 4"
-        , "mixedX4/scan-map x 4"
-        , "mixedX4/filter-scan x 4"
-        , "mixedX4/take-scan x 4"
-        , "mixedX4/drop-scan x 4"
-        ]
-      )
-    , ( "Iterated Operations"
-      , [ "iterated/mapM"
-        , "iterated/scan[x0.01]"
-        , "iterated/filterEven"
-        , "iterated/takeAll"
-        , "iterated/dropOne"
-        , "iterated/dropWhileFalse[x0.01]"
-        , "iterated/dropWhileTrue"
-        ]
-      )
-    , ( "Append Operations"
-      , [ "appendR"
-      --  , "appendL"
-        ]
-      )
-    , ( "Zip Operation"
-      , [ "zip"
-        ]
-      )
-    , ( "Concat Operation"
-      , [ "concatMap"
-        , "concatMapFoldable"
-        ]
-      )
-    , ( "Conversion Operations"
-      , [ "elimination/toList"
-        ]
-      )
-    ]
-
--------------------------------------------------------------------------------
-
--- returns [(packagename, version)]
-getPkgVersions :: [String] -> IO [(String, String)]
-getPkgVersions packages = do
-    (ecode, out, _) <- readProcess "stack list-dependencies --bench"
-
-    case ecode of
-        ExitSuccess -> do
-            -- Get our streaming packages and their versions
-            let match [] = Nothing
-                match (_ : []) = Nothing
-                match (x : y : _) =
-                    case elem x packages of
-                        False -> Nothing
-                        True -> Just (x, y)
-
-             in return
-                $ catMaybes
-                $ map match
-                $ map words (lines (T.unpack $ T.decodeUtf8 out))
-        ExitFailure _ -> do
-            putStrLn $ "Warning! Cannot determine package versions, "
-                ++ "the 'stack list-dependencies' command failed."
-            return []
-
--- suffix versions to packages
-suffixVersion :: [(String, String)] -> String -> String
-suffixVersion pkginfo p =
-    case lookup p pkginfo of
-        Nothing -> p
-        Just v -> p ++ "-" ++ v
-
-ignoringErr :: IO () -> IO ()
-ignoringErr a = catch a (\(ErrorCall err :: ErrorCall) ->
-    putStrLn $ "Failed with error:\n" ++ err ++ "\nSkipping.")
-
-createCharts :: String -> String -> Bool -> String -> Bool -> IO ()
-createCharts input pkgList graphs delta versions = do
-    let packages = splitOn "," pkgList
-
-    pkgInfo <-
-        if versions
-        then getPkgVersions packages
-        else return []
-
-    let cmpStyle = case delta of
-            "absolute" -> Absolute
-            "multiples" -> Multiples
-            "percent" -> PercentDiff
-            x -> error $ "Unknown compare option: " ++ show x
-
-    let bsort pxs bs =
-                let i = intersect (map (last . splitOn "/") pxs) bs
-                in i ++ (bs \\ i)
-    let cfg (t, prefixes) = defaultConfig
-            { mkTitle = Just t
-            , outputDir = Just "charts"
-            , presentation = Groups cmpStyle
-            , diffStrategy = SingleEstimator
-            , omitBaseline = True
-            , classifyBenchmark = \bm ->
-                case any (`isPrefixOf` bm) prefixes of
-                    True ->
-                        let xs = reverse (splitOn "/" bm)
-                            grp   = xs !! 0
-                            bench = xs !! 1
-                        in case grp `elem` packages of
-                                True -> Just (suffixVersion pkgInfo grp, bench)
-                                False -> Nothing
-                    False -> Nothing
-            , selectGroups = \gs ->
-                let gs' = map fst gs
-                    i = intersect (map (suffixVersion pkgInfo) packages) gs'
-                    new = i ++ (gs' \\ i)
-                in nub $ concat $ map (\x -> filter (\(y,_) -> y == x) gs) new
-            , selectBenchmarks = \g -> bsort prefixes $
-                either error (map fst) $ g (ColumnIndex 0) Nothing
-            }
-
-        -- links in README.rst eat up the space so we match the same
-    let toOutfile t = filter (not . isSpace) (takeWhile (/= '(') t)
-        packages' = packages
-    {-
-    let packages' = map (\x ->
-            if "pure-" `isPrefixOf` x
-            then fromJust (stripPrefix "pure-" x)
-            else x) packages
-
-    let selectByRegression f =
-            reverse
-          $ fmap fst
-          $ either
-              (const $ either error id $ f (ColumnIndex 0) Nothing)
-              (sortOn snd)
-              $ f (ColumnIndex 1) Nothing
-
-    let makeOneGraph infile (t, prefixes) = do
-            let title' fname =
-                        if delta /= "absolute"
-                        then t ++ " (" ++ fname ++ ") relative to " ++ packages' !! 0
-                        else t ++ " (" ++ fname ++ ") (Lower is Better)"
-                cfg' = cfg (title', prefixes)
-                cfg'' =
-                    if delta /= "absolute"
-                    then cfg' { selectBenchmarks = selectByRegression }
-                    else cfg'
-            if graphs
-            then ignoringErr $ graph infile (toOutfile t) cfg''
-            else ignoringErr $ report infile Nothing cfg''
-
-    mapM_ (makeOneGraph input) charts
-    -}
-
-    let cutOffByRegression p f =
-            let cmp = if delta == "absolute"
-                      then Multiples
-                      else cmpStyle
-            in reverse
-              $ fmap fst
-              $ filter (\(_,y) -> p y) . (sortOn snd)
-              $ either
-                  (const $ either error id $ f (ColumnIndex 0) (Just cmp))
-                  id
-                  $ f (ColumnIndex 1) (Just cmp)
-
-    -- Make a graph of all operations sorted based on performance regression in
-    -- descending order and operations below a 10% threshold filtered out.
-    let makeDiffGraph infile prefixes t p = do
-            let cfg' = (cfg (t, prefixes))
-                    { presentation = Groups cmpStyle
-                    , selectBenchmarks = cutOffByRegression p
-                    }
-            if graphs
-            then ignoringErr $ graph infile (toOutfile (t "")) cfg'
-            else ignoringErr $ report infile Nothing cfg'
-
-    -- compare two packages for best and worst operations
-    let makeTitle fname =
-            if delta /= "absolute"
-            then
-                let prefix = if delta == "percent"
-                             then "Extra % "
-                             else ""
-                    connector = if delta == "multiples"
-                             then "as multiples of"
-                             else "wrt"
-                    field = case fname of
-                        "time" -> "time taken"
-                        "maxrss" -> "memory used"
-                        x -> x
-                    pkg = if length packages' == 2
-                          then "by '" ++ packages' !! 1 ++ "'"
-                          else ""
-                in prefix ++ field ++ " " ++ pkg ++ " " ++ connector
-                    ++ " '" ++ packages' !! 0 ++ "'"
-            else fname ++ " (Lower is Better)"
-    let p x =
-            case delta of
-                "absolute" -> True
-                "multiples" -> x < (-1.1) || x > 1.1
-                "percent" -> x < (-10) || x > 10
-                y -> error $ "Unknown compare option: " ++ show y
-    makeDiffGraph input (concatMap snd charts) makeTitle p
-
--- Pass <input file> <comma separated list of packages> <True/False>
-main :: IO ()
-main = withCli createCharts
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 This package provides micro-benchmarks to measure and compare the
 performance of various streaming implementations in Haskell.
 
-We have taken due to care to make sure that we are
+We have taken due care to make sure that we are
 benchmarking correctly and fairly. See [the notes on correct
 benchmarking](docs/benchmarking-notes.md).
 
@@ -56,25 +56,37 @@
 each library's code to the best of our knowledge, please point out if
 you find any measurement issues.
 
-### Reproducing benchmark results
+## Running Benchmarks
 
-Commands to reproduce the benchmark results are provided in each section
-below. But before you run those commands you need to build the reporting
-tool once using the following command. Note that this command works with
-only ghc-8.8.4 or lower. However, after building this tool you can run
-the benchmarks with any GHC version.
+You can run individual benchmarks using `cabal bench <target>`. You may
+need to specify a build flag to include a particular streaming library
+e.g. `--flag pipes` to benchmark the `pipes` library. Please consult the cabal
+file to find the exact flag names.
 
+### Generating Comparison Reports
+
+You can generate the comparison reports presented in this page yourself.
+To do so you need to run the benchmarks using the reporting tool, first build
+the reporting tool using the following command:
+
 ```
-$ cabal install --flag dev --installdir charts --with-compiler ghc-8.8.4 bench-report
+$ cd bench-runner
+$ cabal install --project-file cabal.project.user --installdir ../bin
 ```
 
-Nix users can use bench-report.nix. It uses an older version of nixpkgs that
-contains the required dependencies:
+If you want to create a report for benchmarks showing a 10% or greater
+improvement with Streamly over Lists, use:
 
 ```
-$ nix-shell bench-report.nix --run "cabal install --flag dev --installdir charts bench-report"
+$ bin/bench-runner --package-name streaming-benchmarks --package-version 0.4.0 --compare --diff-cutoff-percent 10 --diff-style absolute --targets "StreamlyPure List"
 ```
 
+After running once, you can add `--no-measure` option to use the same benchmark
+measurements for different reports.  For example, use:
+
+* `--diff-cutoff-percent -10` to know where lists are better than streamly
+* `--diff-style multiples` to generate ratios instead of absolute values
+
 ### Streamly vs Haskell Lists
 
 Streamly, when used with `Identity` monad, is almost the same as Haskell lists
@@ -86,7 +98,8 @@
 [streamly](https://github.com/composewell/streamly)
 with lists using a one million element stream.  For brevity only
 those operations where the performance of the two packages differ by
-more than 10% are shown in the table below.
+more than 10% are shown in the table below. The last column shows how
+many times slower list is compared to streamly.
 
 | Benchmark           | streamly(μs) |  list(μs)  | list/streamly |
 | ------------------- | ------------ | ---------- | ------------- |
@@ -112,12 +125,9 @@
 
 * streamly-0.8.0, base-4.14.1.0, ghc-8.10.4, Linux
 
-To reproduce these results use the following commands:
+To generate these reports run `bench-runner` with:
 
-```
-$ ./bench.sh --benchmarks "pure-streamly,list" --measure
-$ ./bench.sh --benchmarks "pure-streamly,list" --diff multiples
-```
+* `--targets "StreamlyPure List"`
 
 ### Streamly vs Streaming
 
@@ -168,12 +178,9 @@
 
 * streamly-0.8.0, streaming-0.2.3.0, ghc-8.10.4, Linux
 
-To reproduce these results use the following commands:
+To generate these reports run `bench-runner` with:
 
-```
-$ ./bench.sh --benchmarks "streamly,streaming" --measure
-$ ./bench.sh --benchmarks "streamly,streaming" --diff multiples
-```
+* `--targets "Streamly Streaming" --cabal-build-options "--flag streaming"`
 
 ### Streamly vs Pipes
 
@@ -224,12 +231,9 @@
 
 * streamly-0.8.0, pipes-4.3.16, ghc-8.10.4, Linux
 
-To reproduce these results use the following commands:
+To generate these reports run `bench-runner` with:
 
-```
-$ ./bench.sh --benchmarks "streamly,pipes" --measure
-$ ./bench.sh --benchmarks "streamly,pipes" --diff multiples
-```
+* `--targets "Streamly Pipes" --cabal-build-options "--flag pipes"`
 
 ### Streamly vs Conduit
 
@@ -280,31 +284,24 @@
 
 * streamly-0.8.0, conduit-1.3.4.1, ghc-8.10.4, Linux
 
-To reproduce these results use the following commands:
-
-```
-$ ./bench.sh --benchmarks "streamly,conduit" --measure
-$ ./bench.sh --benchmarks "streamly,conduit" --diff multiples
-```
+To generate these reports run `bench-runner` with:
 
-## Comparing other libraries
+* `--targets "Streamly Conduit" --cabal-build-options "--flag conduit"`
 
-This package supports many streaming libraries. Use the following command to
-see all available benchmarks:
+## Stack and heap utilization
 
-```
-$ ./bench.sh --help
-```
+`bench-runner` also generates a `maxrss` comparison report, displaying the
+maximum resident memory for each benchmark.
 
-You can then select the libraries you want to compare:
+## Comparing other libraries
 
-```
-$ ./bench.sh --benchmarks "streaming,pipes" --measure
-```
+This package supports many streaming libraries, bytestring, text, vector etc.
+You can run the benchmarks directly or use `bench-runner` to create comparison
+reports. Check out the targets in the cabal file.
 
 ## Adding New Libraries
 
-It is trivial to add a new package. This is how 
+It is trivial to add a new package. This is how
 [a benchmark file](https://github.com/composewell/streaming-benchmarks/blob/master/Benchmarks/Streamly.hs)
 for a streaming package looks like. Pull requests are welcome, we will be happy
 to help, [just join the gitter chat](https://gitter.im/composewell/streamly)
diff --git a/bench-report.nix b/bench-report.nix
deleted file mode 100644
--- a/bench-report.nix
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  nixpkgs ?
-    # nixpkgs 21.05 needs a revised version of bench-show and we do not
-    # know how to use a revised version in nix.
-    #import (builtins.fetchTarball https://github.com/NixOS/nixpkgs/archive/refs/tags/21.05.tar.gz)
-    import (builtins.fetchTarball https://github.com/composewell/nixpkgs/archive/01dd2b4e738.tar.gz)
-        {}
-#, compiler ? "ghc884" # For nix 21.05
-, compiler ? "default"
-}:
-let haskellPackages =
-        if compiler == "default"
-        then nixpkgs.haskellPackages
-        else nixpkgs.haskell.packages.${compiler};
-
-    mkPackage = super: pkg: path: opts: inShell:
-                let orig = super.callCabal2nixWithOptions pkg path opts {};
-                 in if inShell
-                    # Avoid copying the source directory to nix store by using
-                    # src = null.
-                    then orig.overrideAttrs (oldAttrs: { src = null; })
-                    else orig;
-
-    mkHaskellPackages = inShell:
-        haskellPackages.override {
-            overrides = self: super:
-                with nixpkgs.haskell.lib;
-                {
-                    streaming-benchmarks = mkPackage super "streaming-benchmarks" ./. "--flag dev" inShell;
-                };
-        };
-
-    drv = mkHaskellPackages true;
-
-    shell = drv.shellFor {
-        packages = p:
-          [ p.streaming-benchmarks
-          ];
-        # Use a better prompt
-        shellHook = ''
-          export CABAL_DIR="$(pwd)/.cabal.nix"
-          if test -n "$PS_SHELL"
-          then
-            export PS1="$PS_SHELL\[$bldred\](nix)\[$txtrst\] "
-          fi
-        '';
-    };
-in if nixpkgs.lib.inNixShell
-   then shell
-   else (mkHaskellPackages false).streaming-benchmarks
diff --git a/bench-runner/Main.hs b/bench-runner/Main.hs
new file mode 100644
--- /dev/null
+++ b/bench-runner/Main.hs
@@ -0,0 +1,60 @@
+module Main (main) where
+
+import BenchRunner (mainWith)
+import BuildLib (Quickness(..))
+import Control.Applicative ((<|>))
+import Data.List (isInfixOf, isPrefixOf, isSuffixOf)
+
+-- tags with _grp and _cmp suffixes are special
+ -- [(<benchmark name>", [<tags>])]
+targets :: [(String, [String])]
+targets =
+    [ ("StreamlyPure", ["pure_stream_cmp"])
+    , ("List", ["pure_stream_cmp"])
+    , ("Streamly", ["io_stream_cmp"])
+    , ("ByteStringLazy", ["io_stream_cmp"])
+    , ("VectorStreams", [])
+    -- , ("Streaming", [])
+    -- , ("Machines", [])
+    -- , ("Pipes", [])
+    -- , ("Conduit", [])
+    -- , ("Drinkery", [])
+    ]
+
+rtsOpts :: String -> String -> String
+rtsOpts exeName benchName0 = unwords [general, exeSpecific, benchSpecific]
+
+    where
+
+    -- Drop All.
+    benchName = drop 4 benchName0
+    general
+        -- | "o-1-sp" `isInfixOf` benchName = "-K36K -M16M"
+        | otherwise = ""
+    exeSpecific
+        -- | "Prelude.Concurrent" `isSuffixOf` exeName = "-K512K -M384M"
+        | otherwise = ""
+    benchSpecific
+        -- | "Data.Stream.StreamD/o-n-space.elimination.toList" == benchName = "-K2M"
+        | otherwise = ""
+
+speedOpts :: String -> String -> Maybe Quickness
+speedOpts exeName benchName0 = exeSpecific <|> benchSpecific
+
+    where
+
+    -- slowestOf Quicker _ = Quicker
+    -- slowestOf _ Quicker = Quicker
+    -- slowestOf _ _ = SuperQuick
+
+    -- Drop All.
+    benchName = drop 4 benchName0
+    exeSpecific
+        -- | "Prelude.Concurrent" == exeName = Just SuperQuick
+        | otherwise = Nothing
+    benchSpecific
+        -- | "Prelude.Parallel/o-n-heap.mapping.mapM" == benchName = Just SuperQuick
+        | otherwise = Nothing
+
+main :: IO ()
+main = mainWith targets speedOpts rtsOpts
diff --git a/bench-runner/bench-runner.cabal b/bench-runner/bench-runner.cabal
new file mode 100644
--- /dev/null
+++ b/bench-runner/bench-runner.cabal
@@ -0,0 +1,41 @@
+cabal-version:      2.4
+name:               bench-runner
+version:            0.1.0.0
+
+-- A short (one-line) description of the package.
+-- synopsis:
+
+-- A longer description of the package.
+-- description:
+
+-- A URL where users can report bugs.
+-- bug-reports:
+
+-- The license under which the package is released.
+-- license:
+
+-- The package author(s).
+-- author:
+
+-- An email address to which users can send suggestions, bug reports, and patches.
+-- maintainer:
+
+-- A copyright notice.
+-- copyright:
+-- category:
+-- extra-source-files: CHANGELOG.md
+
+executable bench-runner
+    ghc-options: -Wall
+    main-is:          Main.hs
+
+    -- Modules included in this executable, other than Main.
+    -- other-modules:
+
+    -- LANGUAGE extensions used by modules in this package.
+    -- other-extensions:
+    build-depends:    base
+                    , bench-report
+                    , containers
+    hs-source-dirs:   .
+    default-language: Haskell2010
diff --git a/bench-runner/cabal.project.user b/bench-runner/cabal.project.user
new file mode 100644
--- /dev/null
+++ b/bench-runner/cabal.project.user
@@ -0,0 +1,35 @@
+packages: .
+
+package bench-report
+  flags: +no-charts
+
+source-repository-package
+  type: git
+  location: https://github.com/composewell/streamly-coreutils.git
+  tag: fa180060c7510c89d2767980ca6f7ec7011d04b9
+
+source-repository-package
+  type: git
+  location: https://github.com/composewell/bench-report.git
+  tag: 4dad3ea916a950524bcfd5097fc6f0f63e645987
+
+-- source-repository-package
+--   type: git
+--   location: https://github.com/composewell/streamly.git
+--   tag: 9a039b89c6b81300b2bd9c8765bf4bfa18e7c83c
+-- 
+-- source-repository-package
+--   type: git
+--   location: https://github.com/composewell/streamly.git
+--   tag: 9a039b89c6b81300b2bd9c8765bf4bfa18e7c83c
+--   subdir: core
+-- 
+-- source-repository-package
+--   type: git
+--   location: https://github.com/composewell/streamly-process.git
+--   tag: c1ce40ebe84973d0c54dd27fb17e337bf9ca4a46
+-- 
+-- source-repository-package
+--   type: git
+--   location: https://github.com/composewell/streamly-shell.git
+--   tag: 070ff21fda7aab8ca45b08b330746299a91eb981
diff --git a/bench.sh b/bench.sh
deleted file mode 100644
--- a/bench.sh
+++ /dev/null
@@ -1,325 +0,0 @@
-#!/bin/bash
-
-print_help () {
-  echo "Usage: $0 "
-  echo "       [--benchmarks <streamly,vector,...>]"
-  echo "       [--diff <percent|multiples>]"
-  echo "       [--graphs]"
-  echo "       [--measure]"
-  echo "       [--append] "
-  echo "       [--slow]"
-  echo "       [--fast]"
-  echo "       [--versions] "
-  echo "       [--stack] "
-  echo "       -- <gauge options>"
-  echo
-  echo "--benchmarks: specify comma separated list of packages to be compared"
-  echo
-  echo "Available benchmarks are: "
-  echo "Pure streams: list, pure-streamly, vector, sequence, dlist, bytestring, text"
-  echo "Monadic streams: streamly, streams-vector, streaming, pipes, conduit, machines, drinkery"
-  echo
-  echo "--graphs: generate SVG graphs instead of text reports"
-  echo "--diff: show diff of subsequent packages from the first package"
-  echo "--slow: slower but a bit more precise benchmarking"
-  echo "--fast: faster but a bit less precise benchmarking"
-  echo "--measure: rerun benchmark measurements"
-  echo "--append: append the new measurement results to previous ones for comparison"
-  echo "--versions: add package versions in the report/graphs"
-  echo "--stack: use stack for build and benchmark"
-  echo
-  echo "Any arguments after a '--' are passed directly to guage"
-  exit
-}
-
-# $1: message
-die () {
-  >&2 echo -e "Error: $1"
-  exit 1
-}
-
-set_benchmarks() {
-  if test -z "$BENCHMARKS"
-  then
-    BENCHMARKS=$DEFAULT_BENCHMARKS
-  elif test "$BENCHMARKS" = "all"
-  then
-    BENCHMARKS=$ALL_BENCHMARKS
-  fi
-  echo "Using benchmark suites [$BENCHMARKS]"
-}
-
-# $1: benchmark name (linear, nested, base)
-find_report_prog() {
-    local prog_name="bench-report"
-    hash -r
-    local prog_path=$($WHICH_COMMAND $prog_name)
-    if test -x "$prog_path"
-    then
-      echo $prog_path
-    else
-      if test -x "charts/$prog_name"
-      then echo "charts/$prog_name"
-      else
-        return 1
-      fi
-    fi
-}
-
-# $1: benchmark name (linear, nested, base)
-build_report_prog() {
-    local prog_name="bench-report"
-    local prog_path=$($WHICH_COMMAND $prog_name)
-
-    hash -r
-    if test -x "charts/$prog_name"
-    then return 0
-    fi
-    if test ! -x "$prog_path" -a "$BUILD_ONCE" = "0"
-    then
-      echo "Building bench-show executable"
-      BUILD_ONCE=1
-      $BUILD_CHART_EXE || die "build failed"
-      if test "$USE_STACK" -ne 1
-      then
-        cabal install --flag dev --installdir=charts bench-report
-      fi
-    elif test ! -x "$prog_path"
-    then
-      return 1
-    fi
-    return 0
-}
-
-build_report_progs() {
-  if test "$RAW" = "0"
-  then
-      build_report_prog || exit 1
-      local prog
-      prog=$(find_report_prog) || \
-          die "Cannot find bench-show executable"
-      echo "Using bench-show executable [$prog]"
-  fi
-}
-
-# We run the benchmarks in isolation in a separate process so that different
-# benchmarks do not interfere with other. To enable that we need to pass the
-# benchmark exe path to guage as an argument. Unfortunately it cannot find its
-# own path currently.
-
-# The path is dependent on the architecture and cabal version.
-# Use this command to find the exe if this script fails with an error:
-# find .stack-work/ -type f -name "benchmarks"
-
-stack_bench_prog () {
-  local bench_name=$1
-  local bench_prog=`stack path --dist-dir`/build/$bench_name/$bench_name
-  if test -x "$bench_prog"
-  then
-    echo $bench_prog
-  else
-    return 1
-  fi
-}
-
-cabal_bench_prog () {
-  local bench_name=$1
-  local bench_prog=`$WHICH_COMMAND $1`
-  if test -x "$bench_prog"
-  then
-    echo $bench_prog
-  else
-    return 1
-  fi
-}
-
-bench_output_file() {
-    echo "charts/results.csv"
-}
-
-# --min-duration 0 means exactly one iteration per sample. We use a million
-# iterations in the benchmarking code explicitly and do not use the iterations
-# done by the benchmarking tool.
-#
-# Benchmarking tool by default discards the first iteration to remove
-# aberrations due to initial evaluations etc. We do not discard it because we
-# are anyway doing iterations in the benchmarking code and many of them so that
-# any constant factor gets amortized and anyway it is a cost that we pay in
-# real life.
-#
-# We can pass --min-samples value from the command line as second argument
-# after the benchmark name in case we want to use more than one sample.
-
-run_bench () {
-  local bench_name=$1
-  local output_file=$(bench_output_file $bench_name)
-  local bench_prog
-  bench_prog=$($GET_BENCH_PROG $bench_name) || \
-    die "Cannot find benchmark executable for benchmark $bench_name"
-
-  mkdir -p `dirname $output_file`
-
-  echo "Running benchmark $bench_name ..."
-
-  local MATCH_ARGS=""
-  for i in $(echo $BENCHMARKS | tr "," "\n")
-  do
-     MATCH_ARGS="$MATCH_ARGS -m pattern /$i"
-  done
-
-  $bench_prog $SPEED_OPTIONS \
-    --csvraw=$output_file \
-    -v 2 \
-    --measure-with $bench_prog $MATCH_ARGS $GAUGE_ARGS \
-      || die "Benchmarking failed"
-}
-
-run_benches() {
-    for i in $1
-    do
-      run_bench $i
-    done
-}
-
-backup_output_file() {
-  local bench_name=$1
-  local output_file=$(bench_output_file $bench_name)
-
-  if test -e $output_file -a "$APPEND" != 1
-  then
-      mv -f -v $output_file ${output_file}.prev
-  fi
-}
-
-run_measurements() {
-  local bench_list=$1
-  local to_run
-
-  for i in $bench_list
-  do
-    local output_file=$(bench_output_file $i)
-    if test "$MEASURE" = 1 -o ! -e $output_file
-    then
-      backup_output_file $i
-      to_run="$to_run $i"
-    fi
-  done
-
-  run_benches "$to_run"
-}
-
-run_reports() {
-    local prog
-    prog=$(find_report_prog) || \
-      die "Cannot find bench-graph executable"
-    echo
-
-    local output_file=$(bench_output_file)
-    echo "Generating reports for ${output_file}..."
-    $prog $output_file $1 $GRAPH $DELTA $VERSIONS
-}
-
-#-----------------------------------------------------------------------------
-# Execution starts here
-#-----------------------------------------------------------------------------
-
-DEFAULT_BENCHMARKS="streamly,streaming,conduit,pipes,machines"
-ALL_BENCHMARKS="streamly,vector,streaming,conduit,pipes,machines,drinkery"
-DELTA="absolute"
-
-APPEND=0
-RAW=0
-GRAPH=False
-VERSIONS=False
-MEASURE=0
-SPEED_OPTIONS="--quick --min-samples 10 --time-limit 1 --min-duration 0"
-
-GAUGE_ARGS=
-BUILD_ONCE=0
-USE_STACK=0
-
-GHC_VERSION=$(ghc --numeric-version)
-STREAMING_BENCHMARKS_VERSION=0.3.0
-
-cabal_which() {
-  find dist-newstyle -type f -path \
-  "*${GHC_VERSION}/streaming-benchmarks-$STREAMING_BENCHMARKS_VERSION/*/$1"
-}
-
-#-----------------------------------------------------------------------------
-# Read command line
-#-----------------------------------------------------------------------------
-
-while test -n "$1"
-do
-  case $1 in
-    -h|--help|help) print_help ;;
-    # options with arguments
-    --slow) SPEED_OPTIONS="--min-duration 0"; shift ;;
-    --fast) SPEED_OPTIONS="--quick --min-samples 1 --min-duration 0 --include-first-iter"
-            shift ;;
-    --append) APPEND=1; shift ;;
-    --benchmarks) shift; BENCHMARKS=$1; shift ;;
-    --diff) shift; DELTA=$1; shift ;;
-    --raw) RAW=1; shift ;;
-    --graphs) GRAPH=True; shift ;;
-    --versions) VERSIONS=True; shift ;;
-    --stack) USE_STACK=1; shift ;;
-    --measure) MEASURE=1; shift ;;
-    --) shift; break ;;
-    -*|--*) print_help ;;
-    *) break ;;
-  esac
-done
-GAUGE_ARGS=$*
-
-if test "$USE_STACK" = "1"
-then
-  WHICH_COMMAND="stack exec which"
-  GET_BENCH_PROG=stack_bench_prog
-  BUILD_CHART_EXE="stack build"
-  BUILD_BENCH="stack build $STACK_BUILD_FLAGS --bench --no-run-benchmarks"
-else
-  # XXX cabal issue "cabal v2-exec which" cannot find benchmark/test executables
-  #WHICH_COMMAND="cabal v2-exec which"
-  WHICH_COMMAND=cabal_which
-  GET_BENCH_PROG=cabal_bench_prog
-  BUILD_CHART_EXE="cabal v2-build --flag dev bench-report"
-  BUILD_BENCH="cabal v2-build $CABAL_BUILD_FLAGS --enable-benchmarks all"
-fi
-
-# echo "Using stack command [$STACK]"
-set_benchmarks
-
-#-----------------------------------------------------------------------------
-# Build stuff
-#-----------------------------------------------------------------------------
-
-# We need to build the report progs first at the current (latest) commit before
-# checking out any other commit for benchmarking.
-#build_report_progs "$BENCHMARKS"
-
-if test ! -e charts/bench-report
-then
-  echo "Please build the bench-report executable first."
-  echo "It requires ghc-8.8.4 or earlier"
-  echo
-  echo "cabal install --flag dev --installdir charts --with-compiler ghc-8.8.4 bench-report"
-  exit
-fi
-
-#-----------------------------------------------------------------------------
-# Run benchmarks
-#-----------------------------------------------------------------------------
-
-$BUILD_BENCH || die "build failed"
-run_measurements bmarks
-
-#-----------------------------------------------------------------------------
-# Run reports
-#-----------------------------------------------------------------------------
-
-if test "$RAW" = "0"
-then
-  run_reports "$BENCHMARKS"
-fi
diff --git a/lib/Benchmarks/BenchTH.hs b/lib/Benchmarks/BenchTH.hs
new file mode 100644
--- /dev/null
+++ b/lib/Benchmarks/BenchTH.hs
@@ -0,0 +1,111 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Benchmarks.BenchTH
+    ( mkBench
+    , mkBenchIO
+    , mkBenchN
+    , purePackages
+    , monadicPackages
+    , monadicArrays
+    , allPackages
+    ) where
+
+import Benchmarks.Common
+    (benchIO, benchIOAction, benchPure, benchPureFunc, benchIOArray)
+import Language.Haskell.TH.Syntax (Q, Exp, mkName)
+import Language.Haskell.TH.Lib (varE)
+
+-- First item in the tuple is the module name and the second one is the
+-- corresponding benchmark group name.
+--
+monadicPackages :: [(String, String)]
+monadicPackages =
+    [ ("Streamly", "streamly")
+    , ("VectorStreams", "streams-vector")
+    , ("Streaming", "streaming")
+    , ("Machines", "machines")
+    , ("Pipes", "pipes")
+    , ("Conduit", "conduit")
+    , ("Drinkery", "drinkery")
+    ]
+
+purePackages :: [(String, String)]
+purePackages =
+    [ -- stream like packages
+      ("List", "list")
+    , ("StreamlyPure", "pure-streamly")
+    , ("DList", "dlist")
+    , ("Sequence", "sequence")
+    , ("ByteStringLazy", "lazy-bytestring")
+
+    -- array like packages
+    , ("ByteString", "bytestring")
+    , ("Text", "text")
+    , ("Vector", "vector")
+    , ("VectorUnboxed", "unboxed-vector")
+    , ("VectorStorable", "storable-vector")
+    ]
+
+monadicArrays :: [(String, String)]
+monadicArrays = [("StreamlyArray", "array-streamly")]
+
+allPackages :: [(String, String)]
+allPackages =
+       purePackages
+    ++ monadicPackages
+    ++ monadicArrays
+
+-- mkBench <stream producer func> <stream consumer func> <module name>
+-- <bench name>
+mkBench :: String -> String -> String -> String -> Q Exp
+mkBench f x mdl bname =
+    case lookup mdl purePackages of
+        Nothing -> case lookup mdl monadicPackages of
+            Just _ ->
+                [| benchIO bname $(varE (mkName f)) $(varE (mkName x)) |]
+            Nothing ->
+                if mdl == "StreamlyArray"
+                then
+                    [| benchIOArray bname
+                            $(varE (mkName f))
+                            $(varE (mkName x))
+                    |]
+                else error $
+                    "module " ++ show mdl ++ " not found in module list"
+        Just _ ->
+                [| benchPure bname $(varE (mkName f)) $(varE (mkName x)) |]
+
+mkBenchN :: String -> String -> Int -> String -> String -> Q Exp
+mkBenchN f x n mdl bname =
+    case lookup mdl purePackages of
+        Nothing -> case lookup mdl monadicPackages of
+            Just _ ->
+                [| benchIO bname $(varE (mkName f)) ($(varE (mkName x)) n) |]
+            Nothing ->
+                if mdl == "StreamlyArray"
+                then
+                    [| benchIOArray bname
+                            $(varE (mkName f))
+                            ($(varE (mkName x)) n)
+                    |]
+                else
+                    error $
+                        "module " ++ show mdl ++ " not found in module list"
+        Just _ ->
+                [| benchPure bname $(varE (mkName f)) ($(varE (mkName x)) n)
+                |]
+
+mkBenchIO :: String -> String -> String -> Q Exp
+mkBenchIO action mdl bname =
+    case lookup mdl purePackages of
+        Nothing -> case lookup mdl monadicPackages of
+            Just _ ->
+                [| benchIOAction bname $(varE (mkName action)) |]
+            Nothing ->
+                if mdl == "StreamlyArray"
+                then
+                    [| benchIOArray "array-streamly" $(varE (mkName action)) |]
+                else error $
+                    "module " ++ show mdl ++ " not found in module list"
+        Just _ ->
+                [| benchPureFunc bname $(varE (mkName action)) |]
diff --git a/lib/Benchmarks/BenchmarkTH.hs b/lib/Benchmarks/BenchmarkTH.hs
new file mode 100644
--- /dev/null
+++ b/lib/Benchmarks/BenchmarkTH.hs
@@ -0,0 +1,94 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE DeriveLift #-}
+
+module Benchmarks.BenchmarkTH
+    ( createBgroupSink
+    , createBgroupSinkN
+    , createBgroupSrc
+    , createBgroupIO
+    , pureMods
+    , monadicMods
+    , allMods
+    , benchMods
+    , iterMods
+    , Select (..)
+    ) where
+
+import Data.List ((\\))
+import Language.Haskell.TH.Syntax (Q, Exp, Lift)
+
+import Benchmarks.BenchTH
+
+benchMods, iterMods, pureMods, monadicMods, monadicArrayMods, allMods :: [String]
+pureMods    = map fst purePackages
+monadicMods = map fst monadicPackages
+monadicArrayMods = map fst monadicArrays
+allMods     = pureMods ++ monadicMods ++ monadicArrayMods
+benchMods   = allMods \\ ["DList"]
+iterMods = allMods \\
+    [ "DList"
+    , "Streaming"
+    , "Machines"
+    , "Pipes"
+    , "Conduit"
+    , "Drinkery"
+    , "VectorStreams"
+    ]
+
+data Select = Exclude [String] | Include [String] deriving Lift
+
+-- | createBgroupSink <selection func> <module name> <benchmark name>
+--                    <stream consumer function name>
+createBgroupSink :: Select -> String -> String -> String -> Q Exp
+createBgroupSink select modName bname fname =
+    case select of
+        Exclude mods -> f elem mods
+        Include mods -> f notElem mods
+
+    where
+
+    f p mods =
+        if p modName mods
+        then [| Nothing |]
+        else [| Just $(mkBench "source" fname modName bname) |]
+
+-- | createBgroupSink <selection func> <module names> <benchmark name>
+--                    <stream consumer function name> <number of iterations>
+createBgroupSinkN :: Select -> String -> String -> String -> Int -> Q Exp
+createBgroupSinkN select modName bname fname n =
+    case select of
+        Exclude mods -> f elem mods
+        Include mods -> f notElem mods
+
+    where
+
+    f p mods =
+        if p modName mods
+        then [| Nothing |]
+        else [| Just $(mkBenchN "source" fname n modName bname) |]
+
+createBgroupSrc :: Select -> String -> String -> String -> Q Exp
+createBgroupSrc select modName bname fname =
+    case select of
+        Exclude mods -> f elem mods
+        Include mods -> f notElem mods
+
+    where
+
+    f p mods =
+        if p modName mods
+        then [| Nothing |]
+        else [| Just $(mkBench fname "toNull" modName bname) |]
+
+createBgroupIO :: Select -> String -> String -> String -> Q Exp
+createBgroupIO select modName bname fname =
+    case select of
+        Exclude mods -> f elem mods
+        Include mods -> f notElem mods
+
+    where
+
+    f p mods =
+        if p modName mods
+        then [| Nothing |]
+        else [| Just $(mkBenchIO fname modName bname) |]
diff --git a/lib/Benchmarks/Common.hs b/lib/Benchmarks/Common.hs
new file mode 100644
--- /dev/null
+++ b/lib/Benchmarks/Common.hs
@@ -0,0 +1,56 @@
+-- |
+-- Module      : Benchmarks.Common
+-- Copyright   : (c) 2018 Harendra Kumar
+--
+-- License     : MIT
+-- Maintainer  : harendra.kumar@gmail.com
+
+module Benchmarks.Common
+    ( value
+    , maxValue
+    , appendValue
+    , benchIO
+    , benchIOAction
+    , benchIOArray
+    , benchId
+    , benchPure
+    , benchPureFunc
+    ) where
+
+import Control.DeepSeq (NFData)
+import Data.Functor.Identity (Identity, runIdentity)
+import System.Random (randomRIO)
+
+import Gauge
+
+value, maxValue,appendValue :: Int
+value = 1000000
+maxValue = value + 1000
+appendValue = 10000
+
+{-# INLINE benchIOAction #-}
+benchIOAction :: NFData b => String -> (Int -> IO b) -> Benchmark
+benchIOAction name action = bench name $ nfIO $ randomRIO (1,1) >>= action
+
+{-# INLINE benchIO #-}
+benchIO :: (NFData b) => String -> (Int -> a) -> (a -> IO b) -> Benchmark
+benchIO name src f = bench name $ nfIO $ randomRIO (1,1) >>= f . src
+
+{-# INLINE benchId #-}
+benchId :: (NFData b) => String -> (Int -> a) -> (a -> Identity b) -> Benchmark
+benchId name src f = bench name $ nf (runIdentity . f) (src 10)
+
+{-# INLINE benchPureFunc #-}
+benchPureFunc :: NFData b => String -> (Int -> b) -> Benchmark
+benchPureFunc name action =
+    bench name $ nfIO $ randomRIO (1,1) >>= return . action
+
+{-# INLINE benchPure #-}
+benchPure :: (NFData b) => String -> (Int -> a) -> (a -> b) -> Benchmark
+benchPure name src f =
+    bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
+
+{-# INLINE benchIOArray #-}
+benchIOArray :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
+benchIOArray name src f =
+    bench name $ nfIO $ randomRIO (1,1) >>= src >>= f
diff --git a/lib/Benchmarks/DefaultMain.hs b/lib/Benchmarks/DefaultMain.hs
new file mode 100644
--- /dev/null
+++ b/lib/Benchmarks/DefaultMain.hs
@@ -0,0 +1,146 @@
+-- |
+-- Module      : Main
+-- Copyright   : (c) 2018 Harendra Kumar
+--
+-- License     : MIT
+-- Maintainer  : harendra.kumar@gmail.com
+
+{-# LANGUAGE TemplateHaskell #-}
+
+module Benchmarks.DefaultMain (defaultMain) where
+
+import Data.List ((\\))
+import Data.Maybe (catMaybes)
+import Gauge (bgroup)
+import Language.Haskell.TH.Syntax (Q, Exp)
+
+import qualified Gauge as Gauge (defaultMain)
+
+import Benchmarks.BenchmarkTH
+import Prelude hiding (all)
+
+all, most, almost :: Select
+all = Exclude []
+most = Exclude ["DList"]
+almost = Exclude ["DList", "Sequence", "ByteStringLazy"]
+
+defaultMain :: String -> Q Exp
+defaultMain name = [| do
+  Gauge.defaultMain [ bgroup (name ++ "/benchmarks") $ catMaybes
+    [ Just $ bgroup "elimination" $ catMaybes
+      [ $(createBgroupSink all name "drain" "toNull")
+      , $(createBgroupSink (Exclude ["List"]) name "toList" "toList")
+      , $(createBgroupSink all name "foldl'" "foldl")
+      , $(createBgroupSink most name "last" "last")
+      , $(createBgroupSrc (Include ["Streamly", "List", "VectorStreams"])
+            name "enumInt" "sourceIntFromThenTo")
+      ]
+    , Just $ bgroup "transformation" $ catMaybes
+      [ $(createBgroupSinkN almost name "scan" "scan" 1)
+      , $(createBgroupSinkN all name "map" "map" 1)
+      , $(createBgroupSinkN most name "mapM" "mapM" 1)
+      ]
+    , Just $ bgroup "transformationX4" $ catMaybes
+      [ $(createBgroupSinkN almost name "scan x 4" "scan" 4)
+      , $(createBgroupSinkN all name "map x 4" "map" 4)
+      , $(createBgroupSinkN most name "mapM x 4" "mapM" 4)
+      ]
+    , Just $ bgroup "filtering" $ catMaybes
+      [ $(createBgroupSinkN most name "filter-all-out" "filterAllOut" 1)
+      , $(createBgroupSinkN most name "filter-all-in" "filterAllIn" 1)
+      , $(createBgroupSinkN most name "drop-all" "dropAll" 1)
+      , $(createBgroupSinkN most name "takeWhile-true" "takeWhileTrue" 1)
+      , $(createBgroupSinkN most name "filter-even" "filterEven" 1)
+      , $(createBgroupSinkN most name "take-all" "takeAll" 1)
+      , $(createBgroupSinkN most name "drop-one" "dropOne" 1)
+      , $(createBgroupSinkN most name "dropWhile-true" "dropWhileTrue" 1)
+      , $(createBgroupSinkN most name "dropWhile-false" "dropWhileFalse" 1)
+      ]
+      -- drop-all/dropWhile-true/filter-all-out x 4 would be the same as
+      -- drop-all/dropWhile-true/filter-all-out x 1 as they would already
+      -- drop all elements and do nothing in the next iterations
+    , Just $ bgroup "filteringX4" $ catMaybes
+      [ $(createBgroupSinkN most name "filter-even x 4" "filterEven" 4)
+      -- , $(createBgroupSinkN most name "filter-all-out x 4" "filterAllOut" 4)
+      , $(createBgroupSinkN most name "filter-all-in x 4" "filterAllIn" 4)
+      , $(createBgroupSinkN most name "take-all x 4" "takeAll" 4)
+      , $(createBgroupSinkN most name "takeWhile-true x 4" "takeWhileTrue" 4)
+      , $(createBgroupSinkN most name "drop-one x 4" "dropOne" 4)
+      -- , $(createBgroupSinkN most name "drop-all x 4" "dropAll" 4)
+      -- , $(createBgroupSinkN most name "dropWhile-true x 4" "dropWhileTrue" 4)
+      , $(createBgroupSinkN most name "dropWhile-false x 4" "dropWhileFalse" 4)
+      ]
+    , Just $ bgroup "mixedX4" $ catMaybes
+      [ $(createBgroupSinkN almost name "scan-map x 4" "scanMap" 4)
+      , $(createBgroupSinkN almost name "drop-scan x 4" "dropScan" 4)
+      , $(createBgroupSinkN almost name "take-scan x 4" "takeScan" 4)
+      , $(createBgroupSinkN almost name "filter-scan x 4" "filterScan" 4)
+      , $(createBgroupSinkN most name "drop-map x 4" "dropMap" 4)
+      , $(createBgroupSinkN most name "take-drop x 4" "takeDrop" 4)
+      , $(createBgroupSinkN most name "take-map x 4" "takeMap" 4)
+      , $(createBgroupSinkN most name "filter-drop x 4" "filterDrop" 4)
+      , $(createBgroupSinkN most name "filter-take x 4" "filterTake" 4)
+      , $(createBgroupSinkN most name "filter-map x 4" "filterMap" 4)
+      ]
+    , $(createBgroupSink (Exclude ["DList", "StreamlyArray"]) name "zip" "zip")
+    -- XXX use 4x250k concatMap for a comparative idea of cost wrt other ops
+    , $(createBgroupSink (Include
+        [ "List"
+        , "Streamly"
+        , "StreamlyPure"
+        , "VectorStreams"
+        , "Vector"
+        , "VectorStorable"
+        , "VectorUnboxed"
+        , "ByteString"
+        , "ByteStringLazy"
+        , "Text"
+        ]) name "concatMap" "concatMap")
+    , $(createBgroupSink (Exclude
+        [ "List"
+        , "DList"
+        , "Streamly"
+        , "StreamlyPure"
+        , "VectorStreams"
+        , "Vector"
+        , "VectorStorable"
+        , "VectorUnboxed"
+        , "ByteString"
+        , "ByteStringLazy"
+        , "Sequence"
+        , "StreamlyArray"
+        , "Text"
+        ]) name "concatMapFoldable" "concatMapFoldable")
+
+    -- XXX The rest are StreamK operations, use a separate bench group/suite
+    -- for these?
+    , $(createBgroupIO (Exclude
+        [ "Drinkery"
+        , "StreamlyArray"
+        ]) name "appendR (1/100)" "appendSourceR")
+    , $(createBgroupIO (Include
+        [ "DList"
+        , "Conduit"
+        -- , "Streamly"
+        -- , "StreamlyPure"
+        ]) name "appendL (1/100)" "appendSourceL")
+      -- Perform 100,000 mapM recursively over a stream of length 10
+    , Just $ bgroup "iterated" $ catMaybes
+      [ $(createBgroupSrc (Include (iterMods \\ pureMods)) name
+            "mapM" "iterateMapM")
+      , $(createBgroupSrc (Include (iterMods \\ ["Sequence", "ByteStringLazy"])) name
+            "scan" "iterateScan")
+      , $(createBgroupSrc (Include iterMods) name
+            "filterEven" "iterateFilterEven")
+      , $(createBgroupSrc (Include iterMods) name
+            "takeAll" "iterateTakeAll")
+      , $(createBgroupSrc (Include iterMods) name
+            "dropOne" "iterateDropOne")
+      , $(createBgroupSrc (Include iterMods) name
+            "dropWhileFalse" "iterateDropWhileFalse")
+      , $(createBgroupSrc (Include iterMods) name
+            "dropWhileTrue" "iterateDropWhileTrue")
+      ]
+   ]
+   ]
+   |]
diff --git a/streaming-benchmarks.cabal b/streaming-benchmarks.cabal
--- a/streaming-benchmarks.cabal
+++ b/streaming-benchmarks.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name:          streaming-benchmarks
-version:       0.3.0
+version:       0.4.1
 license:       MIT
 license-file:  LICENSE
 author:        Composewell Technologies
@@ -25,127 +25,271 @@
   * conduit
   * drinkery
 
-tested-with: GHC==8.8.4, GHC==8.10.4
+tested-with:
+    GHC==8.10.7
+  , GHC==9.2.8
+  , GHC==9.4.4
+  , GHC==9.6.3
+  , GHC==9.8.4
+  , GHC==9.10.3
+  , GHC==9.12.4
+  , GHC==9.14.1
+
 build-type: Simple
 extra-source-files:
-  Changelog.md
-  README.md
-  bench.sh
-  bench-report.nix
+  Benchmarks/VectorCommon.hs
+  bench-runner/Main.hs
+  bench-runner/bench-runner.cabal
+  bench-runner/cabal.project.user
 
 extra-doc-files:
+  Changelog.md
+  README.md
   docs/benchmarking-notes.md
 
 source-repository head
   type: git
-  location: git://github.com/composewell/streaming-benchmarks.git
+  location: https://github.com/composewell/streaming-benchmarks
 
-flag dev
-  description: Development build
+flag no-fusion-plugin
+  description: Disable fusion plugin for streamly benchmarks
   manual: True
   default: False
 
-flag fusion-plugin
-  description: Use fusion plugin for benchmarks
+flag use-gauge
+  description: Use gauge instead of tasty-bench for benchmarking
   manual: True
   default: False
 
-benchmark bmarks
-  default-language: Haskell2010
-  type:             exitcode-stdio-1.0
-  hs-source-dirs:   .
-  main-is:          Benchmarks.hs
-  other-modules:    Benchmarks.Common
-                  , Benchmarks.BenchTH
-                  , Benchmarks.BenchmarkTH
+flag drinkery
+  description: Use drinkery
+  manual: True
+  default: False
 
-                  -- Pure streams
-                  , Benchmarks.List
-                  , Benchmarks.DList
-                  , Benchmarks.Sequence
-                  , Benchmarks.Vector
-                  , Benchmarks.StreamlyPure
-                  , Benchmarks.StreamlyArray
-                  , Benchmarks.ByteString
-                  , Benchmarks.ByteStringLazy
-                  , Benchmarks.Text
+flag conduit
+  description: Use conduit
+  manual: True
+  default: False
 
-                  -- Monadic streams
-                  , Benchmarks.Streamly
-                  , Benchmarks.VectorStreams
-                  , Benchmarks.Streaming
-                  , Benchmarks.Conduit
-                  , Benchmarks.Pipes
-                  , Benchmarks.Machines
-                  , Benchmarks.Drinkery
+flag pipes
+  description: Use pipes
+  manual: True
+  default: False
 
-                -- List transformers
-                -- , Benchmarks.LogicT
-                -- , Benchmarks.ListT
-                -- , Benchmarks.ListTransformer
+flag machines
+  description: Use machines
+  manual: True
+  default: False
 
-  ghc-options: -O2 -Wall -with-rtsopts "-T"
-               -fspec-constr-recursive=16
-               -fmax-worker-args=16
-  ghc-options:    -Wcompat
-                  -Wunrecognised-warning-flags
-                  -Widentities
-                  -Wincomplete-record-updates
-                  -Wincomplete-uni-patterns
-                  -Wredundant-constraints
-                  -Wnoncanonical-monad-instances
-  if flag(fusion-plugin)
-      ghc-options: -fplugin Fusion.Plugin
+flag streaming
+  description: Use streaming
+  manual: True
+  default: False
 
+common lib-options
+  default-language: Haskell2010
+  ghc-options:
+    -Wall
+    -Wcompat
+    -Wunrecognised-warning-flags
+    -Widentities
+    -Wincomplete-record-updates
+    -Wincomplete-uni-patterns
+    -Wredundant-constraints
+    -Wnoncanonical-monad-instances
+    -Rghc-timing
+    +RTS -M512M -RTS
+    -O2
   build-depends:
     base                == 4.*,
-    deepseq             >= 1.4.0 && < 1.5,
-    gauge               >= 0.2.3 && < 0.3,
-    mtl                 >= 2     && < 2.3,
+    deepseq             >= 1.4.4 && < 1.6,
+    mtl                 >= 2.2.2 && < 2.4,
     random              >= 1.0   && < 2.0,
-    transformers        >= 0.4   && < 0.6,
-    template-haskell    >= 2.10  && < 2.18,
+    transformers        >= 0.5.5 && < 0.7,
+    template-haskell    >= 2.14  && < 2.25
+  if flag(use-gauge)
+    build-depends:  gauge >= 0.2.4 && < 0.3
+  else
+    build-depends:    tasty-bench >= 0.3 && < 0.6
+                    , tasty     >= 1.4.1 && < 1.6
+    mixins: tasty-bench
+      (Test.Tasty.Bench as Gauge
+      , Test.Tasty.Bench as Gauge.Main
+      )
 
-    bytestring          >= 0.9   && < 0.12,
-    text                >= 1.0   && < 1.3,
-    vector              >= 0.12  && < 0.13,
-    streamly            >= 0.8.0 && < 0.9,
-    streaming           >= 0.1.4 && < 0.3,
-    machines            >= 0.6.0 && < 0.8,
-    pipes               >= 4     && < 4.4,
-    conduit             >= 1.3   && < 1.4,
-    drinkery            >= 0.3   && < 0.5,
-    dlist               >= 0.7   && < 1.1,
-    containers          >= 0.5   && < 0.7
-    -- does not build with lts-11.0
-    -- simple-conduit      >= 0.4.0 && < 0.7,
-    -- list-transformer    >= 1.0.2 && < 1.1,
-    -- list-t              >= 0.4.6 && < 1.1,
-    -- logict              >= 0.5.0 && < 0.7,
-  if flag(fusion-plugin)
-    build-depends:
-        fusion-plugin     >= 0.2   && < 0.3
+common bench-options
+  import: lib-options
+  ghc-options:
+    -rtsopts
+    -with-rtsopts "-T"
+  build-depends: streaming-benchmarks
 
-executable bench-report
-  default-language: Haskell2010
-  default-extensions: OverloadedStrings
-  hs-source-dirs:   .
-  main-is: Charts.hs
-  ghc-options: -Wall
-  if flag(dev)
-    buildable: True
-    build-depends:
-        base              == 4.*
-      , bench-show        >= 0.3.0   && < 0.4
-      , bytestring        >= 0.9     && < 0.12
-      , Chart             >= 1.6     && < 2
-      , Chart-diagrams    >= 1.6     && < 2
-      , csv               >= 0.1     && < 0.2
-      , directory         >= 1.2     && < 1.4
-      , split             >= 0.2     && < 0.3
-      , text              >= 1.1.1   && < 1.3
-      , transformers      >= 0.4     && < 0.6
-      , typed-process     >= 0.1.0.0 && < 0.3
-      , getopt-generics   >= 0.11    && < 0.14
+common streamly-options
+  import: bench-options
+  ghc-options:
+    -fdicts-strict
+    -fspec-constr-recursive=16
+    -fmax-worker-args=16
+  if !flag(no-fusion-plugin)
+      ghc-options: -fplugin Fusion.Plugin
+  build-depends:
+      streamly-core >= 0.1.0 && < 0.3.1
+  if !flag(no-fusion-plugin)
+    build-depends: fusion-plugin >= 0.2 && < 0.3
+
+library
+    import: lib-options
+    hs-source-dirs: lib
+    exposed-modules:
+          Benchmarks.Common
+        , Benchmarks.BenchTH
+        , Benchmarks.BenchmarkTH
+        , Benchmarks.DefaultMain
+
+-- Streams
+benchmark Streamly
+  import: streamly-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Streamly.hs
+  ghc-options: -main-is Benchmarks.Streamly
+
+benchmark StreamlyPure
+  import: streamly-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/StreamlyPure.hs
+  ghc-options: -main-is Benchmarks.StreamlyPure
+
+benchmark List
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/List.hs
+  ghc-options: -main-is Benchmarks.List
+
+benchmark DList
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/DList.hs
+  ghc-options: -main-is Benchmarks.DList
+  build-depends: dlist >= 0.7 && < 1.1
+
+benchmark Streaming
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Streaming.hs
+  ghc-options: -main-is Benchmarks.Streaming
+  if flag(streaming)
+    build-depends: streaming >= 0.1.4 && < 0.3
   else
     buildable: False
+
+benchmark Machines
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Machines.hs
+  ghc-options: -main-is Benchmarks.Machines
+  if flag(machines)
+    build-depends: machines >= 0.6.0 && < 0.8
+  else
+    buildable: False
+
+benchmark Pipes
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Pipes.hs
+  ghc-options: -main-is Benchmarks.Pipes
+  if flag(pipes)
+    build-depends: pipes >= 4 && < 4.4
+  else
+    buildable: False
+
+benchmark Conduit
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Conduit.hs
+  ghc-options: -main-is Benchmarks.Conduit
+  if flag(conduit)
+    build-depends: conduit >= 1.3 && < 1.4
+  else
+    buildable: False
+
+benchmark Drinkery
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Drinkery.hs
+  ghc-options: -main-is Benchmarks.Drinkery
+  if flag(drinkery)
+    build-depends: drinkery >= 0.3 && < 0.5
+  else
+    buildable: False
+
+-- benchmark SimpleConduit
+--   import: bench-options
+--   type: exitcode-stdio-1.0
+--   main-is: Benchmarks/SimpleConduit.hs
+--   ghc-options: -main-is Benchmarks.SimpleConduit
+--   build-depends: simple-conduit >= 0.6 && < 0.7
+
+-- Arrays
+benchmark StreamlyArray
+  import: streamly-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/StreamlyArray.hs
+  ghc-options:
+    -main-is Benchmarks.StreamlyArray
+    +RTS -M1500M -RTS
+
+benchmark Sequence
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Sequence.hs
+  ghc-options: -main-is Benchmarks.Sequence
+  build-depends: containers >= 0.5 && < 0.9
+
+benchmark ByteString
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/ByteString.hs
+  ghc-options: -main-is Benchmarks.ByteString
+  build-depends: bytestring >= 0.9 && < 0.13
+
+benchmark ByteStringLazy
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/ByteStringLazy.hs
+  ghc-options: -main-is Benchmarks.ByteStringLazy
+  build-depends: bytestring >= 0.9 && < 0.13
+
+benchmark Text
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Text.hs
+  ghc-options: -main-is Benchmarks.Text
+  build-depends: text >= 1.0 && < 3.0
+
+benchmark VectorStreams
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/VectorStreams.hs
+  ghc-options: -main-is Benchmarks.VectorStreams
+  build-depends: vector >= 0.12 && < 0.14
+
+benchmark Vector
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/Vector.hs
+  ghc-options: -main-is Benchmarks.Vector
+  build-depends: vector >= 0.12 && < 0.14
+
+benchmark VectorUnboxed
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/VectorUnboxed.hs
+  ghc-options: -main-is Benchmarks.VectorUnboxed
+  build-depends: vector >= 0.12 && < 0.14
+
+benchmark VectorStorable
+  import: bench-options
+  type: exitcode-stdio-1.0
+  main-is: Benchmarks/VectorStorable.hs
+  ghc-options: -main-is Benchmarks.VectorStorable
+  build-depends: vector >= 0.12 && < 0.14
