2#if __GLASGOW_HASKELL__ >= 800
3{-# OPTIONS_GHC -Wno-orphans #-}
7-- Module : Streamly.Benchmark.Common
8-- Copyright : (c) 2019 Composewell Technologies
11-- Maintainer : streamly@composewell.com
13module Streamly.Benchmark.Common
37import Control.DeepSeq (NFData(..))
38import Control.Exception (evaluate)
39import Control.Monad (when)
40import Data.Functor.Identity (Identity, runIdentity)
41import Data.List (scanl')
42import Data.Maybe (mapMaybe)
43import System.Console.GetOpt
44 (OptDescr(..), ArgDescr(..), ArgOrder(..), getOpt')
45import System.Environment (getArgs, lookupEnv, setEnv)
46import Text.Read (readMaybe)
47import System.Random (randomRIO)
49import qualified Streamly.Prelude as S
51import Streamly.Prelude (SerialT)
54-------------------------------------------------------------------------------
56-------------------------------------------------------------------------------
58o_1_space_prefix :: String -> String
59o_1_space_prefix name = name ++ "/o-1-space"
61o_n_space_prefix :: String -> String
62o_n_space_prefix name = name ++ "/o-n-space"
64o_n_heap_prefix :: String -> String
65o_n_heap_prefix name = name ++ "/o-n-heap"
67o_n_stack_prefix :: String -> String
68o_n_stack_prefix name = name ++ "/o-n-stack"
70-------------------------------------------------------------------------------
71-- Benchmarking utilities
72-------------------------------------------------------------------------------
74#if !MIN_VERSION_deepseq(1,4,3)
75instance NFData Ordering where rnf = (`seq` ())
78-- XXX once we convert all the functions to use this we can rename this to
80{-# INLINE benchIOSink1 #-}
81benchIOSink1 :: NFData b => String -> (Int -> IO b) -> Benchmark
82benchIOSink1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
84{-# INLINE benchIOSrc1 #-}
85benchIOSrc1 :: String -> (Int -> IO ()) -> Benchmark
86benchIOSrc1 name f = bench name $ nfIO $ randomRIO (1,1) >>= f
88-- We need a monadic bind here to make sure that the function f does not get
89-- completely optimized out by the compiler in some cases.
90{-# INLINE benchFold #-}
92 => String -> (t IO Int -> IO b) -> (Int -> t IO Int) -> Benchmark
93benchFold name f src = bench name $ nfIO $ randomRIO (1,1) >>= f . src
95{-# INLINE benchPure #-}
96benchPure :: NFData b => String -> (Int -> a) -> (a -> b) -> Benchmark
97benchPure name src f = bench name $ nfIO $ randomRIO (1,1) >>= return . f . src
99-- XXX once we convert all the functions to use this we can rename this to
101{-# INLINE benchPureSink1 #-}
102benchPureSink1 :: NFData b => String -> (Int -> Identity b) -> Benchmark
103benchPureSink1 name f =
104 bench name $ nfIO $ randomRIO (1,1) >>= return . runIdentity . f
106{-# INLINE benchPureSrc #-}
107benchPureSrc :: String -> (Int -> SerialT Identity a) -> Benchmark
108benchPureSrc name src = benchPure name src (runIdentity . S.drain)
110-------------------------------------------------------------------------------
111-- String/List generation for read instances
112-------------------------------------------------------------------------------
114{-# INLINABLE mkString #-}
115mkString :: Int -> String
116mkString value = "fromList [1" ++ concat (replicate value ",1") ++ "]"
118{-# INLINABLE mkListString #-}
119mkListString :: Int -> String
120mkListString value = "[1" ++ concat (replicate value ",1") ++ "]"
122{-# INLINABLE mkList #-}
123mkList :: Int -> [Int]
124mkList value = [1..value]
126-------------------------------------------------------------------------------
128-------------------------------------------------------------------------------
130defaultStreamSize :: Int
131defaultStreamSize = 100000
133-------------------------------------------------------------------------------
134-- Parse custom CLI options
135-------------------------------------------------------------------------------
137newtype BenchOpts = StreamSize Int deriving Show
139getStreamSize :: String -> Int
141 case (readMaybe size :: Maybe Int) of
143 Nothing -> error "Stream size must be numeric"
145options :: [OptDescr BenchOpts]
148 Option [] ["stream-size"] (ReqArg getSize "COUNT") "Stream element count"
153 getSize = StreamSize . getStreamSize
156 :: (Maybe String, Maybe String) -- (prev, yielded)
158 -> (Maybe String, Maybe String)
159deleteOptArgs (Nothing, _) opt =
160 if opt == "--stream-size"
161 then (Just opt, Nothing)
162 else (Just opt, Just opt)
164deleteOptArgs (Just prev, _) opt =
165 if opt == "--stream-size" || prev == "--stream-size"
166 then (Just opt, Nothing)
167 else (Just opt, Just opt)
169parseCLIOpts :: Int -> IO (Int, Config, [String])
170parseCLIOpts defStreamSize = do
173 -- Parse custom options
174 let (opts, _, _, errs) = getOpt' Permute options args
175 when (not $ null errs) $ error $ concat errs
176 (streamSize, args') <-
178 StreamSize x : _ -> do
179 putStrLn $ "Stream size: " ++ show x
180 -- When using the gauge "--measure-with" option we need to make
181 -- sure that we pass the stream size to child process forked by
182 -- gauge. So we use this env var for that purpose.
183 setEnv "STREAM_SIZE" (show x)
184 -- Hack! remove the option and its argument from args
185 -- getOpt should have a way to return the unconsumed args in
190 $ scanl' deleteOptArgs (Nothing, Nothing) args
193 r <- lookupEnv "STREAM_SIZE"
196 s <- evaluate $ getStreamSize x
199 setEnv "STREAM_SIZE" (show defStreamSize)
200 return (defStreamSize, args)
202 -- Parse gauge options
203 let config = defaultConfig
206 , includeFirstIter = streamSize > defStreamSize
208 let (cfg, benches) = parseWith config args'
209 streamSize `seq` return (streamSize, cfg, benches)
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