diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs b/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs index 173c980dee..500d7d7333 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Exceptions.hs @@ -21,21 +21,14 @@ module Stream.Exceptions (benchmarks) where -import Control.Exception (Exception, throwIO) -import Stream.Common (drain) - -import qualified Data.IORef as Ref -import qualified Data.Map.Strict as Map +import Control.Exception (Exception) import Control.Exception (SomeException) -import System.IO (Handle, hClose, hPutChar) +import System.IO (Handle, hClose) import qualified Streamly.FileSystem.Handle as FH import qualified Streamly.Internal.FileSystem.Handle as IFH import qualified Streamly.Internal.Data.Unfold as IUF -import qualified Streamly.Internal.Data.Unfold.Prelude as IUF - import qualified Streamly.Internal.Data.Stream as Stream -import qualified Streamly.Internal.Data.Stream.Prelude as Stream import Test.Tasty.Bench hiding (env) import Prelude hiding (last, length) @@ -45,23 +38,8 @@ import Streamly.Benchmark.Common.Handle #ifdef INSPECTION import Control.Monad.Catch (MonadCatch) import Test.Inspection - -import qualified Streamly.Internal.Data.Stream as D #endif -type Stream = Stream.Stream -toStreamD :: a -> a -toStreamD = id -fromStreamD :: a -> a -fromStreamD = id - -afterUnsafe :: IO b -> Stream IO a -> Stream IO a -finallyUnsafe :: IO b -> Stream IO a -> Stream IO a -bracketUnsafe :: IO b -> (b -> IO c) -> (b -> Stream IO a) -> Stream IO a -afterUnsafe = Stream.afterUnsafe -finallyUnsafe = Stream.finallyUnsafe -bracketUnsafe = Stream.bracketUnsafe - ------------------------------------------------------------------------------- -- stream exceptions ------------------------------------------------------------------------------- @@ -73,72 +51,6 @@ data BenchException instance Exception BenchException -retryNoneSimple :: Int -> Int -> IO () -retryNoneSimple length from = - drain - $ Stream.retry - (Map.singleton BenchException1 length) - (const Stream.nil) - source - - where - - source = Stream.enumerateFromTo from (from + length) - -retryNone :: Int -> Int -> IO () -retryNone length from = do - ref <- Ref.newIORef (0 :: Int) - drain - $ Stream.retry (Map.singleton BenchException1 length) (const Stream.nil) - $ source ref - - where - - source ref = - Stream.replicateM (from + length) - $ Ref.modifyIORef' ref (+ 1) >> Ref.readIORef ref - -retryAll :: Int -> Int -> IO () -retryAll length from = do - ref <- Ref.newIORef 0 - drain - $ Stream.retry - (Map.singleton BenchException1 (length + from)) (const Stream.nil) - $ source ref - - where - - source ref = - Stream.fromEffect - $ do - Ref.modifyIORef' ref (+ 1) - val <- Ref.readIORef ref - if val >= length - then return length - else throwIO BenchException1 - -retryUnknown :: Int -> Int -> IO () -retryUnknown length from = do - drain - $ Stream.retry (Map.singleton BenchException1 length) (const source) - $ throwIO BenchException2 `Stream.before` Stream.nil - - where - - source = Stream.enumerateFromTo from (from + length) - - -o_1_space_serial_exceptions :: Int -> [Benchmark] -o_1_space_serial_exceptions length = - [ bgroup - "exceptions/serial" - [ benchIOSrc1 "retryNoneSimple" (retryNoneSimple length) - , benchIOSrc1 "retryNone" (retryNone length) - , benchIOSrc1 "retryAll" (retryAll length) - , benchIOSrc1 "retryUnknown" (retryUnknown length) - ] - ] - -- XXX Move these to FileSystem.Handle benchmarks ------------------------------------------------------------------------------- @@ -171,63 +83,32 @@ inspect $ hasNoTypeClasses 'readWriteHandleExceptionStream readWriteFinally_Stream :: Handle -> Handle -> IO () readWriteFinally_Stream inh devNull = let readEx = - finallyUnsafe (hClose inh) (Stream.unfold FH.reader inh) + Stream.finallyUnsafe (hClose inh) (Stream.unfold FH.reader inh) in Stream.fold (FH.write devNull) readEx #ifdef INSPECTION inspect $ hasNoTypeClasses 'readWriteFinally_Stream #endif -readWriteFinallyStream :: Handle -> Handle -> IO () -readWriteFinallyStream inh devNull = - let readEx = Stream.finally (hClose inh) (Stream.unfold FH.reader inh) - in Stream.fold (FH.write devNull) readEx - -- | Send the file contents to /dev/null with exception handling fromToBytesBracket_Stream :: Handle -> Handle -> IO () fromToBytesBracket_Stream inh devNull = - let readEx = bracketUnsafe (return ()) (\_ -> hClose inh) - (\_ -> fromStreamD $ IFH.read inh) - in IFH.putBytes devNull (toStreamD readEx) + let readEx = Stream.bracketUnsafe (return ()) (\_ -> hClose inh) + (\_ -> IFH.read inh) + in IFH.putBytes devNull readEx #ifdef INSPECTION inspect $ hasNoTypeClasses 'fromToBytesBracket_Stream #endif -fromToBytesBracketStream :: Handle -> Handle -> IO () -fromToBytesBracketStream inh devNull = - let readEx = Stream.bracket (return ()) (\_ -> hClose inh) - (\_ -> fromStreamD $ IFH.read inh) - in IFH.putBytes devNull (toStreamD readEx) - -readWriteBeforeAfterStream :: Handle -> Handle -> IO () -readWriteBeforeAfterStream inh devNull = - let readEx = - Stream.after (hClose inh) - $ Stream.before (hPutChar devNull 'A') (Stream.unfold FH.reader inh) - in Stream.fold (FH.write devNull) readEx - -#ifdef INSPECTION -inspect $ 'readWriteBeforeAfterStream `hasNoType` ''D.Step -#endif - -readWriteAfterStream :: Handle -> Handle -> IO () -readWriteAfterStream inh devNull = - let readEx = Stream.after (hClose inh) (Stream.unfold FH.reader inh) - in Stream.fold (FH.write devNull) readEx - -#ifdef INSPECTION -inspect $ 'readWriteAfterStream `hasNoType` ''D.Step -#endif - readWriteAfter_Stream :: Handle -> Handle -> IO () readWriteAfter_Stream inh devNull = - let readEx = afterUnsafe (hClose inh) (Stream.unfold FH.reader inh) + let readEx = Stream.afterUnsafe (hClose inh) (Stream.unfold FH.reader inh) in Stream.fold (FH.write devNull) readEx #ifdef INSPECTION inspect $ hasNoTypeClasses 'readWriteAfter_Stream -inspect $ 'readWriteAfter_Stream `hasNoType` ''D.Step +inspect $ 'readWriteAfter_Stream `hasNoType` ''Stream.Step #endif o_1_space_copy_stream_exceptions :: BenchEnv -> [Benchmark] @@ -239,20 +120,12 @@ o_1_space_copy_stream_exceptions env = readWriteHandleExceptionStream inh (nullH env) , mkBenchSmall "Stream.finally_" env $ \inh _ -> readWriteFinally_Stream inh (nullH env) - , mkBenchSmall "Stream.finally" env $ \inh _ -> - readWriteFinallyStream inh (nullH env) - , mkBenchSmall "Stream.after . Stream.before" env $ \inh _ -> - readWriteBeforeAfterStream inh (nullH env) - , mkBenchSmall "Stream.after" env $ \inh _ -> - readWriteAfterStream inh (nullH env) , mkBenchSmall "Stream.after_" env $ \inh _ -> readWriteAfter_Stream inh (nullH env) ] , bgroup "exceptions/fromToBytes" [ mkBenchSmall "Stream.bracket_" env $ \inh _ -> fromToBytesBracket_Stream inh (nullH env) - , mkBenchSmall "Stream.bracket" env $ \inh _ -> - fromToBytesBracketStream inh (nullH env) ] ] @@ -288,11 +161,6 @@ inspect $ hasNoTypeClasses 'readChunksBracket_ #endif #endif -readChunksBracket :: Handle -> Handle -> IO () -readChunksBracket inh devNull = - let readEx = IUF.bracket return (\_ -> hClose inh) FH.chunkReader - in IUF.fold (IFH.writeChunks devNull) readEx inh - o_1_space_copy_exceptions_readChunks :: BenchEnv -> [Benchmark] o_1_space_copy_exceptions_readChunks env = [ bgroup "exceptions/readChunks" @@ -300,8 +168,6 @@ o_1_space_copy_exceptions_readChunks env = readChunksOnException inH (nullH env) , mkBench "UF.bracket_" env $ \inH _ -> readChunksBracket_ inH (nullH env) - , mkBench "UF.bracket" env $ \inH _ -> - readChunksBracket inH (nullH env) ] ] @@ -312,39 +178,28 @@ o_1_space_copy_exceptions_readChunks env = -- | Send the file contents to /dev/null with exception handling toChunksBracket_ :: Handle -> Handle -> IO () toChunksBracket_ inh devNull = - let readEx = bracketUnsafe + let readEx = Stream.bracketUnsafe (return ()) (\_ -> hClose inh) - (\_ -> fromStreamD $ IFH.readChunks inh) + (\_ -> IFH.readChunks inh) in Stream.fold (IFH.writeChunks devNull) readEx #ifdef INSPECTION inspect $ hasNoTypeClasses 'toChunksBracket_ #endif -toChunksBracket :: Handle -> Handle -> IO () -toChunksBracket inh devNull = - let readEx = Stream.bracket - (return ()) - (\_ -> hClose inh) - (\_ -> fromStreamD $ IFH.readChunks inh) - in Stream.fold (IFH.writeChunks devNull) readEx - o_1_space_copy_exceptions_toChunks :: BenchEnv -> [Benchmark] o_1_space_copy_exceptions_toChunks env = [ bgroup "exceptions/toChunks" [ mkBench "Stream.bracket_" env $ \inH _ -> toChunksBracket_ inH (nullH env) - , mkBench "Stream.bracket" env $ \inH _ -> - toChunksBracket inH (nullH env) ] ] benchmarks :: String -> BenchEnv -> Int -> [Benchmark] -benchmarks moduleName _env size = +benchmarks moduleName _env _size = [ bgroup (o_1_space_prefix moduleName) $ concat - [ o_1_space_serial_exceptions size - , o_1_space_copy_exceptions_readChunks _env + [ o_1_space_copy_exceptions_readChunks _env , o_1_space_copy_exceptions_toChunks _env , o_1_space_copy_stream_exceptions _env ] diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Adaptive.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Adaptive.hs similarity index 100% rename from benchmark/Streamly/Benchmark/Data/Stream/Adaptive.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/Adaptive.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Concurrent.hs similarity index 95% rename from benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/Concurrent.hs index 8e5a20f540..25c8989eb4 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Concurrent.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Concurrent.hs @@ -5,7 +5,7 @@ -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon +import ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) moduleName :: String diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentCommon.hs similarity index 99% rename from benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentCommon.hs index d562e7d845..6746c8146f 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentCommon.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentCommon.hs @@ -9,7 +9,7 @@ -- License : BSD3 -- Maintainer : streamly@composewell.com -module Stream.ConcurrentCommon +module ConcurrentCommon ( allBenchmarks , mkParallel , unParallel diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentEager.hs similarity index 95% rename from benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentEager.hs index e40e1de08e..c7d5a01fe0 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentEager.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentEager.hs @@ -5,7 +5,7 @@ -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon +import ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) import qualified Streamly.Internal.Data.Stream.Prelude as Stream diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentInterleaved.hs similarity index 95% rename from benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentInterleaved.hs index 8b5946f9f5..783fe83360 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentInterleaved.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentInterleaved.hs @@ -5,7 +5,7 @@ -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon +import ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) import qualified Streamly.Internal.Data.Stream.Prelude as Stream diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentOrdered.hs similarity index 95% rename from benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentOrdered.hs index 7b8e5da176..d09f153d02 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentOrdered.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentOrdered.hs @@ -5,7 +5,7 @@ -- License : BSD3 -- Maintainer : streamly@composewell.com -import Stream.ConcurrentCommon +import ConcurrentCommon import Streamly.Benchmark.Common (runWithCLIOpts, defaultStreamSize) import qualified Streamly.Data.Stream.Prelude as Stream diff --git a/benchmark/Streamly/Benchmark/Data/Stream/ConcurrentThreadHeavy.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentThreadHeavy.hs similarity index 100% rename from benchmark/Streamly/Benchmark/Data/Stream/ConcurrentThreadHeavy.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/ConcurrentThreadHeavy.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs new file mode 100644 index 0000000000..e639237893 --- /dev/null +++ b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs @@ -0,0 +1,331 @@ +-- | +-- Module : Stream.Exceptions +-- Copyright : (c) 2019 Composewell Technologies +-- License : BSD-3-Clause +-- Maintainer : streamly@composewell.com +-- Stability : experimental +-- Portability : GHC + +{-# LANGUAGE CPP #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} + +#ifdef __HADDOCK_VERSION__ +#undef INSPECTION +#endif + +#ifdef INSPECTION +{-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-} +#endif + +module Main (main) where + +import Control.Exception (Exception, throwIO) +import Data.HashMap.Strict (HashMap) +import Data.Proxy (Proxy(..)) +import Stream.Common (drain, benchIOSink) +import Streamly.Internal.Data.IsMap.HashMap () +import Streamly.Internal.Data.Stream (Stream) +import System.IO (Handle, hClose, hPutChar) + +import qualified Data.IORef as Ref +import qualified Data.Map.Strict as Map + +import qualified Stream.Common as Common +import qualified Streamly.Internal.Data.Fold as Fold +import qualified Streamly.FileSystem.Handle as FH +import qualified Streamly.Internal.FileSystem.Handle as IFH +import qualified Streamly.Internal.Data.Stream as Stream +import qualified Streamly.Internal.Data.Stream.Prelude as Stream +import qualified Streamly.Internal.Data.Unfold as IUF +import qualified Streamly.Internal.Data.Unfold.Prelude as IUF + +import Test.Tasty.Bench hiding (env) +import Prelude hiding (last, length) +import Streamly.Benchmark.Common +import Streamly.Benchmark.Common.Handle + +#ifdef INSPECTION +import Control.Monad.Catch (MonadCatch) +import Test.Inspection +#endif + +------------------------------------------------------------------------------- +-- stream exceptions +------------------------------------------------------------------------------- + +data BenchException + = BenchException1 + | BenchException2 + deriving (Show, Eq, Ord) + +instance Exception BenchException + +retryNoneSimple :: Int -> Int -> IO () +retryNoneSimple length from = + drain + $ Stream.retry + (Map.singleton BenchException1 length) + (const Stream.nil) + source + + where + + source = Stream.enumerateFromTo from (from + length) + +retryNone :: Int -> Int -> IO () +retryNone length from = do + ref <- Ref.newIORef (0 :: Int) + drain + $ Stream.retry (Map.singleton BenchException1 length) (const Stream.nil) + $ source ref + + where + + source ref = + Stream.replicateM (from + length) + $ Ref.modifyIORef' ref (+ 1) >> Ref.readIORef ref + +retryAll :: Int -> Int -> IO () +retryAll length from = do + ref <- Ref.newIORef 0 + drain + $ Stream.retry + (Map.singleton BenchException1 (length + from)) (const Stream.nil) + $ source ref + + where + + source ref = + Stream.fromEffect + $ do + Ref.modifyIORef' ref (+ 1) + val <- Ref.readIORef ref + if val >= length + then return length + else throwIO BenchException1 + +retryUnknown :: Int -> Int -> IO () +retryUnknown length from = do + drain + $ Stream.retry (Map.singleton BenchException1 length) (const source) + $ throwIO BenchException2 `Stream.before` Stream.nil + + where + + source = Stream.enumerateFromTo from (from + length) + + +o_1_space_serial_exceptions :: Int -> [Benchmark] +o_1_space_serial_exceptions length = + [ bgroup + "exceptions/serial" + [ benchIOSrc1 "retryNoneSimple" (retryNoneSimple length) + , benchIOSrc1 "retryNone" (retryNone length) + , benchIOSrc1 "retryAll" (retryAll length) + , benchIOSrc1 "retryUnknown" (retryUnknown length) + ] + ] + +-- XXX Move these to FileSystem.Handle benchmarks + +------------------------------------------------------------------------------- +-- copy stream exceptions +------------------------------------------------------------------------------- + +readWriteFinallyStream :: Handle -> Handle -> IO () +readWriteFinallyStream inh devNull = + let readEx = Stream.finally (hClose inh) (Stream.unfold FH.reader inh) + in Stream.fold (FH.write devNull) readEx + +fromToBytesBracketStream :: Handle -> Handle -> IO () +fromToBytesBracketStream inh devNull = + let readEx = Stream.bracket (return ()) (\_ -> hClose inh) + (\_ -> IFH.read inh) + in IFH.putBytes devNull readEx + +readWriteBeforeAfterStream :: Handle -> Handle -> IO () +readWriteBeforeAfterStream inh devNull = + let readEx = + Stream.after (hClose inh) + $ Stream.before (hPutChar devNull 'A') (Stream.unfold FH.reader inh) + in Stream.fold (FH.write devNull) readEx + +#ifdef INSPECTION +inspect $ 'readWriteBeforeAfterStream `hasNoType` ''Stream.Step +#endif + +readWriteAfterStream :: Handle -> Handle -> IO () +readWriteAfterStream inh devNull = + let readEx = Stream.after (hClose inh) (Stream.unfold FH.reader inh) + in Stream.fold (FH.write devNull) readEx + +#ifdef INSPECTION +inspect $ 'readWriteAfterStream `hasNoType` ''Stream.Step +#endif + +o_1_space_copy_stream_exceptions :: BenchEnv -> [Benchmark] +o_1_space_copy_stream_exceptions env = + [ bgroup "exceptions" + [ mkBenchSmall "Stream.finally" env $ \inh _ -> + readWriteFinallyStream inh (nullH env) + , mkBenchSmall "Stream.after . Stream.before" env $ \inh _ -> + readWriteBeforeAfterStream inh (nullH env) + , mkBenchSmall "Stream.after" env $ \inh _ -> + readWriteAfterStream inh (nullH env) + ] + , bgroup "exceptions/fromToBytes" + [ mkBenchSmall "Stream.bracket" env $ \inh _ -> + fromToBytesBracketStream inh (nullH env) + ] + ] + + ------------------------------------------------------------------------------- +-- Exceptions readChunks +------------------------------------------------------------------------------- + +readChunksBracket :: Handle -> Handle -> IO () +readChunksBracket inh devNull = + let readEx = IUF.bracket return (\_ -> hClose inh) FH.chunkReader + in IUF.fold (IFH.writeChunks devNull) readEx inh + +o_1_space_copy_exceptions_readChunks :: BenchEnv -> [Benchmark] +o_1_space_copy_exceptions_readChunks env = + [ bgroup "exceptions/readChunks" + [ mkBench "UF.bracket" env $ \inH _ -> + readChunksBracket inH (nullH env) + ] + ] + +------------------------------------------------------------------------------- +-- Exceptions toChunks +------------------------------------------------------------------------------- + +toChunksBracket :: Handle -> Handle -> IO () +toChunksBracket inh devNull = + let readEx = Stream.bracket + (return ()) + (\_ -> hClose inh) + (\_ -> IFH.readChunks inh) + in Stream.fold (IFH.writeChunks devNull) readEx + +o_1_space_copy_exceptions_toChunks :: BenchEnv -> [Benchmark] +o_1_space_copy_exceptions_toChunks env = + [ bgroup "exceptions/toChunks" + [ mkBench "Stream.bracket" env $ \inH _ -> + toChunksBracket inH (nullH env) + ] + ] + +excBenchmarks :: BenchEnv -> Int -> [Benchmark] +excBenchmarks env size = + [ bgroup (o_1_space_prefix moduleName) $ concat + [ o_1_space_serial_exceptions size + , o_1_space_copy_exceptions_readChunks env + , o_1_space_copy_exceptions_toChunks env + , o_1_space_copy_stream_exceptions env + ] + ] + +{-# INLINE pollCounts #-} +pollCounts :: Stream IO Int -> IO () +pollCounts = drain . Stream.parTapCount (const True) f + + where + + f = Stream.drain . Stream.rollingMap2 (-) . Stream.delayPost 1 + +{-# INLINE takeInterval #-} +takeInterval :: Double -> Stream IO Int -> IO () +takeInterval i = drain . Stream.takeInterval i + +-- Inspection testing is disabled for takeInterval +-- Enable it when looking at it throughly +#ifdef INSPECTION +-- inspect $ hasNoType 'takeInterval ''SPEC +-- inspect $ hasNoTypeClasses 'takeInterval +-- inspect $ 'takeInterval `hasNoType` ''D.Step +#endif + +{-# INLINE dropInterval #-} +dropInterval :: Double -> Stream IO Int -> IO () +dropInterval i = drain . Stream.dropInterval i + +-- Inspection testing is disabled for dropInterval +-- Enable it when looking at it throughly +#ifdef INSPECTION +-- inspect $ hasNoTypeClasses 'dropInterval +-- inspect $ 'dropInterval `hasNoType` ''D.Step +#endif + +-- XXX Decide on the time interval +{-# INLINE _intervalsOfSum #-} +_intervalsOfSum :: Stream.MonadAsync m => Double -> Stream m Int -> m () +_intervalsOfSum i = drain . Stream.intervalsOf i Fold.sum + +timeBenchmarks :: BenchEnv -> Int -> [Benchmark] +timeBenchmarks _env size = + [ benchIOSink size "parTapCount 1 second" pollCounts + , benchIOSink size "takeInterval-all" (takeInterval 10000) + , benchIOSink size "dropInterval-all" (dropInterval 10000) + ] + +------------------------------------------------------------------------------- +-- Grouping/Splitting +------------------------------------------------------------------------------- + +{-# INLINE classifySessionsOf #-} +classifySessionsOf :: Stream.MonadAsync m => (Int -> Int) -> Stream m Int -> m () +classifySessionsOf getKey = + Common.drain + . Stream.classifySessionsOf + (const (return False)) 3 (Fold.take 10 Fold.sum) + . Stream.timestamped + . fmap (\x -> (getKey x, x)) + +{-# INLINE classifySessionsOfHash #-} +classifySessionsOfHash :: Stream.MonadAsync m => + (Int -> Int) -> Stream m Int -> m () +classifySessionsOfHash getKey = + Common.drain + . Stream.classifySessionsByGeneric + (Proxy :: Proxy (HashMap k)) + 1 False (const (return False)) 3 (Fold.take 10 Fold.sum) + . Stream.timestamped + . fmap (\x -> (getKey x, x)) + +o_1_space_grouping :: BenchEnv -> Int -> [Benchmark] +o_1_space_grouping _env value = + -- Buffering operations using heap proportional to group/window sizes. + [ bgroup "grouping" + [ benchIOSink value "classifySessionsOf (10000 buckets)" + (classifySessionsOf (getKey 10000)) + , benchIOSink value "classifySessionsOf (64 buckets)" + (classifySessionsOf (getKey 64)) + , benchIOSink value "classifySessionsOfHash (10000 buckets)" + (classifySessionsOfHash (getKey 10000)) + , benchIOSink value "classifySessionsOfHash (64 buckets)" + (classifySessionsOfHash (getKey 64)) + ] + ] + + where + + getKey :: Int -> Int -> Int + getKey n = (`mod` n) + +moduleName :: String +moduleName = "Data.Stream.Prelude" + +main :: IO () +main = do + env <- mkHandleBenchEnv + runWithCLIOpts defaultStreamSize (allBenchmarks env) + + where + + allBenchmarks env size = + excBenchmarks env size + ++ timeBenchmarks env size + ++ o_1_space_grouping env size diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Rate.hs b/benchmark/Streamly/Benchmark/Data/Stream/Prelude/Rate.hs similarity index 100% rename from benchmark/Streamly/Benchmark/Data/Stream/Rate.hs rename to benchmark/Streamly/Benchmark/Data/Stream/Prelude/Rate.hs diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs b/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs index d4d9534e9f..c1a892d06a 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Reduce.hs @@ -24,26 +24,14 @@ import qualified Streamly.Internal.Data.Refold.Type as Refold import qualified Streamly.Internal.Data.Fold as FL import qualified Stream.Common as Common -#ifndef USE_STREAMLY_CORE -import Data.HashMap.Strict (HashMap) -import Data.Proxy (Proxy(..)) -import Streamly.Internal.Data.IsMap.HashMap () -#endif - import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as S -#ifndef USE_STREAMLY_CORE -import qualified Streamly.Data.Stream.Prelude as S -import qualified Streamly.Internal.Data.Stream.Prelude as S -#endif import Test.Tasty.Bench import Streamly.Benchmark.Common import Stream.Common import Prelude hiding (reverse, tail) - - -- Apply transformation g count times on a stream of length len {-# INLINE iterateSource #-} iterateSource :: @@ -146,27 +134,9 @@ o_1_space_grouping value = , benchIOSink value "refoldMany" refoldMany , benchIOSink value "foldIterateM" foldIterateM , benchIOSink value "refoldIterateM" refoldIterateM - -#ifndef USE_STREAMLY_CORE - , benchIOSink value "classifySessionsOf (10000 buckets)" - (classifySessionsOf (getKey 10000)) - , benchIOSink value "classifySessionsOf (64 buckets)" - (classifySessionsOf (getKey 64)) - , benchIOSink value "classifySessionsOfHash (10000 buckets)" - (classifySessionsOfHash (getKey 10000)) - , benchIOSink value "classifySessionsOfHash (64 buckets)" - (classifySessionsOfHash (getKey 64)) -#endif ] ] -#ifndef USE_STREAMLY_CORE - where - - getKey :: Int -> Int -> Int - getKey n = (`mod` n) -#endif - ------------------------------------------------------------------------------- -- Size conserving transformations (reordering, buffering, etc.) ------------------------------------------------------------------------------- @@ -189,32 +159,6 @@ o_n_heap_buffering value = ] ] -------------------------------------------------------------------------------- --- Grouping/Splitting -------------------------------------------------------------------------------- - -#ifndef USE_STREAMLY_CORE -{-# INLINE classifySessionsOf #-} -classifySessionsOf :: S.MonadAsync m => (Int -> Int) -> Stream m Int -> m () -classifySessionsOf getKey = - Common.drain - . S.classifySessionsOf - (const (return False)) 3 (FL.take 10 FL.sum) - . S.timestamped - . fmap (\x -> (getKey x, x)) - -{-# INLINE classifySessionsOfHash #-} -classifySessionsOfHash :: S.MonadAsync m => - (Int -> Int) -> Stream m Int -> m () -classifySessionsOfHash getKey = - Common.drain - . S.classifySessionsByGeneric - (Proxy :: Proxy (HashMap k)) - 1 False (const (return False)) 3 (FL.take 10 FL.sum) - . S.timestamped - . fmap (\x -> (getKey x, x)) -#endif - ------------------------------------------------------------------------------- -- Mixed Transformation ------------------------------------------------------------------------------- diff --git a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs index e16e9902b1..0bb0ae6b78 100644 --- a/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs +++ b/benchmark/Streamly/Benchmark/Data/Stream/Transform.hs @@ -24,7 +24,7 @@ module Stream.Transform (benchmarks) where import Control.Monad.IO.Class (MonadIO(..)) - +import Streamly.Internal.Data.Stream (Stream) import System.Random (randomRIO) import qualified Streamly.Internal.Data.Fold as FL @@ -32,20 +32,13 @@ import qualified Streamly.Internal.Data.Scanl as Scanl import qualified Stream.Common as Common import qualified Streamly.Internal.Data.Unfold as Unfold - -import Streamly.Internal.Data.Stream (Stream) import qualified Streamly.Internal.Data.Stream as Stream -#ifndef USE_STREAMLY_CORE -import qualified Streamly.Internal.Data.Stream.Prelude as Stream -#endif import Test.Tasty.Bench import Stream.Common hiding (scanl') import Streamly.Benchmark.Common import Prelude hiding (sequence, mapM) - - ------------------------------------------------------------------------------- -- Pipelines (stream-to-stream transformations) ------------------------------------------------------------------------------- @@ -98,17 +91,6 @@ sequence = Common.drain . Stream.sequence tap :: MonadIO m => Int -> Stream m Int -> m () tap n = composeN n $ Stream.tap FL.sum -#ifndef USE_STREAMLY_CORE -{-# INLINE pollCounts #-} -pollCounts :: Int -> Stream IO Int -> IO () -pollCounts n = - composeN n (Stream.parTapCount (const True) f) - - where - - f = Stream.drain . Stream.rollingMap2 (-) . Stream.delayPost 1 -#endif - {-# INLINE _timestamped #-} _timestamped :: MonadIO m => Stream m Int -> m () _timestamped = Stream.drain . Stream.timestamped @@ -142,9 +124,6 @@ o_1_space_mapping value = sequence (sourceUnfoldrAction value n) , benchIOSink value "mapM" (mapM 1) , benchIOSink value "tap" (tap 1) -#ifndef USE_STREAMLY_CORE - , benchIOSink value "parTapCount 1 second" (pollCounts 1) -#endif -- XXX tasty-bench hangs benchmarking this -- , benchIOSink value "timestamped" _timestamped -- Scanning @@ -314,31 +293,6 @@ takeWhileTrue value n = composeN n $ Stream.takeWhile (<= (value + 1)) takeWhileMTrue :: MonadIO m => Int -> Int -> Stream m Int -> m () takeWhileMTrue value n = composeN n $ Stream.takeWhileM (return . (<= (value + 1))) -#if !defined(USE_STREAMLY_CORE) -{-# INLINE takeInterval #-} -takeInterval :: Double -> Int -> Stream IO Int -> IO () -takeInterval i n = composeN n (Stream.takeInterval i) - --- Inspection testing is disabled for takeInterval --- Enable it when looking at it throughly -#ifdef INSPECTION --- inspect $ hasNoType 'takeInterval ''SPEC --- inspect $ hasNoTypeClasses 'takeInterval --- inspect $ 'takeInterval `hasNoType` ''D.Step -#endif - -{-# INLINE dropInterval #-} -dropInterval :: Double -> Int -> Stream IO Int -> IO () -dropInterval i n = composeN n (Stream.dropInterval i) - --- Inspection testing is disabled for dropInterval --- Enable it when looking at it throughly -#ifdef INSPECTION --- inspect $ hasNoTypeClasses 'dropInterval --- inspect $ 'dropInterval `hasNoType` ''D.Step -#endif -#endif - {-# INLINE dropOne #-} dropOne :: MonadIO m => Int -> Stream m Int -> m () dropOne n = composeN n $ Stream.drop 1 @@ -359,13 +313,6 @@ dropWhileMTrue value n = composeN n $ Stream.dropWhileM (return . (<= (value + 1 dropWhileFalse :: MonadIO m => Int -> Int -> Stream m Int -> m () dropWhileFalse value n = composeN n $ Stream.dropWhile (> (value + 1)) -#ifndef USE_STREAMLY_CORE --- XXX Decide on the time interval -{-# INLINE _intervalsOfSum #-} -_intervalsOfSum :: Stream.MonadAsync m => Double -> Int -> Stream m Int -> m () -_intervalsOfSum i n = composeN n (Stream.intervalsOf i FL.sum) -#endif - {-# INLINE findIndices #-} findIndices :: MonadIO m => Int -> Int -> Stream m Int -> m () findIndices value n = composeN n $ Stream.findIndices (== (value + 1)) @@ -420,10 +367,6 @@ o_1_space_filtering value = -- , benchIOSink value "takeWhileM-true" (_takeWhileMTrue value 1) , benchIOSink value "drop-one" (dropOne 1) , benchIOSink value "drop-all" (dropAll value 1) -#if !defined(USE_STREAMLY_CORE) - , benchIOSink value "takeInterval-all" (takeInterval 10000 1) - , benchIOSink value "dropInterval-all" (dropInterval 10000 1) -#endif , benchIOSink value "dropWhile-true" (dropWhileTrue value 1) -- , benchIOSink value "dropWhileM-true" (_dropWhileMTrue value 1) , benchIOSink diff --git a/benchmark/streamly-benchmarks.cabal b/benchmark/streamly-benchmarks.cabal index ecf6dd6173..a3b91db412 100644 --- a/benchmark/streamly-benchmarks.cabal +++ b/benchmark/streamly-benchmarks.cabal @@ -445,8 +445,6 @@ benchmark Data.Stream Stream.Lift Stream.Split Stream.Common - if !flag(use-streamly-core) - other-modules: Stream.Exceptions if flag(limit-build-mem) if flag(dev) @@ -457,7 +455,7 @@ benchmark Data.Stream benchmark Data.Stream.Adaptive import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude main-is: Adaptive.hs if flag(use-streamly-core) || impl(ghcjs) buildable: False @@ -467,10 +465,10 @@ benchmark Data.Stream.Adaptive benchmark Data.Stream.Concurrent import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/ + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude, Streamly/Benchmark/Data/ main-is: Concurrent.hs other-modules: - Stream.ConcurrentCommon + ConcurrentCommon Stream.Common if flag(use-streamly-core) || impl(ghcjs) buildable: False @@ -480,10 +478,10 @@ benchmark Data.Stream.Concurrent benchmark Data.Stream.ConcurrentEager import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/ + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude, Streamly/Benchmark/Data/ main-is: ConcurrentEager.hs other-modules: - Stream.ConcurrentCommon + ConcurrentCommon Stream.Common if flag(use-streamly-core) || impl(ghcjs) buildable: False @@ -493,10 +491,10 @@ benchmark Data.Stream.ConcurrentEager benchmark Data.Stream.ConcurrentInterleaved import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/ + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude, Streamly/Benchmark/Data/ main-is: ConcurrentInterleaved.hs other-modules: - Stream.ConcurrentCommon + ConcurrentCommon Stream.Common if flag(use-streamly-core) || impl(ghcjs) buildable: False @@ -506,10 +504,10 @@ benchmark Data.Stream.ConcurrentInterleaved benchmark Data.Stream.ConcurrentOrdered import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/ + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude, Streamly/Benchmark/Data/ main-is: ConcurrentOrdered.hs other-modules: - Stream.ConcurrentCommon + ConcurrentCommon Stream.Common if flag(use-streamly-core) || impl(ghcjs) buildable: False @@ -519,20 +517,32 @@ benchmark Data.Stream.ConcurrentOrdered benchmark Data.Stream.ConcurrentThreadHeavy import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream + hs-source-dirs: Streamly/Benchmark/Data/Stream/Prelude main-is: ConcurrentThreadHeavy.hs if flag(use-streamly-core) || impl(ghcjs) buildable: False else buildable: True +benchmark Data.Stream.Prelude + import: bench-options + type: exitcode-stdio-1.0 + hs-source-dirs: Streamly/Benchmark/Data, Streamly/Benchmark/Data/Stream/Prelude + main-is: Exceptions.hs + other-modules: + Stream.Common + if flag(use-streamly-core) || impl(ghcjs) + buildable: False + else + buildable: True + benchmark Data.Stream.Rate import: bench-options-threaded type: exitcode-stdio-1.0 - hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/ + hs-source-dirs: Streamly/Benchmark/Data/, Streamly/Benchmark/Data/Stream/Prelude main-is: Rate.hs other-modules: - Stream.ConcurrentCommon + ConcurrentCommon Stream.Common if flag(use-streamly-core) || impl(ghcjs) buildable: False diff --git a/hie.yaml b/hie.yaml index 353bd0279d..0873395937 100644 --- a/hie.yaml +++ b/hie.yaml @@ -68,6 +68,8 @@ cradle: component: "bench:Data.StreamK" - path: "./benchmark/Streamly/Benchmark/Data/StreamK/FromStream.hs" component: "bench:Data.StreamK.FromStream" + - path: "./benchmark/Streamly/Benchmark/Data/Stream/Prelude/Exceptions.hs" + component: "bench:Data.Stream.Prelude.Exceptions" - path: "./benchmark/Streamly/Benchmark/Data/Unfold.hs" component: "bench:Data.Unfold" - path: "./benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs" diff --git a/streamly.cabal b/streamly.cabal index 4fd77cf1be..0288a37e7d 100644 --- a/streamly.cabal +++ b/streamly.cabal @@ -69,26 +69,34 @@ extra-source-files: bench-test-lib/bench-test-lib.cabal bench-test-lib/src/BenchTestLib/DirIO.hs benchmark/*.hs - benchmark/bench-runner/Main.hs - benchmark/bench-runner/bench-runner.cabal benchmark/Streamly/Benchmark/Data/*.hs - benchmark/Streamly/Benchmark/Data/Scanl/*.hs - benchmark/Streamly/Benchmark/Data/Fold/*.hs - benchmark/Streamly/Benchmark/Data/Serialize/*.hs + benchmark/Streamly/Benchmark/Data/Array.hs benchmark/Streamly/Benchmark/Data/Array/Common.hs benchmark/Streamly/Benchmark/Data/Array/CommonImports.hs benchmark/Streamly/Benchmark/Data/Array/Generic.hs benchmark/Streamly/Benchmark/Data/Array/SmallArray.hs - benchmark/Streamly/Benchmark/Data/Array.hs - benchmark/Streamly/Benchmark/Data/RingArray.hs - benchmark/Streamly/Benchmark/Data/MutArray.hs benchmark/Streamly/Benchmark/Data/Array/Stream.hs + benchmark/Streamly/Benchmark/Data/Fold/*.hs benchmark/Streamly/Benchmark/Data/Fold/Window.hs + benchmark/Streamly/Benchmark/Data/MutArray.hs + benchmark/Streamly/Benchmark/Data/RingArray.hs + benchmark/Streamly/Benchmark/Data/Scanl/*.hs + benchmark/Streamly/Benchmark/Data/Serialize/*.hs benchmark/Streamly/Benchmark/Data/Stream/*.hs + benchmark/Streamly/Benchmark/Data/Stream/Prelude/*.hs benchmark/Streamly/Benchmark/Data/StreamK/*.hs benchmark/Streamly/Benchmark/FileSystem/*.hs benchmark/Streamly/Benchmark/FileSystem/Handle/*.hs benchmark/Streamly/Benchmark/Unicode/*.hs + benchmark/Streamly/Benchmark/Unicode/data/AllChars.txt + benchmark/Streamly/Benchmark/Unicode/data/Devanagari.txt + benchmark/Streamly/Benchmark/Unicode/data/Japanese.txt + benchmark/Streamly/Benchmark/Unicode/data/Vietnamese.txt + benchmark/Streamly/Benchmark/Unicode/data/Deutsch.txt + benchmark/Streamly/Benchmark/Unicode/data/English.txt + benchmark/Streamly/Benchmark/Unicode/data/Korean.txt + benchmark/bench-runner/Main.hs + benchmark/bench-runner/bench-runner.cabal benchmark/lib/Streamly/Benchmark/*.hs benchmark/lib/Streamly/Benchmark/Common/*.hs benchmark/streamly-benchmarks.cabal @@ -108,8 +116,8 @@ extra-source-files: src/Streamly/Internal/FileSystem/Event/Darwin.h src/assert.hs src/config.h.in - src/inline.hs src/deprecation.h + src/inline.hs test/Streamly/Test/Data/*.hs test/Streamly/Test/Data/Array/CommonImports.hs test/Streamly/Test/Data/Array/Common.hs @@ -136,24 +144,17 @@ extra-source-files: test/Streamly/Test/Serialize/*.hs test/Streamly/Test/Data/Scanl/*.hs test/Streamly/Test/Data/Fold/*.hs - test/lib/Streamly/Test/Common.hs - test/lib/Streamly/Test/Prelude/Common.hs - test/lib/Streamly/Test/Parser/Common.hs - test/streamly-tests.cabal - test/version-bounds.hs test/Streamly/Test/Unicode/ucd/NormalizationTest.txt test/Streamly/Test/Unicode/extra/NormalizationTest.txt test/Streamly/Test/Data/Unbox.hs test/Streamly/Test/Data/Unbox/*.hs test/Streamly/Test/Data/Serialize.hs test/Streamly/Test/Data/Serialize/*.hs - benchmark/Streamly/Benchmark/Unicode/data/AllChars.txt - benchmark/Streamly/Benchmark/Unicode/data/Devanagari.txt - benchmark/Streamly/Benchmark/Unicode/data/Japanese.txt - benchmark/Streamly/Benchmark/Unicode/data/Vietnamese.txt - benchmark/Streamly/Benchmark/Unicode/data/Deutsch.txt - benchmark/Streamly/Benchmark/Unicode/data/English.txt - benchmark/Streamly/Benchmark/Unicode/data/Korean.txt + test/lib/Streamly/Test/Common.hs + test/lib/Streamly/Test/Prelude/Common.hs + test/lib/Streamly/Test/Parser/Common.hs + test/streamly-tests.cabal + test/version-bounds.hs extra-doc-files: CONTRIBUTING.md