packages feed

streamly-0.8.0: benchmark/Streamly/Benchmark/Prelude/Serial/Generation.hs

-- |
-- Module      : Serial.Generation
-- Copyright   : (c) 2018 Composewell Technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com

{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}

module Serial.Generation (benchmarks) where

import Data.Functor.Identity (Identity)

import qualified Prelude
import qualified GHC.Exts as GHC

import qualified Streamly.Prelude  as S

import Gauge
import Streamly.Prelude (SerialT, fromSerial, MonadAsync)
import Streamly.Benchmark.Common
import Streamly.Benchmark.Prelude
import Prelude hiding (repeat, replicate, iterate)

-------------------------------------------------------------------------------
-- Generation
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- fromList
-------------------------------------------------------------------------------

{-# INLINE sourceIsList #-}
sourceIsList :: Int -> Int -> SerialT Identity Int
sourceIsList value n = GHC.fromList [n..n+value]

{-# INLINE sourceIsString #-}
sourceIsString :: Int -> Int -> SerialT Identity Char
sourceIsString value n = GHC.fromString (Prelude.replicate (n + value) 'a')

{-# INLINE readInstance #-}
readInstance :: String -> SerialT Identity Int
readInstance str =
    let r = reads str
    in case r of
        [(x,"")] -> x
        _ -> error "readInstance: no parse"

-- For comparisons
{-# INLINE readInstanceList #-}
readInstanceList :: String -> [Int]
readInstanceList str =
    let r = reads str
    in case r of
        [(x,"")] -> x
        _ -> error "readInstance: no parse"

{-# INLINE repeat #-}
repeat :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
repeat count = S.take count . S.repeat

{-# INLINE repeatM #-}
repeatM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
repeatM count = S.take count . S.repeatM . return

{-# INLINE replicate #-}
replicate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
replicate = S.replicate

{-# INLINE replicateM #-}
replicateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
replicateM count = S.replicateM count . return

{-# INLINE enumerateFrom #-}
enumerateFrom :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerateFrom count = S.take count . S.enumerateFrom

{-# INLINE enumerateFromTo #-}
enumerateFromTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerateFromTo = sourceIntFromTo

{-# INLINE enumerateFromThen #-}
enumerateFromThen :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerateFromThen count inp = S.take count $ S.enumerateFromThen inp (inp + 1)

{-# INLINE enumerateFromThenTo #-}
enumerateFromThenTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerateFromThenTo = sourceIntFromThenTo

-- n ~ 1
{-# INLINE enumerate #-}
enumerate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerate count n = S.take (count + n) S.enumerate

-- n ~ 1
{-# INLINE enumerateTo #-}
enumerateTo :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
enumerateTo count n = S.enumerateTo (minBound + count + n)

{-# INLINE iterate #-}
iterate :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
iterate count = S.take count . S.iterate (+1)

{-# INLINE iterateM #-}
iterateM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
iterateM count = S.take count . S.iterateM (return . (+1)) . return

{-# INLINE fromIndices #-}
fromIndices :: (Monad m, S.IsStream t) => Int -> Int -> t m Int
fromIndices value n = S.take value $ S.fromIndices (+ n)

{-# INLINE fromIndicesM #-}
fromIndicesM :: (MonadAsync m, S.IsStream t) => Int -> Int -> t m Int
fromIndicesM value n = S.take value $ S.fromIndicesM (return <$> (+ n))

o_1_space_generation :: Int -> [Benchmark]
o_1_space_generation value =
    [ bgroup "generation"
        [ benchIOSrc fromSerial "unfoldr" (sourceUnfoldr value)
        , benchIOSrc fromSerial "unfoldrM" (sourceUnfoldrM value)
        , benchIOSrc fromSerial "repeat" (repeat value)
        , benchIOSrc fromSerial "repeatM" (repeatM value)
        , benchIOSrc fromSerial "replicate" (replicate value)
        , benchIOSrc fromSerial "replicateM" (replicateM value)
        , benchIOSrc fromSerial "iterate" (iterate value)
        , benchIOSrc fromSerial "iterateM" (iterateM value)
        , benchIOSrc fromSerial "fromIndices" (fromIndices value)
        , benchIOSrc fromSerial "fromIndicesM" (fromIndicesM value)
        , benchIOSrc fromSerial "intFromTo" (sourceIntFromTo value)
        , benchIOSrc fromSerial "intFromThenTo" (sourceIntFromThenTo value)
        , benchIOSrc fromSerial "integerFromStep" (sourceIntegerFromStep value)
        , benchIOSrc fromSerial "fracFromThenTo" (sourceFracFromThenTo value)
        , benchIOSrc fromSerial "fracFromTo" (sourceFracFromTo value)
        , benchIOSrc fromSerial "fromList" (sourceFromList value)
        , benchPureSrc "IsList.fromList" (sourceIsList value)
        , benchPureSrc "IsString.fromString" (sourceIsString value)
        , benchIOSrc fromSerial "fromListM" (sourceFromListM value)
        , benchIOSrc fromSerial "enumerateFrom" (enumerateFrom value)
        , benchIOSrc fromSerial "enumerateFromTo" (enumerateFromTo value)
        , benchIOSrc fromSerial "enumerateFromThen" (enumerateFromThen value)
        , benchIOSrc fromSerial "enumerateFromThenTo" (enumerateFromThenTo value)
        , benchIOSrc fromSerial "enumerate" (enumerate value)
        , benchIOSrc fromSerial "enumerateTo" (enumerateTo value)

          -- These essentially test cons and consM
        , benchIOSrc fromSerial "fromFoldable" (sourceFromFoldable value)
        , benchIOSrc fromSerial "fromFoldableM" (sourceFromFoldableM value)

        , benchIOSrc fromSerial "absTimes" $ absTimes value
        ]
    ]

o_n_heap_generation :: Int -> [Benchmark]
o_n_heap_generation value =
    [ bgroup "buffered"
    -- Buffers the output of show/read.
    -- XXX can the outputs be streaming? Can we have special read/show
    -- style type classes, readM/showM supporting streaming effects?
        [ bench "readsPrec pure streams" $
          nf readInstance (mkString value)
        , bench "readsPrec Haskell lists" $
          nf readInstanceList (mkListString value)
        ]
    ]

-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------

-- In addition to gauge options, the number of elements in the stream can be
-- passed using the --stream-size option.
--
benchmarks :: String -> Int -> [Benchmark]
benchmarks moduleName size =
        [ bgroup (o_1_space_prefix moduleName) (o_1_space_generation size)
        , bgroup (o_n_heap_prefix moduleName) (o_n_heap_generation size)
        ]