on master help sign in
Accept stream size via a CLI option

Use --stream-size to accept the stream size. The CLI argument position is not fixed anymore so it can be specified anywhere on the command line. The remaining arguments are used by gauge.

commit8ec2ebe188b6d8d0cc4b2e7949e90e4d786b92ee authorHarendra Kumar <harendra.kumar@gmail.com> dateSat 4 Jan 2020, 16:04 (7 years ago) parentf684e26
7 files changed+142−97
benchmark/Common.hs+82 benchmark/Linear.hs+9−15 benchmark/LinearAsync.hs+10−21 benchmark/LinearRate.hs+10−16 benchmark/Nested.hs+11−16 benchmark/NestedConcurrent.hs+11−16 streamly.cabal+9−13
benchmark/Common.hsnew file+82
@@ -0,0 +1,82 @@
1+-- |
2+-- Module : Main
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD3
6+-- Maintainer : streamly@composewell.com
7+
8+module Common (parseCLIOpts) where
9+
10+import Control.Exception (evaluate)
11+import Control.Monad (when)
12+import Data.List (scanl')
13+import Data.Maybe (catMaybes)
14+import System.Console.GetOpt
15+ (OptDescr(..), ArgDescr(..), ArgOrder(..), getOpt')
16+import System.Environment (getArgs)
17+import Text.Read (readMaybe)
18+
19+import Gauge
20+
21+-------------------------------------------------------------------------------
22+-- Parse custom CLI options
23+-------------------------------------------------------------------------------
24+
25+data BenchOpts = StreamSize Int deriving Show
26+
27+options :: [OptDescr BenchOpts]
28+options =
29+ [
30+ Option [] ["stream-size"] (ReqArg getSize "COUNT") "Stream element count"
31+ ]
32+
33+ where
34+
35+ getSize :: String -> BenchOpts
36+ getSize size =
37+ case (readMaybe size :: Maybe Int) of
38+ Just x -> StreamSize x
39+ Nothing -> error "Stream size must be numeric"
40+
41+deleteOptArgs
42+ :: (Maybe String, Maybe String) -- (prev, yielded)
43+ -> String
44+ -> (Maybe String, Maybe String)
45+deleteOptArgs (Nothing, _) opt =
46+ if opt == "--stream-size"
47+ then (Just opt, Nothing)
48+ else (Just opt, Just opt)
49+
50+deleteOptArgs (Just prev, _) opt =
51+ if opt == "--stream-size" || prev == "--stream-size"
52+ then (Just opt, Nothing)
53+ else (Just opt, Just opt)
54+
55+parseCLIOpts :: Int -> IO (Int, Config, [String])
56+parseCLIOpts defaultStreamSize = do
57+ args <- getArgs
58+
59+ -- Parse custom options
60+ let (opts, _, _, errs) = getOpt' Permute options args
61+ when (not $ null errs) $ error $ concat errs
62+ (streamSize, args') <- evaluate $
63+ case opts of
64+ StreamSize x : _ ->
65+ -- Hack! remove the option and its argument from args
66+ -- getOpt should have a way to return the unconsumed args in
67+ -- correct order.
68+ let newArgs =
69+ catMaybes
70+ $ map snd
71+ $ scanl' deleteOptArgs (Nothing, Nothing) args
72+ in (x, newArgs)
73+ _ -> (defaultStreamSize, args)
74+
75+ -- Parse gauge options
76+ let config = defaultConfig
77+ { timeLimit = Just 1
78+ , minDuration = 0
79+ , includeFirstIter = streamSize > defaultStreamSize
80+ }
81+ let (cfg, benches) = parseWith config args'
82+ return (streamSize, cfg, benches)
benchmark/Linear.hs+9−15
@@ -12,10 +12,10 @@
1212
1313import Control.DeepSeq (NFData(..), deepseq)
1414import Data.Functor.Identity (Identity, runIdentity)
15−import System.Random (randomRIO)
1615import Data.Monoid (Last(..))
17−import System.Environment (getArgs)
18−import Text.Read (readMaybe)
16+import System.Random (randomRIO)
17+
18+import Common (parseCLIOpts)
1919
2020import qualified GHC.Exts as GHC
2121import qualified Streamly.Benchmark.Prelude as Ops
@@ -121,13 +121,14 @@ mkListString value = "[1" ++ concat (replicate value ",1") ++ "]"
121121mkList :: Int -> [Int]
122122mkList value = [1..value]
123123
124+defaultStreamSize :: Int
125+defaultStreamSize = 100000
126+
124127main :: IO ()
125128main = do
126− -- Basement.Terminal.initialize required?
127− args <- getArgs
128− let (value, args') = parseValue args
129− (cfg, extra) = parseWith defaultConfig args'
130− runMode (mode cfg) cfg extra
129+ -- XXX Fix indentation
130+ (value, cfg, benches) <- parseCLIOpts defaultStreamSize
131+ runMode (mode cfg) cfg benches
131132 [ bgroup "serially"
132133 [ bgroup "pure"
133134 [ benchPureSink value "id" id
@@ -474,10 +475,3 @@ main = do
474475 ]
475476 ]
476477 ]
477− where
478− defaultValue = 100000
479− parseValue [] = (defaultValue, [])
480− parseValue a@(x:xs) =
481− case (readMaybe x :: Maybe Int) of
482− Just value -> (value, xs)
483− Nothing -> (defaultValue, a)
benchmark/LinearAsync.hs+10−21
@@ -9,13 +9,14 @@
99import Control.DeepSeq (NFData)
1010-- import Data.Functor.Identity (Identity, runIdentity)
1111import System.Random (randomRIO)
12−import Text.Read (readMaybe)
13−import System.Environment (getArgs)
14−import qualified Streamly.Benchmark.Prelude as Ops
12+
13+import Common (parseCLIOpts)
1514
1615import Streamly
1716import Gauge
1817
18+import qualified Streamly.Benchmark.Prelude as Ops
19+
1920-- We need a monadic bind here to make sure that the function f does not get
2021-- completely optimized out by the compiler in some cases.
2122--
@@ -43,13 +44,14 @@ _benchId :: NFData b => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
4344_benchId name f = bench name $ nf (runIdentity . f) (Ops.source 10)
4445-}
4546
47+defaultStreamSize :: Int
48+defaultStreamSize = 10000
49+
4650main :: IO ()
4751main = do
48− -- Basement.Terminal.initialize required?
49− args <- getArgs
50− let (value, args') = parseValue args
51− (cfg, extra) = parseWith (newConfig value) args'
52− runMode (mode cfg) cfg extra
52+ -- XXX Fix indentation
53+ (value, cfg, benches) <- parseCLIOpts defaultStreamSize
54+ runMode (mode cfg) cfg benches
5355 [ bgroup "asyncly"
5456 [ benchSrcIO asyncly "unfoldr" (Ops.sourceUnfoldr value)
5557 , benchSrcIO asyncly "unfoldrM" (Ops.sourceUnfoldrM value)
@@ -133,16 +135,3 @@ main = do
133135 (Ops.concatStreamsWith parallel (value `div` 10) 10)
134136 ]
135137 ]
136− where
137− defaultValue = 10000
138− parseValue [] = (defaultValue, [])
139− parseValue a@(x:xs) =
140− case (readMaybe x :: Maybe Int) of
141− Just value -> (value, xs)
142− Nothing -> (defaultValue, a)
143− newConfig value =
144− defaultConfig
145− { timeLimit = Just 1
146− , minDuration = 0
147− , includeFirstIter = value >= 10000000
148− }
benchmark/LinearRate.hs+10−16
@@ -1,4 +1,3 @@
1−{-# LANGUAGE CPP #-}
21-- |
32-- Module : Main
43-- Copyright : (c) 2018 Harendra Kumar
@@ -11,13 +10,14 @@
1110
1211-- import Data.Functor.Identity (Identity, runIdentity)
1312import System.Random (randomRIO)
14−import qualified Streamly.Benchmark.Prelude as Ops
15−import System.Environment (getArgs)
16−import Text.Read (readMaybe)
13+
14+import Common (parseCLIOpts)
1715
1816import Streamly
1917import Gauge
2018
19+import qualified Streamly.Benchmark.Prelude as Ops
20+
2121-- | Takes a source, and uses it with a default drain/fold method.
2222{-# INLINE benchSrcIO #-}
2323benchSrcIO
@@ -33,13 +33,14 @@ _benchId :: NFData b => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
3333_benchId name f = bench name $ nf (runIdentity . f) (Ops.source 10)
3434-}
3535
36+defaultStreamSize :: Int
37+defaultStreamSize = 100000
38+
3639main :: IO ()
3740main = do
38− -- Basement.Terminal.initialize required?
39− args <- getArgs
40− let (value, args') = parseValue args
41− (cfg, extra) = parseWith defaultConfig args'
42− runMode (mode cfg) cfg extra
41+ -- XXX Fix indentation
42+ (value, cfg, benches) <- parseCLIOpts defaultStreamSize
43+ runMode (mode cfg) cfg benches
4344 -- XXX arbitrarily large rate should be the same as rate Nothing
4445 [ bgroup "avgrate"
4546 [ bgroup "asyncly"
@@ -65,10 +66,3 @@ main = do
6566 ]
6667 ]
6768 ]
68− where
69− defaultValue = 100000
70− parseValue [] = (defaultValue, [])
71− parseValue a@(x:xs) =
72− case (readMaybe x :: Maybe Int) of
73− Just value -> (value, xs)
74− Nothing -> (defaultValue, a)
benchmark/Nested.hs+11−16
@@ -8,11 +8,13 @@
88import Control.DeepSeq (NFData)
99import Data.Functor.Identity (Identity, runIdentity)
1010import System.Random (randomRIO)
11−import qualified NestedOps as Ops
11+
12+import Common (parseCLIOpts)
13+
1214import Streamly
1315import Gauge
14−import System.Environment (getArgs)
15−import Text.Read (readMaybe)
16+
17+import qualified NestedOps as Ops
1618
1719benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
1820benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
@@ -20,14 +22,14 @@ benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
2022_benchId :: (NFData b) => String -> (Int -> Identity b) -> Benchmark
2123_benchId name f = bench name $ nf (\g -> runIdentity (g 1)) f
2224
25+defaultStreamSize :: Int
26+defaultStreamSize = 100000
27+
2328main :: IO ()
2429main = do
25− -- TBD Study scaling with 10, 100, 1000 loop iterations
26− -- Basement.Terminal.initialize required?
27− args <- getArgs
28− let (linearCount, args') = parseValue args
29− (cfg, extra) = parseWith defaultConfig args'
30− runMode (mode cfg) cfg extra
30+ -- XXX Fix indentation
31+ (linearCount, cfg, benches) <- parseCLIOpts defaultStreamSize
32+ runMode (mode cfg) cfg benches
3133 [ bgroup "serially"
3234 [ benchIO "toNullAp" $ Ops.toNullAp linearCount serially
3335 , benchIO "toNull" $ Ops.toNull linearCount serially
@@ -56,10 +58,3 @@ main = do
5658 [ benchIO "toNullAp" $ Ops.toNullAp linearCount zipSerially
5759 ]
5860 ]
59− where
60− defaultValue = 100000
61− parseValue [] = (defaultValue, [])
62− parseValue a@(x:xs) =
63− case (readMaybe x :: Maybe Int) of
64− Just value -> (value, xs)
65− Nothing -> (defaultValue, a)
benchmark/NestedConcurrent.hs+11−16
@@ -8,11 +8,13 @@
88import Control.DeepSeq (NFData)
99import Data.Functor.Identity (Identity, runIdentity)
1010import System.Random (randomRIO)
11−import qualified NestedOps as Ops
11+
12+import Common (parseCLIOpts)
13+
1214import Streamly
1315import Gauge
14−import System.Environment (getArgs)
15−import Text.Read (readMaybe)
16+
17+import qualified NestedOps as Ops
1618
1719benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
1820benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
@@ -20,14 +22,14 @@ benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
2022_benchId :: (NFData b) => String -> (Int -> Identity b) -> Benchmark
2123_benchId name f = bench name $ nf (\g -> runIdentity (g 1)) f
2224
25+defaultStreamSize :: Int
26+defaultStreamSize = 100000
27+
2328main :: IO ()
2429main = do
25− -- TBD Study scaling with 10, 100, 1000 loop iterations
26− -- Basement.Terminal.initialize required?
27− args <- getArgs
28− let (linearCount, args') = parseValue args
29− (cfg, extra) = parseWith defaultConfig args'
30− runMode (mode cfg) cfg extra
30+ -- XXX Fix indentation
31+ (linearCount, cfg, benches) <- parseCLIOpts defaultStreamSize
32+ runMode (mode cfg) cfg benches
3133 [
3234 bgroup "aheadly"
3335 [ benchIO "toNullAp" $ Ops.toNullAp linearCount aheadly
@@ -81,10 +83,3 @@ main = do
8183 [ benchIO "toNullAp" $ Ops.toNullAp linearCount zipAsyncly
8284 ]
8385 ]
84− where
85− defaultValue = 100000
86− parseValue [] = (defaultValue, [])
87− parseValue a@(x:xs) =
88− case (readMaybe x :: Maybe Int) of
89− Just value -> (value, xs)
90− Nothing -> (defaultValue, a)
streamly.cabal+9−13
@@ -584,21 +584,17 @@ test-suite parallel-loops
584584-- Benchmarks
585585-------------------------------------------------------------------------------
586586
587−-- NOTE :
588−-- For linear, linear-async, linear-rate, nested and nested-concurrent if you
589−-- want to pass the number of stream elements for benchmarking, you can pass it
590−-- as the first argument after `--`, as a gauge argument. If you don't give the
591−-- argument, the number of stream elements default to 100000.
592−-- Examples:
593−-- $ cabal run linear -- 1000000 [additional gauge options here...]
594−-- $ cabal run linear -- [additional gauge options here...]
587+-- For linear, linear-async, linear-rate, nested and nested-concurrent
588+-- you can pass the number of elements in the stream using the
589+-- --stream-size option:
590+-- $ cabal run linear -- --stream-size 1000000
595591
596592benchmark linear
597593 import: bench-options
598594 type: exitcode-stdio-1.0
599595 hs-source-dirs: benchmark
600596 main-is: Linear.hs
601− other-modules: Streamly.Benchmark.Prelude
597+ other-modules: Streamly.Benchmark.Prelude, Common
602598 build-depends:
603599 streamly
604600 , base >= 4.8 && < 5
@@ -617,7 +613,7 @@ benchmark nested
617613 type: exitcode-stdio-1.0
618614 hs-source-dirs: benchmark
619615 main-is: Nested.hs
620− other-modules: NestedOps
616+ other-modules: NestedOps, Common
621617 build-depends:
622618 streamly
623619 , base >= 4.8 && < 5
@@ -721,7 +717,7 @@ benchmark linear-async
721717 type: exitcode-stdio-1.0
722718 hs-source-dirs: benchmark
723719 main-is: LinearAsync.hs
724− other-modules: Streamly.Benchmark.Prelude
720+ other-modules: Streamly.Benchmark.Prelude, Common
725721 build-depends:
726722 streamly
727723 , base >= 4.8 && < 5
@@ -740,7 +736,7 @@ benchmark nested-concurrent
740736 type: exitcode-stdio-1.0
741737 hs-source-dirs: benchmark
742738 main-is: NestedConcurrent.hs
743− other-modules: NestedOps
739+ other-modules: NestedOps, Common
744740 build-depends:
745741 streamly
746742 , base >= 4.8 && < 5
@@ -756,7 +752,7 @@ benchmark linear-rate
756752 type: exitcode-stdio-1.0
757753 hs-source-dirs: benchmark
758754 main-is: LinearRate.hs
759− other-modules: Streamly.Benchmark.Prelude
755+ other-modules: Streamly.Benchmark.Prelude, Common
760756 build-depends:
761757 streamly
762758 , base >= 4.8 && < 5