2{-# OPTIONS_GHC -Wno-orphans #-}
5-- Module : Streamly.Benchmark.Common
6-- Copyright : (c) 2019 Composewell Technologies
9-- Maintainer : streamly@composewell.com
11module Streamly.Benchmark.Common
36#ifdef MIN_VERSION_gauge
37import Control.Exception (evaluate)
38import Control.Monad (when)
39import Text.Read (readMaybe)
40import Data.List (scanl')
41import Data.Maybe (mapMaybe)
42import System.Console.GetOpt
43 (OptDescr(..), ArgDescr(..), ArgOrder(..), getOpt')
44import System.Environment (getArgs, lookupEnv, setEnv)
46import Data.Proxy (Proxy(..))
47import Test.Tasty.Ingredients.Basic (includingOptions)
48import Test.Tasty.Options
49 (IsOption(..), OptionDescription(..), lookupOption, safeRead)
50import Test.Tasty.Runners (Ingredient, defaultMainWithIngredients, parseOptions)
52import Control.DeepSeq (NFData(..))
53import Data.Functor.Identity (Identity, runIdentity)
54import System.Random (randomRIO)
56import qualified Streamly.Internal.Data.Fold as Fold
57import qualified Streamly.Internal.Data.Stream.StreamD as S
61-------------------------------------------------------------------------------
63-------------------------------------------------------------------------------
65o_1_space_prefix :: String -> String
66o_1_space_prefix name = name ++ "/o-1-space"
68o_n_space_prefix :: String -> String
69o_n_space_prefix name = name ++ "/o-n-space"
71o_n_heap_prefix :: String -> String
72o_n_heap_prefix name = name ++ "/o-n-heap"
74o_n_stack_prefix :: String -> String
75o_n_stack_prefix name = name ++ "/o-n-stack"
77-------------------------------------------------------------------------------
78-- Benchmarking utilities
79-------------------------------------------------------------------------------
81-- XXX once we convert all the functions to use this we can rename this to
83{-# INLINE benchIOSink1 #-}
84benchIOSink1 :: NFData b => String -> (Int -> IO b) -> Benchmark
85benchIOSink1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
87{-# INLINE benchIOSrc1 #-}
88benchIOSrc1 :: String -> (Int -> IO ()) -> Benchmark
89benchIOSrc1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
91-- We need a monadic bind here to make sure that the function f does not get
92-- completely optimized out by the compiler in some cases.
93{-# INLINE benchFold #-}
95 => String -> (t IO Int -> IO b) -> (Int -> t IO Int) -> Benchmark
96benchFold name f src = bench name $ nfIO $ randomRIO (1,1) >>= f . src
98{-# INLINE benchPure #-}
99benchPure :: NFData b => String -> (Int -> a) -> (a -> b) -> Benchmark
100benchPure name src f = bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
102-- XXX once we convert all the functions to use this we can rename this to
104{-# INLINE benchPureSink1 #-}
105benchPureSink1 :: NFData b => String -> (Int -> Identity b) -> Benchmark
106benchPureSink1 name f =
107 bench name $ nfIO $ randomRIO (1,1) >>= return . runIdentity . f
109{-# INLINE benchPureSrc #-}
110benchPureSrc :: String -> (Int -> S.Stream Identity a) -> Benchmark
111benchPureSrc name src = benchPure name src (runIdentity . drain)
115 drain = S.fold Fold.drain
117-------------------------------------------------------------------------------
118-- String/List generation for read instances
119-------------------------------------------------------------------------------
121{-# INLINABLE mkString #-}
122mkString :: Int -> String
123mkString value = "fromList [1" ++ concat (replicate value ",1") ++ "]"
125{-# INLINABLE mkListString #-}
126mkListString :: Int -> String
127mkListString value = "[1" ++ concat (replicate value ",1") ++ "]"
129{-# INLINABLE mkList #-}
130mkList :: Int -> [Int]
131mkList value = [1..value]
133-------------------------------------------------------------------------------
135-------------------------------------------------------------------------------
137defaultStreamSize :: Int
138defaultStreamSize = 100000
140-------------------------------------------------------------------------------
141-- Parse custom CLI options
142-------------------------------------------------------------------------------
144newtype BenchOpts = StreamSize Int deriving Show
146#ifdef MIN_VERSION_gauge
147getStreamSize :: String -> Int
149 case (readMaybe size :: Maybe Int) of
151 Nothing -> error "Stream size must be numeric"
153options :: [OptDescr BenchOpts]
156 System.Console.GetOpt.Option [] ["stream-size"] (ReqArg getSize "COUNT") "Stream element count"
161 getSize = StreamSize . getStreamSize
164 :: (Maybe String, Maybe String) -- (prev, yielded)
166 -> (Maybe String, Maybe String)
167deleteOptArgs (Nothing, _) opt =
168 if opt == "--stream-size"
169 then (Just opt, Nothing)
170 else (Just opt, Just opt)
172deleteOptArgs (Just prev, _) opt =
173 if opt == "--stream-size" || prev == "--stream-size"
174 then (Just opt, Nothing)
175 else (Just opt, Just opt)
177parseCLIOpts :: Int -> IO (Int, Config, [String])
178parseCLIOpts defStreamSize = do
180 -- Parse custom options
181 let (opts, _, _, errs) = getOpt' Permute options args
182 when (not $ null errs) $ error $ concat errs
183 (streamSize, args') <-
185 StreamSize x : _ -> do
186 putStrLn $ "Stream size: " ++ show x
187 -- When using the gauge "--measure-with" option we need to make
188 -- sure that we pass the stream size to child process forked by
189 -- gauge. So we use this env var for that purpose.
190 setEnv "STREAM_SIZE" (show x)
191 -- Hack! remove the option and its argument from args
192 -- getOpt should have a way to return the unconsumed args in
197 $ scanl' deleteOptArgs (Nothing, Nothing) args
200 r <- lookupEnv "STREAM_SIZE"
203 s <- evaluate $ getStreamSize x
206 setEnv "STREAM_SIZE" (show defStreamSize)
207 return (defStreamSize, args)
209 -- Parse gauge options
210 let config = defaultConfig
213 , includeFirstIter = streamSize > defStreamSize
215 let (cfg, benches) = parseWith config args'
216 streamSize `seq` return (streamSize, cfg, benches)
219instance IsOption BenchOpts where
220 defaultValue = StreamSize defaultStreamSize
221 parseValue = fmap StreamSize . safeRead
222 optionName = pure "stream-size"
223 optionHelp = pure "Size of the stream to be used in benchmarks"
225parseCLIOpts :: Int -> Benchmark -> IO (Int, [Ingredient])
226parseCLIOpts defStreamSize benches = do
227 let customOpts = [Test.Tasty.Options.Option (Proxy :: Proxy BenchOpts)]
228 ingredients = includingOptions customOpts : benchIngredients
229 opts <- parseOptions ingredients benches -- (TestGroup "" [])
230 let StreamSize size = lookupOption opts
231 -- putStrLn $ "Stream size: " ++ show size
232 if size == defaultStreamSize
233 then return (defStreamSize, ingredients)
234 else return (size, ingredients)
237runWithCLIOptsEnv :: Int -> (Int -> IO a) -> (a -> Int -> [Benchmark]) -> IO ()
238runWithCLIOptsEnv defStreamSize alloc mkBench = do
240#ifdef MIN_VERSION_gauge
241 (value, cfg, benches) <- parseCLIOpts defStreamSize
243 value `seq` runMode (mode cfg) cfg benches (mkBench r value)
246 (value, ingredients) <-
247 parseCLIOpts defStreamSize $ bgroup "All" (mkBench r0 0)
249 value `seq` defaultMainWithIngredients ingredients
250 $ bgroup "All" (mkBench r value)
253runWithCLIOpts :: Int -> (Int -> [Benchmark]) -> IO ()
254runWithCLIOpts defStreamSize f =
255 runWithCLIOptsEnv defStreamSize
256 (const $ return undefined)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list