on master help sign in
Add benchmarks for PrimArray
75b7e6badithyaov
benchmark/Streamly/Benchmark/Data/PrimArray.hsnew file+97
@@ -0,0 +1,97 @@
1+-- |
2+-- Module : Main
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+-- Stability : experimental
8+-- Portability : GHC
9+
10+{-# LANGUAGE CPP #-}
11+
12+module Main (main) where
13+
14+import Control.DeepSeq (NFData(..))
15+import System.Random (randomRIO)
16+
17+import qualified Streamly.Benchmark.Data.PrimArrayOps as Ops
18+import qualified Streamly.Data.PrimArray as A
19+import qualified Streamly.Prelude as S
20+
21+import Gauge
22+
23+-------------------------------------------------------------------------------
24+--
25+-------------------------------------------------------------------------------
26+
27+{-# INLINE benchIO #-}
28+benchIO :: NFData b => String -> (Int -> IO a) -> (a -> b) -> Benchmark
29+benchIO name src f = bench name $ nfIO $
30+ randomRIO (1,1) >>= src >>= return . f
31+
32+-- Drain a source that generates an array in the IO monad
33+{-# INLINE benchIOSrc #-}
34+benchIOSrc :: A.Prim a => String -> (Int -> IO (Ops.Stream a)) -> Benchmark
35+benchIOSrc name src = benchIO name src id
36+
37+{-# INLINE benchPureSink #-}
38+benchPureSink :: NFData b => String -> (Ops.Stream Int -> b) -> Benchmark
39+benchPureSink name f = benchIO name Ops.sourceIntFromTo f
40+
41+{-# INLINE benchIO' #-}
42+benchIO' :: NFData b => String -> (Int -> IO a) -> (a -> IO b) -> Benchmark
43+benchIO' name src f = bench name $ nfIO $
44+ randomRIO (1,1) >>= src >>= f
45+
46+{-# INLINE benchIOSink #-}
47+benchIOSink :: NFData b => String -> (Ops.Stream Int -> IO b) -> Benchmark
48+benchIOSink name f = benchIO' name Ops.sourceIntFromTo f
49+
50+{-
51+mkString :: String
52+mkString = "[1" ++ concat (replicate Ops.value ",1") ++ "]"
53+-}
54+
55+main :: IO ()
56+main =
57+ defaultMain
58+ [ bgroup "Data.PrimArray"
59+ [ bgroup "generation"
60+ [ benchIOSrc "writeN . intFromTo" Ops.sourceIntFromTo
61+ , benchIOSrc "write . intFromTo" Ops.sourceIntFromToFromStream
62+ , benchIOSrc "fromList . intFromTo" Ops.sourceIntFromToFromList
63+ , benchIOSrc "writeN . unfoldr" Ops.sourceUnfoldr
64+ , benchIOSrc "writeN . fromList" Ops.sourceFromList
65+ -- , benchPureSrc "writeN . IsList.fromList" Ops.sourceIsList
66+ -- , benchPureSrc "writeN . IsString.fromString" Ops.sourceIsString
67+ -- , mkString `deepseq` (bench "read" $ nf Ops.readInstance mkString)
68+ , benchPureSink "show" Ops.showInstance
69+ ]
70+ , bgroup "elimination"
71+ [ benchPureSink "id" id
72+ , benchPureSink "==" Ops.eqInstance
73+ , benchPureSink "/=" Ops.eqInstanceNotEq
74+ , benchPureSink "<" Ops.ordInstance
75+ , benchPureSink "min" Ops.ordInstanceMin
76+ -- length is used to check for foldr/build fusion
77+ -- , benchPureSink "length . IsList.toList" (length . GHC.toList)
78+ , benchIOSink "foldl'" Ops.pureFoldl'
79+ , benchIOSink "read" (S.drain . S.unfold A.read)
80+ , benchIOSink "toStreamRev" (S.drain . A.toStreamRev)
81+#ifdef DEVBUILD
82+ , benchPureSink "foldable/foldl'" Ops.foldableFoldl'
83+ , benchPureSink "foldable/sum" Ops.foldableSum
84+#endif
85+ ]
86+ , bgroup "transformation"
87+ [ benchIOSink "scanl'" (Ops.scanl' 1)
88+ , benchIOSink "scanl1'" (Ops.scanl1' 1)
89+ , benchIOSink "map" (Ops.map 1)
90+ ]
91+ , bgroup "transformationX4"
92+ [ benchIOSink "scanl'" (Ops.scanl' 4)
93+ , benchIOSink "scanl1'" (Ops.scanl1' 4)
94+ , benchIOSink "map" (Ops.map 4)
95+ ]
96+ ]
97+ ]
benchmark/Streamly/Benchmark/Data/PrimArrayOps.hsnew file+150
@@ -0,0 +1,150 @@
1+-- |
2+-- Module : Streamly.Benchmark.Data.PrimArrayOps
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD-3-Clause
6+-- Maintainer : streamly@composewell.com
7+-- Stability : experimental
8+-- Portability : GHC
9+
10+{-# LANGUAGE CPP #-}
11+{-# LANGUAGE DeriveAnyClass #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE FlexibleContexts #-}
14+{-# LANGUAGE ScopedTypeVariables #-}
15+
16+module Streamly.Benchmark.Data.PrimArrayOps where
17+
18+import Control.Monad.IO.Class (MonadIO)
19+import Prelude (Int, Bool, (+), ($), (==), (>), (.), Maybe(..), undefined)
20+import qualified Prelude as P
21+#ifdef DEVBUILD
22+import qualified Data.Foldable as F
23+#endif
24+
25+import qualified Streamly as S hiding (foldMapWith, runStream)
26+import qualified Streamly.Data.PrimArray as A
27+import qualified Streamly.Prelude as S
28+
29+value :: Int
30+value = 100000
31+
32+-------------------------------------------------------------------------------
33+-- Benchmark ops
34+-------------------------------------------------------------------------------
35+
36+-------------------------------------------------------------------------------
37+-- Stream generation and elimination
38+-------------------------------------------------------------------------------
39+
40+type Stream = A.PrimArray
41+
42+{-# INLINE sourceUnfoldr #-}
43+sourceUnfoldr :: MonadIO m => Int -> m (Stream Int)
44+sourceUnfoldr n = S.fold (A.writeN value) $ S.unfoldr step n
45+ where
46+ step cnt =
47+ if cnt > n + value
48+ then Nothing
49+ else (Just (cnt, cnt + 1))
50+
51+{-# INLINE sourceIntFromTo #-}
52+sourceIntFromTo :: MonadIO m => Int -> m (Stream Int)
53+sourceIntFromTo n = S.fold (A.writeN value) $ S.enumerateFromTo n (n + value)
54+
55+{-# INLINE sourceIntFromToFromStream #-}
56+sourceIntFromToFromStream :: MonadIO m => Int -> m (Stream Int)
57+sourceIntFromToFromStream n = S.fold A.write $ S.enumerateFromTo n (n + value)
58+
59+{-# INLINE sourceIntFromToFromList #-}
60+sourceIntFromToFromList :: MonadIO m => Int -> m (Stream Int)
61+sourceIntFromToFromList n = P.return $ A.fromList $ [n..n + value]
62+
63+{-# INLINE sourceFromList #-}
64+sourceFromList :: MonadIO m => Int -> m (Stream Int)
65+sourceFromList n = S.fold (A.writeN value) $ S.fromList [n..n+value]
66+{-
67+{-# INLINE sourceIsList #-}
68+sourceIsList :: Int -> Stream Int
69+sourceIsList n = GHC.fromList [n..n+value]
70+
71+{-# INLINE sourceIsString #-}
72+sourceIsString :: Int -> Stream P.Char
73+sourceIsString n = GHC.fromString (P.replicate (n + value) 'a')
74+-}
75+-------------------------------------------------------------------------------
76+-- Transformation
77+-------------------------------------------------------------------------------
78+
79+{-# INLINE composeN #-}
80+composeN :: P.Monad m
81+ => Int -> (Stream Int -> m (Stream Int)) -> Stream Int -> m (Stream Int)
82+composeN n f x =
83+ case n of
84+ 1 -> f x
85+ 2 -> f x P.>>= f
86+ 3 -> f x P.>>= f P.>>= f
87+ 4 -> f x P.>>= f P.>>= f P.>>= f
88+ _ -> undefined
89+
90+{-# INLINE scanl' #-}
91+{-# INLINE scanl1' #-}
92+{-# INLINE map #-}
93+
94+scanl', scanl1', map
95+ :: MonadIO m => Int -> Stream Int -> m (Stream Int)
96+
97+{-# INLINE onArray #-}
98+onArray
99+ :: MonadIO m => (S.SerialT m Int -> S.SerialT m Int)
100+ -> Stream Int
101+ -> m (Stream Int)
102+onArray f arr = S.fold (A.writeN value) $ f $ (S.unfold A.read arr)
103+
104+scanl' n = composeN n $ onArray $ S.scanl' (+) 0
105+scanl1' n = composeN n $ onArray $ S.scanl1' (+)
106+map n = composeN n $ onArray $ S.map (+1)
107+
108+{-# INLINE eqInstance #-}
109+eqInstance :: Stream Int -> Bool
110+eqInstance src = src == src
111+
112+{-# INLINE eqInstanceNotEq #-}
113+eqInstanceNotEq :: Stream Int -> Bool
114+eqInstanceNotEq src = src P./= src
115+
116+{-# INLINE ordInstance #-}
117+ordInstance :: Stream Int -> Bool
118+ordInstance src = src P.< src
119+
120+{-# INLINE ordInstanceMin #-}
121+ordInstanceMin :: Stream Int -> Stream Int
122+ordInstanceMin src = P.min src src
123+
124+{-# INLINE showInstance #-}
125+showInstance :: Stream Int -> P.String
126+showInstance src = P.show src
127+
128+{-
129+{-# INLINE readInstance #-}
130+readInstance :: P.String -> Stream Int
131+readInstance str =
132+ let r = P.reads str
133+ in case r of
134+ [(x,"")] -> x
135+ _ -> P.error "readInstance: no parse"
136+-}
137+
138+{-# INLINE pureFoldl' #-}
139+pureFoldl' :: MonadIO m => Stream Int -> m Int
140+pureFoldl' = S.foldl' (+) 0 . S.unfold A.read
141+
142+#ifdef DEVBUILD
143+{-# INLINE foldableFoldl' #-}
144+foldableFoldl' :: Stream Int -> Int
145+foldableFoldl' = F.foldl' (+) 0
146+
147+{-# INLINE foldableSum #-}
148+foldableSum :: Stream Int -> Int
149+foldableSum = P.sum
150+#endif
streamly.cabal+16
@@ -691,6 +691,22 @@ benchmark unpinned-array
691 build-depends:
691 build-depends:
692 transformers >= 0.4 && < 0.6
692 transformers >= 0.4 && < 0.6
693
693
694+benchmark prim-array
695+ import: bench-options
696+ type: exitcode-stdio-1.0
697+ hs-source-dirs: benchmark
698+ main-is: Streamly/Benchmark/Data/PrimArray.hs
699+ other-modules: Streamly.Benchmark.Data.PrimArrayOps
700+ build-depends:
701+ streamly
702+ , base >= 4.8 && < 5
703+ , deepseq >= 1.4.1 && < 1.5
704+ , random >= 1.0 && < 2.0
705+ , gauge >= 0.2.4 && < 0.3
706+ if impl(ghc < 8.0)
707+ build-depends:
708+ transformers >= 0.4 && < 0.6
709+
694benchmark small-array
710benchmark small-array
695 import: bench-options
711 import: bench-options
696 type: exitcode-stdio-1.0
712 type: exitcode-stdio-1.0