mirror of
https://github.com/ilyakooo0/streamly.git
synced 2024-10-05 20:58:38 +03:00
add linear-async, base streams benchmark reporting
split linear to separate serial and parallel modules. Parallel modules use lower number of elements in the stream so that they can run faster.
This commit is contained in:
parent
54bb7ea8fd
commit
a929a1682c
43
bench.sh
43
bench.sh
@ -39,8 +39,7 @@ set_benchmarks() {
|
||||
|
||||
# $1: benchmark name (linear, nested, base)
|
||||
find_report_prog() {
|
||||
local bench_name=$1
|
||||
local prog_name="chart-$bench_name"
|
||||
local prog_name="chart"
|
||||
hash -r
|
||||
local prog_path=$($STACK exec which $prog_name)
|
||||
if test -x "$prog_path"
|
||||
@ -53,8 +52,7 @@ find_report_prog() {
|
||||
|
||||
# $1: benchmark name (linear, nested, base)
|
||||
build_report_prog() {
|
||||
local bench_name=$1
|
||||
local prog_name="chart-$bench_name"
|
||||
local prog_name="chart"
|
||||
local prog_path=$($STACK exec which $prog_name)
|
||||
|
||||
hash -r
|
||||
@ -71,18 +69,13 @@ build_report_prog() {
|
||||
}
|
||||
|
||||
build_report_progs() {
|
||||
local bench_list=$1
|
||||
|
||||
if test "$RAW" = "0"
|
||||
then
|
||||
for i in $bench_list
|
||||
do
|
||||
build_report_prog $i || exit 1
|
||||
build_report_prog || exit 1
|
||||
local prog
|
||||
prog=$(find_report_prog $i) || \
|
||||
die "Cannot find bench-graph executable for benchmark $i"
|
||||
prog=$(find_report_prog) || \
|
||||
die "Cannot find bench-graph executable"
|
||||
echo "Using bench-graph executable [$prog]"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
@ -198,25 +191,16 @@ run_measurements() {
|
||||
fi
|
||||
}
|
||||
|
||||
run_report() {
|
||||
local bench_name=$1
|
||||
local input_file=$2
|
||||
|
||||
if test "$RAW" = "0"
|
||||
then
|
||||
local prog
|
||||
prog=$(find_report_prog $bench_name) || \
|
||||
die "Cannot find bench-graph executable for benchmark $bench_name"
|
||||
echo
|
||||
echo "Generating reports for ${bench_name}..."
|
||||
$prog
|
||||
fi
|
||||
}
|
||||
|
||||
run_reports() {
|
||||
local prog
|
||||
prog=$(find_report_prog) || \
|
||||
die "Cannot find bench-graph executable"
|
||||
echo
|
||||
|
||||
for i in $1
|
||||
do
|
||||
run_report $i
|
||||
echo "Generating reports for ${i}..."
|
||||
$prog --benchmark $i
|
||||
done
|
||||
}
|
||||
|
||||
@ -290,4 +274,7 @@ fi
|
||||
# Run reports
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
if test "$RAW" = "0"
|
||||
then
|
||||
run_reports "$BENCHMARKS"
|
||||
fi
|
||||
|
187
benchmark/Chart.hs
Normal file
187
benchmark/Chart.hs
Normal file
@ -0,0 +1,187 @@
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Exception (handle, catch, SomeException, ErrorCall(..))
|
||||
import Control.Monad.Trans.State
|
||||
import Control.Monad.Trans.Maybe
|
||||
import Data.List
|
||||
import Data.List.Split
|
||||
import Data.Ord (comparing)
|
||||
import System.Environment (getArgs)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Control.Monad (mzero)
|
||||
|
||||
import BenchGraph
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Command line parsing
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
data BenchType = Linear | LinearAsync | Nested | Base
|
||||
|
||||
data Options = Options
|
||||
{ genGraphs :: Bool
|
||||
, benchType :: BenchType
|
||||
}
|
||||
|
||||
defaultOptions = Options False Linear
|
||||
|
||||
setGenGraphs val = do
|
||||
(args, opts) <- get
|
||||
put (args, opts { genGraphs = val })
|
||||
|
||||
setBenchType val = do
|
||||
(args, opts) <- get
|
||||
put (args, opts { benchType = val })
|
||||
|
||||
-- Like the shell "shift" to shift the command line arguments
|
||||
shift :: StateT ([String], Options) (MaybeT IO) (Maybe String)
|
||||
shift = do
|
||||
s <- get
|
||||
case s of
|
||||
([], _) -> return Nothing
|
||||
(x : xs, opts) -> put (xs, opts) >> return (Just x)
|
||||
|
||||
parseBench :: StateT ([String], Options) (MaybeT IO) ()
|
||||
parseBench = do
|
||||
x <- shift
|
||||
case x of
|
||||
Just "linear" -> setBenchType Linear
|
||||
Just "linear-async" -> setBenchType LinearAsync
|
||||
Just "nested" -> setBenchType Nested
|
||||
Just "base" -> setBenchType Base
|
||||
Just str -> do
|
||||
liftIO $ putStrLn $ "unrecognized benchmark type " ++ str
|
||||
mzero
|
||||
Nothing -> do
|
||||
liftIO $ putStrLn $ "please provide a benchmark type "
|
||||
mzero
|
||||
|
||||
-- totally imperative style option parsing
|
||||
parseOptions :: IO (Maybe Options)
|
||||
parseOptions = do
|
||||
args <- getArgs
|
||||
runMaybeT $ flip evalStateT (args, defaultOptions) $ do
|
||||
x <- shift
|
||||
case x of
|
||||
Just "--graphs" -> setGenGraphs True
|
||||
Just "--benchmark" -> parseBench
|
||||
Just str -> do
|
||||
liftIO $ putStrLn $ "Unrecognized option " ++ str
|
||||
mzero
|
||||
Nothing -> return ()
|
||||
fmap snd get
|
||||
|
||||
ignoringErr a = catch a (\(ErrorCall err :: ErrorCall) ->
|
||||
putStrLn $ "Failed with error:\n" ++ err ++ "\nSkipping.")
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Linear composition charts
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
makeLinearGraphs :: Config -> String -> IO ()
|
||||
makeLinearGraphs cfg inputFile = do
|
||||
ignoringErr $ graph inputFile "operations" $ cfg
|
||||
{ title = Just "Streamly operations"
|
||||
, classifyBenchmark = \b ->
|
||||
if (not $ "serially/" `isPrefixOf` b)
|
||||
|| "/generation" `isInfixOf` b
|
||||
|| "/compose" `isInfixOf` b
|
||||
|| "/concat" `isSuffixOf` b
|
||||
then Nothing
|
||||
else Just ("Streamly", last $ splitOn "/" b)
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "generation" $ cfg
|
||||
{ title = Just "Stream generation"
|
||||
, classifyBenchmark = \b ->
|
||||
if "serially/generation" `isPrefixOf` b
|
||||
then Just ("Streamly", last $ splitOn "/" b)
|
||||
else Nothing
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "composition" $ cfg
|
||||
{ title = Just "Streamly composition performance"
|
||||
, classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose/"
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "composition-scaling"
|
||||
$ cfg
|
||||
{ title = Just "Streamly composition scaling"
|
||||
, classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose-"
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Nested composition charts
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
makeNestedGraphs :: Config -> String -> IO ()
|
||||
makeNestedGraphs cfg inputFile = do
|
||||
ignoringErr $ graph inputFile "nested-serial-diff" $ cfg
|
||||
{ title = Just "Nested serial"
|
||||
, classifyBenchmark = \b ->
|
||||
let ls = splitOn "/" b
|
||||
in case head ls of
|
||||
"serially" -> Just (head ls, last ls)
|
||||
_ -> Nothing
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Charts for parallel streams
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
makeLinearAsyncGraphs :: Config -> String -> IO ()
|
||||
makeLinearAsyncGraphs cfg inputFile = do
|
||||
putStrLn "Not implemented"
|
||||
return ()
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Charts for base streams
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
makeBaseGraphs :: Config -> String -> IO ()
|
||||
makeBaseGraphs cfg inputFile = do
|
||||
putStrLn "Not implemented"
|
||||
return ()
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- text reports
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
benchShow Options{..} cfg func inp out =
|
||||
if genGraphs
|
||||
then func cfg {outputDir = Just out} inp
|
||||
else
|
||||
ignoringErr $ report inp Nothing $ cfg
|
||||
{ selectBenchmarks =
|
||||
\f ->
|
||||
reverse $ map fst $
|
||||
sortBy (comparing snd) $ f $ ColumnIndex 1
|
||||
}
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let cfg = defaultConfig { presentation = Groups PercentDiff }
|
||||
res <- parseOptions
|
||||
|
||||
case res of
|
||||
Nothing -> do
|
||||
putStrLn "cannot parse options"
|
||||
return ()
|
||||
Just opts@Options{..} -> do
|
||||
case benchType of
|
||||
Linear -> benchShow opts cfg makeLinearGraphs
|
||||
"charts/linear/results.csv"
|
||||
"charts/linear"
|
||||
LinearAsync -> benchShow opts cfg makeLinearAsyncGraphs
|
||||
"charts/linear-async/results.csv"
|
||||
"charts/linear-async"
|
||||
Nested -> benchShow opts cfg makeNestedGraphs
|
||||
"charts/nested/results.csv"
|
||||
"charts/nested"
|
||||
Base -> benchShow opts cfg makeBaseGraphs
|
||||
"charts/base/results.csv"
|
||||
"charts/base"
|
@ -1,90 +0,0 @@
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Exception (handle, catch, SomeException, ErrorCall(..))
|
||||
import Control.Monad.Trans.State
|
||||
import Control.Monad.Trans.Maybe
|
||||
import Data.List
|
||||
import Data.List.Split
|
||||
import Data.Ord (comparing)
|
||||
import System.Environment (getArgs)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Control.Monad (mzero)
|
||||
|
||||
import BenchGraph
|
||||
import Utils
|
||||
|
||||
ignoringErr a = catch a (\(ErrorCall err :: ErrorCall) ->
|
||||
putStrLn $ "Failed with error:\n" ++ err ++ "\nSkipping.")
|
||||
|
||||
makeGraphs cfg = do
|
||||
ignoringErr $ graph inputFile "operations" $ cfg
|
||||
{ title = Just "Streamly operations"
|
||||
, classifyBenchmark = \b ->
|
||||
if (not $ "serially/" `isPrefixOf` b)
|
||||
|| "/generation" `isInfixOf` b
|
||||
|| "/compose" `isInfixOf` b
|
||||
|| "/concat" `isSuffixOf` b
|
||||
then Nothing
|
||||
else Just ("Streamly", last $ splitOn "/" b)
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "generation" $ cfg
|
||||
{ title = Just "Stream generation"
|
||||
, classifyBenchmark = \b ->
|
||||
if "serially/generation" `isPrefixOf` b
|
||||
then Just ("Streamly", last $ splitOn "/" b)
|
||||
else Nothing
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "composition" $ cfg
|
||||
{ title = Just "Streamly composition performance"
|
||||
, classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose/"
|
||||
}
|
||||
|
||||
ignoringErr $ graph inputFile "composition-scaling"
|
||||
$ cfg
|
||||
{ title = Just "Streamly composition scaling"
|
||||
, classifyBenchmark = fmap ("Streamly",) . stripPrefix "serially/compose-"
|
||||
}
|
||||
|
||||
inputFile :: String
|
||||
inputFile = "charts/linear/results.csv"
|
||||
|
||||
-- Primitive command line options parsing
|
||||
data Options = Options
|
||||
{ genGraphs :: Bool
|
||||
}
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let cfg = defaultConfig
|
||||
{ outputDir = Just "charts/linear"
|
||||
, presentation = Groups PercentDiff
|
||||
}
|
||||
|
||||
args <- getArgs
|
||||
res <- runMaybeT $ flip evalStateT args $ do
|
||||
x <- shift
|
||||
case x of
|
||||
Just "--graphs" -> return $ Options { genGraphs = True }
|
||||
Nothing -> return $ Options { genGraphs = False }
|
||||
Just str -> do
|
||||
liftIO $ putStrLn $ "Unrecognized option " ++ str
|
||||
mzero
|
||||
|
||||
case res of
|
||||
Nothing -> return ()
|
||||
Just Options{..} ->
|
||||
if genGraphs
|
||||
then makeGraphs cfg
|
||||
else
|
||||
ignoringErr $ report inputFile Nothing $ cfg
|
||||
{ selectBenchmarks =
|
||||
\f ->
|
||||
reverse $ map fst $
|
||||
sortBy (comparing snd) $ f $ ColumnIndex 1
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
{-# LANGUAGE TupleSections #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Control.Exception (handle, catch, SomeException, ErrorCall)
|
||||
import Control.Monad.Trans.State
|
||||
import Control.Monad.Trans.Maybe
|
||||
import Data.List
|
||||
import Data.List.Split
|
||||
import Data.Ord (comparing)
|
||||
import System.Environment (getArgs)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import Control.Monad (mzero)
|
||||
|
||||
import BenchGraph
|
||||
import Utils
|
||||
|
||||
ignoringErr a = catch a (\(_ :: ErrorCall) ->
|
||||
putStrLn "Failed. Skipping.")
|
||||
|
||||
makeGraphs :: Config -> IO ()
|
||||
makeGraphs cfg = do
|
||||
ignoringErr $ graph inputFile "nested-serial-diff" $ cfg
|
||||
{ title = Just "Nested serial"
|
||||
, classifyBenchmark = \b ->
|
||||
let ls = splitOn "/" b
|
||||
in case head ls of
|
||||
"serially" -> Just (head ls, last ls)
|
||||
_ -> Nothing
|
||||
}
|
||||
|
||||
-- Primitive command line options parsing
|
||||
data Options = Options
|
||||
{ genGraphs :: Bool
|
||||
}
|
||||
|
||||
inputFile :: String
|
||||
inputFile = "charts/nested/results.csv"
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let cfg = defaultConfig
|
||||
{ outputDir = Just "charts/nested"
|
||||
, presentation = Groups PercentDiff
|
||||
}
|
||||
|
||||
args <- getArgs
|
||||
res <- runMaybeT $ flip evalStateT args $ do
|
||||
x <- shift
|
||||
case x of
|
||||
Just "--graphs" -> return $ Options { genGraphs = True }
|
||||
Nothing -> return $ Options { genGraphs = False }
|
||||
Just str -> do
|
||||
liftIO $ putStrLn $ "Unrecognized option " ++ str
|
||||
mzero
|
||||
|
||||
case res of
|
||||
Nothing -> return ()
|
||||
Just Options{..} ->
|
||||
if genGraphs
|
||||
then makeGraphs cfg
|
||||
else
|
||||
ignoringErr $ report inputFile Nothing $ cfg
|
||||
{ selectBenchmarks =
|
||||
\f ->
|
||||
reverse $ map fst $
|
||||
sortBy (comparing snd) $ f $ ColumnIndex 1
|
||||
}
|
@ -19,7 +19,7 @@ import Gauge
|
||||
-- | Takes a fold method, and uses it with a default source.
|
||||
{-# INLINE benchIO #-}
|
||||
benchIO :: (IsStream t, NFData b) => String -> (t IO Int -> IO b) -> Benchmark
|
||||
benchIO name f = bench name $ nfIO $ randomRIO (1,1000) >>= f . Ops.source
|
||||
benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source
|
||||
|
||||
-- | Takes a source, and uses it with a default drain/fold method.
|
||||
{-# INLINE benchSrcIO #-}
|
||||
@ -29,7 +29,7 @@ benchSrcIO
|
||||
-> (Int -> t IO Int)
|
||||
-> Benchmark
|
||||
benchSrcIO t name f
|
||||
= bench name $ nfIO $ randomRIO (1,1000) >>= Ops.toNull t . f
|
||||
= bench name $ nfIO $ randomRIO (1,1) >>= Ops.toNull t . f
|
||||
|
||||
{-
|
||||
_benchId :: NFData b => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
|
||||
@ -123,77 +123,4 @@ main = do
|
||||
, benchIO "4" $ Ops.composeScaling 4
|
||||
]
|
||||
]
|
||||
, bgroup "asyncly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull asyncly
|
||||
benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
-- , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM asyncly
|
||||
, benchSrcIO asyncly "unfoldrM maxThreads 1"
|
||||
(maxThreads 1 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM maxBuffer 1 (1000 ops)"
|
||||
(maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
|
||||
]
|
||||
, bgroup "asyncly/rate"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull asyncly
|
||||
benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
, benchSrcIO asyncly "unfoldrM/Nothing"
|
||||
(rate Nothing . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/1,000,000"
|
||||
(avgRate 1000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/3,000,000"
|
||||
(avgRate 3000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/10,000,000/maxThreads1"
|
||||
(maxThreads 1 . avgRate 10000000 . Ops.sourceUnfoldrM)
|
||||
-- XXX arbitrarily large rate should be the same as rate Nothing
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/10,000,000"
|
||||
(avgRate 10000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/20,000,000"
|
||||
(avgRate 20000000 . Ops.sourceUnfoldrM)
|
||||
]
|
||||
, bgroup "wAsyncly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull wAsyncly
|
||||
benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
-- , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM wAsyncly
|
||||
]
|
||||
-- unfoldr and fromFoldable are always serial and thereofore the same for
|
||||
-- all stream types.
|
||||
, bgroup "aheadly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull aheadly
|
||||
benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
|
||||
, benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM aheadly
|
||||
, benchSrcIO aheadly "unfoldrM maxThreads 1"
|
||||
(maxThreads 1 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
|
||||
(maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
|
||||
-- , benchSrcIO aheadly "fromFoldable" Ops.sourceFromFoldable
|
||||
]
|
||||
, bgroup "aheadly/rate"
|
||||
[
|
||||
-- XXX arbitrarily large maxRate should be the same as maxRate -1
|
||||
benchSrcIO aheadly "unfoldrM rate AvgRate 1000000"
|
||||
(avgRate 1000000 . Ops.sourceUnfoldrM)
|
||||
]
|
||||
-- XXX need to use smaller streams to finish in reasonable time
|
||||
, bgroup "parallely"
|
||||
[ --benchIO "unfoldr" $ Ops.toNull parallely
|
||||
benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
|
||||
--, benchSrcIO parallely "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM parallely
|
||||
-- Zip has only one parallel flavor
|
||||
, benchIO "zip" $ Ops.zipAsync
|
||||
, benchIO "zipM" $ Ops.zipAsyncM
|
||||
]
|
||||
]
|
||||
|
115
benchmark/LinearAsync.hs
Normal file
115
benchmark/LinearAsync.hs
Normal file
@ -0,0 +1,115 @@
|
||||
-- |
|
||||
-- Module : Main
|
||||
-- Copyright : (c) 2018 Harendra Kumar
|
||||
--
|
||||
-- License : BSD3
|
||||
-- Maintainer : harendra.kumar@gmail.com
|
||||
|
||||
import Control.DeepSeq (NFData)
|
||||
-- import Data.Functor.Identity (Identity, runIdentity)
|
||||
import System.Random (randomRIO)
|
||||
import qualified LinearOps as Ops
|
||||
|
||||
import Streamly
|
||||
import Gauge
|
||||
|
||||
-- We need a monadic bind here to make sure that the function f does not get
|
||||
-- completely optimized out by the compiler in some cases.
|
||||
--
|
||||
-- | Takes a fold method, and uses it with a default source.
|
||||
{-# INLINE benchIO #-}
|
||||
benchIO :: (IsStream t, NFData b) => String -> (t IO Int -> IO b) -> Benchmark
|
||||
benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f . Ops.source
|
||||
|
||||
-- | Takes a source, and uses it with a default drain/fold method.
|
||||
{-# INLINE benchSrcIO #-}
|
||||
benchSrcIO
|
||||
:: (t IO Int -> SerialT IO Int)
|
||||
-> String
|
||||
-> (Int -> t IO Int)
|
||||
-> Benchmark
|
||||
benchSrcIO t name f
|
||||
= bench name $ nfIO $ randomRIO (1,1) >>= Ops.toNull t . f
|
||||
|
||||
{-
|
||||
_benchId :: NFData b => String -> (Ops.Stream m Int -> Identity b) -> Benchmark
|
||||
_benchId name f = bench name $ nf (runIdentity . f) (Ops.source 10)
|
||||
-}
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
defaultMain
|
||||
[ bgroup "asyncly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull asyncly
|
||||
benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
-- , benchSrcIO asyncly "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO asyncly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO asyncly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO asyncly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM asyncly
|
||||
, benchSrcIO asyncly "unfoldrM maxThreads 1"
|
||||
(maxThreads 1 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM maxBuffer 1 (1000 ops)"
|
||||
(maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
|
||||
]
|
||||
, bgroup "asyncly/rate"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull asyncly
|
||||
benchSrcIO asyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
, benchSrcIO asyncly "unfoldrM/Nothing"
|
||||
(rate Nothing . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/1,000,000"
|
||||
(avgRate 1000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/3,000,000"
|
||||
(avgRate 3000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/10,000,000/maxThreads1"
|
||||
(maxThreads 1 . avgRate 10000000 . Ops.sourceUnfoldrM)
|
||||
-- XXX arbitrarily large rate should be the same as rate Nothing
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/10,000,000"
|
||||
(avgRate 10000000 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO asyncly "unfoldrM/AvgRate/20,000,000"
|
||||
(avgRate 20000000 . Ops.sourceUnfoldrM)
|
||||
]
|
||||
, bgroup "wAsyncly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull wAsyncly
|
||||
benchSrcIO wAsyncly "unfoldrM" Ops.sourceUnfoldrM
|
||||
-- , benchSrcIO wAsyncly "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO wAsyncly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO wAsyncly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO wAsyncly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM wAsyncly
|
||||
]
|
||||
-- unfoldr and fromFoldable are always serial and thereofore the same for
|
||||
-- all stream types.
|
||||
, bgroup "aheadly"
|
||||
[ -- benchIO "unfoldr" $ Ops.toNull aheadly
|
||||
benchSrcIO aheadly "unfoldrM" Ops.sourceUnfoldrM
|
||||
, benchSrcIO aheadly "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO aheadly "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO aheadly "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM aheadly
|
||||
, benchSrcIO aheadly "unfoldrM maxThreads 1"
|
||||
(maxThreads 1 . Ops.sourceUnfoldrM)
|
||||
, benchSrcIO aheadly "unfoldrM maxBuffer 1 (1000 ops)"
|
||||
(maxBuffer 1 . Ops.sourceUnfoldrMN 1000)
|
||||
-- , benchSrcIO aheadly "fromFoldable" Ops.sourceFromFoldable
|
||||
]
|
||||
, bgroup "aheadly/rate"
|
||||
[
|
||||
-- XXX arbitrarily large maxRate should be the same as maxRate -1
|
||||
benchSrcIO aheadly "unfoldrM rate AvgRate 1000000"
|
||||
(avgRate 1000000 . Ops.sourceUnfoldrM)
|
||||
]
|
||||
-- XXX need to use smaller streams to finish in reasonable time
|
||||
, bgroup "parallely"
|
||||
[ --benchIO "unfoldr" $ Ops.toNull parallely
|
||||
benchSrcIO parallely "unfoldrM" Ops.sourceUnfoldrM
|
||||
--, benchSrcIO parallely "fromFoldable" Ops.sourceFromFoldable
|
||||
, benchSrcIO parallely "fromFoldableM" Ops.sourceFromFoldableM
|
||||
-- , benchSrcIO parallely "foldMapWith" Ops.sourceFoldMapWith
|
||||
, benchSrcIO parallely "foldMapWithM" Ops.sourceFoldMapWithM
|
||||
, benchIO "mapM" $ Ops.mapM parallely
|
||||
-- Zip has only one parallel flavor
|
||||
, benchIO "zip" $ Ops.zipAsync
|
||||
, benchIO "zipM" $ Ops.zipAsyncM
|
||||
]
|
||||
]
|
@ -5,6 +5,7 @@
|
||||
-- License : MIT
|
||||
-- Maintainer : harendra.kumar@gmail.com
|
||||
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
|
||||
module LinearOps where
|
||||
@ -18,8 +19,12 @@ import qualified Streamly as S
|
||||
import qualified Streamly.Prelude as S
|
||||
|
||||
value, maxValue :: Int
|
||||
#ifdef LINEAR_ASYNC
|
||||
value = 10000
|
||||
#else
|
||||
value = 100000
|
||||
maxValue = value + 1000
|
||||
#endif
|
||||
maxValue = value + 1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Benchmark ops
|
||||
|
@ -1,13 +0,0 @@
|
||||
module Utils where
|
||||
|
||||
import Control.Monad.Trans.State
|
||||
import Control.Monad.Trans.Maybe
|
||||
|
||||
-- Like the shell "shift" to shift the command line arguments
|
||||
shift :: StateT [String] (MaybeT IO) (Maybe String)
|
||||
shift = do
|
||||
s <- get
|
||||
case s of
|
||||
[] -> return Nothing
|
||||
x : xs -> put xs >> return (Just x)
|
||||
|
@ -10,9 +10,9 @@ extra-deps:
|
||||
- Chart-diagrams-1.9
|
||||
- SVGFonts-1.6.0.3
|
||||
- math-functions-0.3.0.2
|
||||
- git: git@github.com:composewell/bench-graph
|
||||
- git: https://github.com/composewell/bench-graph
|
||||
commit: 27ea72037f01e252364197e4771e25478af97972
|
||||
- git: git@github.com:harendra-kumar/statistics
|
||||
- git: https://github.com/harendra-kumar/statistics
|
||||
commit: d3c4743c28fdd83d578039867f1a046596f77140
|
||||
subdirs:
|
||||
- dense-linear-algebra
|
||||
|
@ -323,6 +323,34 @@ benchmark linear
|
||||
, random >= 1.0 && < 2.0
|
||||
, gauge >= 0.2.3 && < 0.3
|
||||
|
||||
benchmark linear-async
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: benchmark
|
||||
main-is: LinearAsync.hs
|
||||
other-modules: LinearOps
|
||||
default-language: Haskell2010
|
||||
ghc-options: -O2 -Wall
|
||||
cpp-options: -DLINEAR_ASYNC
|
||||
if flag(dev)
|
||||
ghc-options: -Wmissed-specialisations
|
||||
-Wall-missed-specialisations
|
||||
-fno-ignore-asserts
|
||||
if impl(ghc >= 8.0)
|
||||
ghc-options: -Wcompat
|
||||
-Wunrecognised-warning-flags
|
||||
-Widentities
|
||||
-Wincomplete-record-updates
|
||||
-Wincomplete-uni-patterns
|
||||
-Wredundant-constraints
|
||||
-Wnoncanonical-monad-instances
|
||||
-Wnoncanonical-monadfail-instances
|
||||
build-depends:
|
||||
streamly
|
||||
, base >= 4.8 && < 5
|
||||
, deepseq >= 1.4.0 && < 1.5
|
||||
, random >= 1.0 && < 2.0
|
||||
, gauge >= 0.2.3 && < 0.3
|
||||
|
||||
benchmark nested
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: benchmark
|
||||
@ -410,31 +438,15 @@ benchmark base
|
||||
build-depends:
|
||||
semigroups >= 0.18 && < 0.19
|
||||
|
||||
executable chart-linear
|
||||
executable chart
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: benchmark
|
||||
main-is: ChartLinear.hs
|
||||
other-modules: Utils
|
||||
main-is: Chart.hs
|
||||
if flag(dev)
|
||||
buildable: True
|
||||
build-Depends:
|
||||
base >= 4.8 && < 5
|
||||
, bench-graph >= 0.1 && < 0.2
|
||||
, split
|
||||
, transformers
|
||||
else
|
||||
buildable: False
|
||||
|
||||
executable chart-nested
|
||||
default-language: Haskell2010
|
||||
hs-source-dirs: benchmark
|
||||
main-is: ChartNested.hs
|
||||
other-modules: Utils
|
||||
if flag(dev)
|
||||
buildable: True
|
||||
build-Depends:
|
||||
base >= 4.8 && < 5
|
||||
, bench-graph >= 0.1 && < 0.2
|
||||
, bench-graph >= 0.2 && < 0.3
|
||||
, split
|
||||
, transformers
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user