on master help sign in
Add microbenchmarks for list-transformer ops
d2c4df4Harendra Kumar
benchmark/BenchmarkNestedLoopOps.hsnew file+154
@@ -0,0 +1,154 @@
1+-- |
2+-- Module : BenchmarkOps
3+-- Copyright : (c) 2018 Harendra Kumar
4+--
5+-- License : MIT
6+-- Maintainer : harendra.kumar@gmail.com
7+
8+{-# LANGUAGE ScopedTypeVariables #-}
9+
10+module BenchmarkNestedLoopOps where
11+
12+import Control.Exception (try)
13+import GHC.Exception (ErrorCall)
14+
15+import qualified Streamly as S
16+import qualified Streamly.Prelude as S
17+
18+sumCount :: Int
19+sumCount = 1000000
20+
21+prodCount :: Int
22+prodCount = 1000
23+
24+-------------------------------------------------------------------------------
25+-- Stream generation and elimination
26+-------------------------------------------------------------------------------
27+
28+type Stream m a = S.SerialT m a
29+
30+{-# INLINE source #-}
31+source :: S.IsStream t => Int -> Int -> t m Int
32+source start n = S.fromFoldable [start..start+n]
33+
34+{-# INLINE runStream #-}
35+runStream :: Monad m => Stream m a -> m ()
36+runStream = S.runStream
37+
38+{-# INLINE runToList #-}
39+runToList :: Monad m => Stream m a -> m [a]
40+runToList = S.toList
41+
42+-------------------------------------------------------------------------------
43+-- Benchmark ops
44+-------------------------------------------------------------------------------
45+
46+{-# INLINE toNullLinear #-}
47+toNullLinear :: Monad m => Int -> m ()
48+toNullLinear start = runStream $ source start sumCount
49+
50+{-# INLINE toListLinear #-}
51+toListLinear :: Monad m => Int -> m [Int]
52+toListLinear start = runToList $ source start sumCount
53+
54+{-# INLINE append #-}
55+append
56+ :: (Monoid (t m Int), Monad m, Monad (t m))
57+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
58+append t start = runStream $ t $ foldMap return [start..start+sumCount]
59+
60+{-# INLINE toNull0 #-}
61+toNull0
62+ :: (S.IsStream t, Monad m, Monad (t m))
63+ => (t m (Int, Int) -> S.SerialT m (Int, Int)) -> Int -> m ()
64+toNull0 t start = runStream . t $ do
65+ x <- source start prodCount
66+ y <- source start prodCount
67+ return (x,y)
68+
69+{-# INLINE toList0 #-}
70+toList0
71+ :: (S.IsStream t, Monad m, Monad (t m))
72+ => (t m (Int, Int) -> S.SerialT m (Int, Int)) -> Int -> m [(Int, Int)]
73+toList0 t start = runToList . t $ do
74+ x <- source start prodCount
75+ y <- source start prodCount
76+ return (x,y)
77+
78+{-# INLINE toNull #-}
79+toNull
80+ :: (S.IsStream t, Monad m, Monad (t m))
81+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
82+toNull t start = runStream . t $ do
83+ x <- source start prodCount
84+ y <- source start prodCount
85+ return $ x * x + y * y
86+
87+{-# INLINE toList #-}
88+toList
89+ :: (S.IsStream t, Monad m, Monad (t m))
90+ => (t m Int -> S.SerialT m Int) -> Int -> m [Int]
91+toList t start = runToList . t $ do
92+ x <- source start prodCount
93+ y <- source start prodCount
94+ return $ x * x + y * y
95+
96+{-# INLINE toListSome #-}
97+toListSome
98+ :: (S.IsStream t, Monad m, Monad (t m))
99+ => (t m Int -> S.SerialT m Int) -> Int -> m [Int]
100+toListSome t start =
101+ runToList . t $ S.take 1000 $ do
102+ x <- source start prodCount
103+ y <- source start prodCount
104+ return $ x * x + y * y
105+
106+{-# INLINE filterAllOut #-}
107+filterAllOut
108+ :: (S.IsStream t, Monad m, Monad (t m))
109+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
110+filterAllOut t start = runStream . t $ do
111+ x <- source start prodCount
112+ y <- source start prodCount
113+ let s = x * x + y * y
114+ if (s < 1)
115+ then return s
116+ else S.nil
117+
118+{-# INLINE filterAllIn #-}
119+filterAllIn
120+ :: (S.IsStream t, Monad m, Monad (t m))
121+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
122+filterAllIn t start = runStream . t $ do
123+ x <- source start prodCount
124+ y <- source start prodCount
125+ let s = x * x + y * y
126+ if (s > 1)
127+ then return s
128+ else S.nil
129+
130+{-# INLINE filterSome #-}
131+filterSome
132+ :: (S.IsStream t, Monad m, Monad (t m))
133+ => (t m Int -> S.SerialT m Int) -> Int -> m ()
134+filterSome t start = runStream . t $ do
135+ x <- source start prodCount
136+ y <- source start prodCount
137+ let s = x * x + y * y
138+ if (s > 1100000)
139+ then return s
140+ else S.nil
141+
142+{-# INLINE breakAfterSome #-}
143+breakAfterSome
144+ :: (S.IsStream t, Monad (t IO))
145+ => (t IO Int -> S.SerialT IO Int) -> Int -> IO ()
146+breakAfterSome t start = do
147+ (_ :: Either ErrorCall ()) <- try $ runStream . t $ do
148+ x <- source start prodCount
149+ y <- source start prodCount
150+ let s = x * x + y * y
151+ if (s > 1100000)
152+ then error "break"
153+ else return s
154+ return ()
benchmark/BenchmarkNestedLoops.hsnew file+81
@@ -0,0 +1,81 @@
1+-- |
2+-- Module : Main
3+-- Copyright : (c) 2018 Harendra Kumar
4+--
5+-- License : BSD3
6+-- Maintainer : harendra.kumar@gmail.com
7+
8+import Control.DeepSeq (NFData)
9+import Data.Functor.Identity (Identity, runIdentity)
10+import System.Random (randomRIO)
11+import qualified BenchmarkNestedLoopOps as Ops
12+import Streamly
13+import Gauge
14+
15+benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
16+benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
17+
18+_benchId :: (NFData b) => String -> (Int -> Identity b) -> Benchmark
19+_benchId name f = bench name $ nf (\g -> runIdentity (g 1)) f
20+
21+main :: IO ()
22+main = do
23+ -- TBD Study scaling with 10, 100, 1000 loop iterations
24+ defaultMain
25+ [ bgroup "Linear"
26+ [ benchIO "toNullLinear" Ops.toNullLinear
27+ , benchIO "toListLinear" Ops.toListLinear
28+ ]
29+
30+ , bgroup "Serially"
31+ [ benchIO "append" $ Ops.append serially
32+ , benchIO "toNull0" $ Ops.toNull0 serially
33+ , benchIO "toList0" $ Ops.toList0 serially
34+ , benchIO "toNull" $ Ops.toNull serially
35+ , benchIO "toList" $ Ops.toList serially
36+ , benchIO "toListSome" $ Ops.toListSome serially
37+ , benchIO "filterAllOut" $ Ops.filterAllOut serially
38+ , benchIO "filterAllIn" $ Ops.filterAllIn serially
39+ , benchIO "filterSome" $ Ops.filterSome serially
40+ , benchIO "breakAfterSome" $ Ops.breakAfterSome serially
41+ ]
42+
43+ , bgroup "Coserially"
44+ [ benchIO "append" $ Ops.append coserially
45+ , benchIO "toNull0" $ Ops.toNull0 coserially
46+ , benchIO "toList0" $ Ops.toList0 coserially
47+ , benchIO "toNull" $ Ops.toNull coserially
48+ , benchIO "toList" $ Ops.toList coserially
49+ , benchIO "toListSome" $ Ops.toListSome coserially
50+ , benchIO "filterAllOut" $ Ops.filterAllOut coserially
51+ , benchIO "filterAllIn" $ Ops.filterAllIn coserially
52+ , benchIO "filterSome" $ Ops.filterSome coserially
53+ , benchIO "breakAfterSome" $ Ops.breakAfterSome coserially
54+ ]
55+
56+ , bgroup "Coparallely"
57+ [ benchIO "append" $ Ops.append coparallely
58+ , benchIO "toNull0" $ Ops.toNull0 coparallely
59+ , benchIO "toList0" $ Ops.toList0 coparallely
60+ , benchIO "toNull" $ Ops.toNull coparallely
61+ , benchIO "toList" $ Ops.toList coparallely
62+ , benchIO "toListSome" $ Ops.toListSome coparallely
63+ , benchIO "filterAllOut" $ Ops.filterAllOut coparallely
64+ , benchIO "filterAllIn" $ Ops.filterAllIn coparallely
65+ , benchIO "filterSome" $ Ops.filterSome coparallely
66+ , benchIO "breakAfterSome" $ Ops.breakAfterSome coparallely
67+ ]
68+
69+ , bgroup "Parallely"
70+ [ benchIO "append" $ Ops.append parallely
71+ , benchIO "toNull0" $ Ops.toNull0 parallely
72+ , benchIO "toList0" $ Ops.toList0 parallely
73+ , benchIO "toNull" $ Ops.toNull parallely
74+ , benchIO "toList" $ Ops.toList parallely
75+ , benchIO "toListSome" $ Ops.toListSome parallely
76+ , benchIO "filterAllOut" $ Ops.filterAllOut parallely
77+ , benchIO "filterAllIn" $ Ops.filterAllIn parallely
78+ , benchIO "filterSome" $ Ops.filterSome parallely
79+ , benchIO "breakAfterSome" $ Ops.breakAfterSome parallely
80+ ]
81+ ]
streamly.cabal+28−1
@@ -217,7 +217,7 @@ benchmark bench
217 , transient >= 0.4 && < 0.6
217 , transient >= 0.4 && < 0.6
218 default-language: Haskell2010
218 default-language: Haskell2010
219
219
220−benchmark benchOps
220+benchmark linear
221 type: exitcode-stdio-1.0
221 type: exitcode-stdio-1.0
222 hs-source-dirs: benchmark
222 hs-source-dirs: benchmark
223 main-is: Benchmarks.hs
223 main-is: Benchmarks.hs
@@ -244,6 +244,33 @@ benchmark benchOps
244 , random >= 1.0 && < 2.0
244 , random >= 1.0 && < 2.0
245 , gauge >= 0.2.1 && < 0.3
245 , gauge >= 0.2.1 && < 0.3
246
246
247+benchmark nested
248+ type: exitcode-stdio-1.0
249+ hs-source-dirs: benchmark
250+ main-is: BenchmarkNestedLoops.hs
251+ other-modules: BenchmarkNestedLoopOps
252+ default-language: Haskell2010
253+ ghc-options: -O2 -Wall
254+ if flag(dev)
255+ ghc-options: -Wmissed-specialisations
256+ -Wall-missed-specialisations
257+ -fno-ignore-asserts
258+ if impl(ghc >= 8.0)
259+ ghc-options: -Wcompat
260+ -Wunrecognised-warning-flags
261+ -Widentities
262+ -Wincomplete-record-updates
263+ -Wincomplete-uni-patterns
264+ -Wredundant-constraints
265+ -Wnoncanonical-monad-instances
266+ -Wnoncanonical-monadfail-instances
267+ build-depends:
268+ streamly
269+ , base >= 4.8 && < 5
270+ , deepseq >= 1.4.0 && < 1.5
271+ , random >= 1.0 && < 2.0
272+ , gauge >= 0.2.1 && < 0.3
273+
247-------------------------------------------------------------------------------
274-------------------------------------------------------------------------------
248-- Examples
275-- Examples
249-------------------------------------------------------------------------------
276-------------------------------------------------------------------------------