1{-# LANGUAGE OverloadedStrings #-}
2-- |
3-- Module      : ChunkedWrite
4-- Copyright   : (c) 2010 Simon Meier
5-- License     : BSD3-style (see LICENSE)
6--
7-- Maintainer  : Leon P Smith <leon@melding-monads.com>
8-- Stability   : experimental
9-- Portability : tested on GHC only
10--
11-- Test different strategies for writing lists of simple values:
12--
13--  1. Using 'mconcat . map from<Value>'
14--
15--  2. Using the specialized 'fromWrite<n>List' function where 'n' denotes
16--     the number of elements to write at the same time. Writing chunks of
17--     elements reduces the overhead from the buffer overflow test that has
18--     to be done before every write.
19--
20module ChunkedWrite where
21
22import Data.Char (chr)
23import Data.Int (Int64)
24import Data.Word (Word8, Word32)
25import Data.Monoid
26
27import Criterion.Main
28import qualified Data.ByteString.Lazy as L
29import qualified Data.ByteString as S
30
31import qualified Blaze.ByteString.Builder           as BB
32import qualified Blaze.ByteString.Builder.Char.Utf8 as BB
33
34main :: IO ()
35main = defaultMain
36    [ bench "S.pack: [Word8] -> S.ByteString" $
37        whnf (S.pack) word8s
38
39    , bench "toByteString . fromWord8s: [Word8] -> Builder -> S.ByteString" $
40        whnf (BB.toByteString . BB.fromWord8s) word8s
41
42    , bench "L.pack: [Word8] -> L.ByteString" $
43        whnf (L.length . L.pack) word8s
44
45    , bench "mconcat . map fromByte: [Word8] -> Builder -> L.ByteString" $
46        whnf benchMConcatWord8s word8s
47    , bench "fromWrite1List: [Word8] -> Builder -> L.ByteString" $
48        whnf bench1Word8s word8s
49    , bench "fromWrite2List: [Word8] -> Builder -> L.ByteString" $
50        whnf bench2Word8s word8s
51    , bench "fromWrite4List: [Word8] -> Builder -> L.ByteString" $
52        whnf bench4Word8s word8s
53    , bench "fromWrite8List: [Word8] -> Builder -> L.ByteString" $
54        whnf bench8Word8s word8s
55    , bench "fromWrite16List: [Word8] -> Builder -> L.ByteString" $
56        whnf bench16Word8s word8s
57
58    , bench "mconcat . map fromByte: [Char] -> Builder -> L.ByteString" $
59        whnf benchMConcatChars chars
60    , bench "fromWrite1List: [Char] -> Builder -> L.ByteString" $
61        whnf bench1Chars chars
62    , bench "fromWrite2List: [Char] -> Builder -> L.ByteString" $
63        whnf bench2Chars chars
64    , bench "fromWrite4List: [Char] -> Builder -> L.ByteString" $
65        whnf bench4Chars chars
66    , bench "fromWrite8List: [Char] -> Builder -> L.ByteString" $
67        whnf bench8Chars chars
68    , bench "fromWrite16List: [Char] -> Builder -> L.ByteString" $
69        whnf bench16Chars chars
70
71    , bench "mconcat . map fromWord32host: [Word32] -> Builder -> L.ByteString" $
72        whnf benchMConcatWord32s word32s
73    , bench "fromWrite1List: [Word32] -> Builder -> L.ByteString" $
74        whnf bench1Word32s word32s
75    , bench "fromWrite2List: [Word32] -> Builder -> L.ByteString" $
76        whnf bench2Word32s word32s
77    , bench "fromWrite4List: [Word32] -> Builder -> L.ByteString" $
78        whnf bench4Word32s word32s
79    , bench "fromWrite8List: [Word32] -> Builder -> L.ByteString" $
80        whnf bench8Word32s word32s
81    , bench "fromWrite16List: [Word32] -> Builder -> L.ByteString" $
82        whnf bench16Word32s word32s
83    ]
84  where
85    n = 100000
86
87    word8s :: [Word8]
88    word8s = take n $ map fromIntegral $ [(1::Int)..]
89    {-# NOINLINE word8s #-}
90
91    word32s :: [Word32]
92    word32s = take n $ [1..]
93    {-# NOINLINE word32s #-}
94
95    chars :: String
96    chars = take n $ map (chr . fromIntegral) $ word8s
97    {-# NOINLINE chars #-}
98
99-- Char
100
101benchMConcatChars :: [Char] -> Int64
102benchMConcatChars = L.length . BB.toLazyByteString . mconcat . map BB.fromChar
103
104bench1Chars :: [Char] -> Int64
105bench1Chars = L.length . BB.toLazyByteString . BB.fromWrite1List BB.writeChar
106
107bench2Chars :: [Char] -> Int64
108bench2Chars = L.length . BB.toLazyByteString . BB.fromWrite2List BB.writeChar
109
110bench4Chars :: [Char] -> Int64
111bench4Chars = L.length . BB.toLazyByteString . BB.fromWrite4List BB.writeChar
112
113bench8Chars :: [Char] -> Int64
114bench8Chars = L.length . BB.toLazyByteString . BB.fromWrite8List BB.writeChar
115
116bench16Chars :: [Char] -> Int64
117bench16Chars = L.length . BB.toLazyByteString . BB.fromWrite16List BB.writeChar
118
119-- Word8
120
121benchMConcatWord8s :: [Word8] -> Int64
122benchMConcatWord8s = L.length . BB.toLazyByteString . mconcat . map BB.fromWord8
123
124bench1Word8s :: [Word8] -> Int64
125bench1Word8s = L.length . BB.toLazyByteString . BB.fromWrite1List BB.writeWord8
126
127bench2Word8s :: [Word8] -> Int64
128bench2Word8s = L.length . BB.toLazyByteString . BB.fromWrite2List BB.writeWord8
129
130bench4Word8s :: [Word8] -> Int64
131bench4Word8s = L.length . BB.toLazyByteString . BB.fromWrite4List BB.writeWord8
132
133bench8Word8s :: [Word8] -> Int64
134bench8Word8s = L.length . BB.toLazyByteString . BB.fromWrite8List BB.writeWord8
135
136bench16Word8s :: [Word8] -> Int64
137bench16Word8s = L.length . BB.toLazyByteString . BB.fromWrite16List BB.writeWord8
138
139-- Word32
140
141benchMConcatWord32s :: [Word32] -> Int64
142benchMConcatWord32s = L.length . BB.toLazyByteString . mconcat . map BB.fromWord32host
143
144bench1Word32s :: [Word32] -> Int64
145bench1Word32s = L.length . BB.toLazyByteString . BB.fromWrite1List BB.writeWord32host
146
147bench2Word32s :: [Word32] -> Int64
148bench2Word32s = L.length . BB.toLazyByteString . BB.fromWrite2List BB.writeWord32host
149
150bench4Word32s :: [Word32] -> Int64
151bench4Word32s = L.length . BB.toLazyByteString . BB.fromWrite4List BB.writeWord32host
152
153bench8Word32s :: [Word32] -> Int64
154bench8Word32s = L.length . BB.toLazyByteString . BB.fromWrite8List BB.writeWord32host
155
156bench16Word32s :: [Word32] -> Int64
157bench16Word32s = L.length . BB.toLazyByteString . BB.fromWrite16List BB.writeWord32host
158
159