{-# LANGUAGE OverloadedStrings #-} import Data.Conduit import qualified Data.Conduit.List as CL import Data.Conduit.Blaze import Criterion.Main import Blaze.ByteString.Builder import Data.Monoid import qualified Data.ByteString.Builder as BS import Data.Functor.Identity (runIdentity) import Control.Monad.ST (runST) import Data.ByteString.Lazy.Internal (defaultChunkSize) count :: Int count = 100000 single :: Builder single = copyByteString "Hello World!\n" oneBuilderLeft :: Builder oneBuilderLeft = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) oneBuilderRight :: Builder oneBuilderRight = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> single) builderSource :: Monad m => Source m Builder builderSource = CL.replicate count single singleBS :: BS.Builder singleBS = BS.shortByteString "Hello World!\n" oneBSBuilderLeft :: BS.Builder oneBSBuilderLeft = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> singleBS) oneBSBuilderRight :: BS.Builder oneBSBuilderRight = loop count mempty where loop 0 b = b loop i b = loop (i - 1) (b <> singleBS) builderBSSource :: Monad m => Source m BS.Builder builderBSSource = CL.replicate count singleBS main :: IO () main = defaultMain [ bench "conduit, strict, safe" $ whnfIO $ builderSource $$ builderToByteString =$ CL.sinkNull , bench "conduit, strict, unsafe" $ whnfIO $ builderSource $$ unsafeBuilderToByteString (allocBuffer defaultChunkSize) =$ CL.sinkNull , bench "one builder, left" $ nf toLazyByteString oneBuilderLeft , bench "one builder, right" $ nf toLazyByteString oneBuilderRight , bench "conduit, lazy" $ flip nf builderSource $ \src -> toLazyByteString $ runIdentity $ src $$ CL.fold (<>) mempty , bench "one bs builder, left" $ nf BS.toLazyByteString oneBSBuilderLeft , bench "one bs builder, right" $ nf BS.toLazyByteString oneBSBuilderRight , bench "conduit BS, lazy" $ flip nf builderBSSource $ \src -> BS.toLazyByteString $ runIdentity $ src $$ CL.fold (<>) mempty ]