File: BenchDecimalUnbounded.hs

package info (click to toggle)
haskell-text-builder-linear 0.1.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 236 kB
  • sloc: haskell: 2,021; makefile: 3
file content (174 lines) | stat: -rw-r--r-- 7,236 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{-# LANGUAGE NumDecimals #-}

-- |
-- Copyright:   (c) 2022 Andrew Lelechenko
-- Licence:     BSD3
-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>
module BenchDecimalUnbounded (benchDecimalUnbounded) where

import Data.ByteString qualified as B
import Data.ByteString.Builder qualified as B
import Data.Text qualified as T
import Data.Text.Builder.Linear.Buffer (Buffer, runBuffer, ($$<|), (|>$$))
import Data.Text.Lazy qualified as TL
import Data.Text.Lazy.Builder qualified as TB
import Data.Text.Lazy.Builder.Int qualified as TB
import Test.Tasty.Bench (Benchmark, bench, bgroup, nf)

benchUnboundedLinearBuilderAppend ∷ Integer → Int → T.Text
benchUnboundedLinearBuilderAppend k m = runBuffer (`go` m)
  where
    go ∷ Buffer ⊸ Int → Buffer
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (acc |>$$ i) (n - 1)

benchUnboundedLinearBuilderPrepend ∷ Integer → Int → T.Text
benchUnboundedLinearBuilderPrepend k m = runBuffer (`go` m)
  where
    go ∷ Buffer ⊸ Int → Buffer
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (i $$<| acc) (n - 1)

-- NOTE: In the following benchmark, the ByteString builder would share work
-- if the prepender and the appender are identical, while our linear buffer does
-- not. So we increment the appender to get a fair benchmark.

benchUnboundedLinearBuilder ∷ Integer → Int → T.Text
benchUnboundedLinearBuilder k m = runBuffer (`go` m)
  where
    go ∷ Buffer ⊸ Int → Buffer
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (i $$<| (acc |>$$ (i + 1))) (n - 1)

benchUnboundedLazyBuilderBSAppend ∷ Integer → Int → B.ByteString
benchUnboundedLazyBuilderBSAppend k = B.toStrict . B.toLazyByteString . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (acc <> B.integerDec i) (n - 1)

benchUnboundedLazyBuilderBSPrepend ∷ Integer → Int → B.ByteString
benchUnboundedLazyBuilderBSPrepend k = B.toStrict . B.toLazyByteString . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (B.integerDec i <> acc) (n - 1)

benchUnboundedLazyBuilderBS ∷ Integer → Int → B.ByteString
benchUnboundedLazyBuilderBS k = B.toStrict . B.toLazyByteString . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (B.integerDec i <> (acc <> B.integerDec (i + 1))) (n - 1)

benchLazyBuilderAppend ∷ Integer → Int → T.Text
benchLazyBuilderAppend k = TL.toStrict . TB.toLazyText . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (acc <> TB.decimal i) (n - 1)

benchLazyBuilderPrepend ∷ Integer → Int → T.Text
benchLazyBuilderPrepend k = TL.toStrict . TB.toLazyText . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (TB.decimal i <> acc) (n - 1)

benchLazyBuilder ∷ Integer → Int → T.Text
benchLazyBuilder k = TL.toStrict . TB.toLazyText . go mempty
  where
    go !acc 0 = acc
    go !acc n = let i = fromIntegral n * k in go (TB.decimal i <> (acc <> TB.decimal (i + 1))) (n - 1)

data NamedInteger = I !String !Integer

mkGroup
  ∷ String
  → [Int]
  → (Integer → Int → T.Text)
  → (Integer → Int → B.ByteString)
  → (Integer → Int → T.Text)
  → [NamedInteger]
  → Benchmark
mkGroup name counts f g h = bgroup name . map mkBenches
  where
    mkBenches (I benchName i) =
      bgroup
        benchName
        (map (\count → bgroup (show count) (mkBench i count)) counts)
    mkBench i count =
      [ bench "Data.Text.Lazy.Builder" $ nf (f i) count
      , bench "Data.ByteString.Builder" $ nf (g i) count
      , bench "Data.Text.Builder.Linear" $ nf (h i) count
      ]
{-# INLINE mkGroup #-}

integers ∷ [NamedInteger]
integers =
  [ I "Small" (toInteger (div @Word maxBound 20)) -- ~ 9e17
  , I "Big01" (toInteger (maxBound @Word - 1) ^ (2 ∷ Word)) -- ~3e38
  , I "Big02" (toInteger (maxBound @Word - 1) ^ (5 ∷ Word)) -- ~2e96
  , I "Big03" (toInteger (maxBound @Word - 1) ^ (10 ∷ Word)) -- ~5e192
  , I "Big04" (toInteger (maxBound @Word - 1) ^ (15 ∷ Word)) -- ~1e289
  , I "Big05" (toInteger (maxBound @Word - 1) ^ (20 ∷ Word)) -- ~2e385
  -- , I "Big05a" (toInteger (maxBound @Word - 1) ^ (21 ∷ Word)) -- ~4e404
  -- , I "Big05b" (toInteger (maxBound @Word - 1) ^ (22 ∷ Word)) -- ~7e423
  -- , I "Big05c" (toInteger (maxBound @Word - 1) ^ (23 ∷ Word)) -- ~1e443
  -- , I "Big05d" (toInteger (maxBound @Word - 1) ^ (24 ∷ Word)) -- ~2e462
  , I "Big06" (toInteger (maxBound @Word - 1) ^ (25 ∷ Word)) -- ~4e481
  -- , I "Big06a" (toInteger (maxBound @Word - 1) ^ (26 ∷ Word)) -- ~8e500
  -- , I "Big06b" (toInteger (maxBound @Word - 1) ^ (27 ∷ Word)) -- ~2e520
  -- , I "Big06c" (toInteger (maxBound @Word - 1) ^ (28 ∷ Word))
  -- , I "Big06d" (toInteger (maxBound @Word - 1) ^ (29 ∷ Word))
  , I "Big07" (toInteger (maxBound @Word - 1) ^ (30 ∷ Word)) -- ~ 9e577
  , I "Big08" (toInteger (maxBound @Word - 1) ^ (35 ∷ Word)) -- ~ 2e674
  , I "Big09" (toInteger (maxBound @Word - 1) ^ (40 ∷ Word)) -- ~ 4e770
  , I "Big10" (toInteger (maxBound @Word - 1) ^ (45 ∷ Word)) -- ~ 9e866
  , I "Big11" (toInteger (maxBound @Word - 1) ^ (50 ∷ Word)) -- ~ 2e963
  , I "Huge01" (toInteger (maxBound @Word - 1) ^ (75 ∷ Word)) -- ~9e1444
  , I "Huge02" (toInteger (maxBound @Word - 1) ^ (100 ∷ Word)) -- ~4e1926
  , I "Huge03" (toInteger (maxBound @Word - 1) ^ (200 ∷ Word)) -- ~2e3853
  , I "Huge04" (toInteger (maxBound @Word - 1) ^ (300 ∷ Word)) -- ~6e5779
  , I "Huge05" (toInteger (maxBound @Word - 1) ^ (400 ∷ Word)) -- ~2e7706
  -- , I "Huge05a" (toInteger (maxBound @Word - 1) ^ (450 ∷ Word))
  , I "Huge06" (toInteger (maxBound @Word - 1) ^ (500 ∷ Word)) -- ~9e9632
  -- , I "Huge06b" (toInteger (maxBound @Word - 1) ^ (600 ∷ Word))
  , I "Huge07" (toInteger (maxBound @Word - 1) ^ (700 ∷ Word)) -- ~1e13486
  , I "Huge08" (toInteger (maxBound @Word - 1) ^ (1000 ∷ Word)) -- ~8e19265
  , I "Huge09" (toInteger (maxBound @Word - 1) ^ (3000 ∷ Word)) -- ~6e57797
  , I "Huge10" (toInteger (maxBound @Word - 1) ^ (5000 ∷ Word)) -- ~4e96329
  , I "Huge11" (toInteger (maxBound @Word - 1) ^ (10000 ∷ Word)) -- ~2e192659
  , I "Huge12" (toInteger (maxBound @Word - 1) ^ (100000 ∷ Word)) -- ~9e1926591
  -- , I "Huge13" (toInteger (maxBound @Word - 1) ^ (1000000 ∷ Word))
  , I "1e20" 1e20
  , I "1e100" 1e100
  , I "1e300" (10 ^ (300 ∷ Word))
  , I "1e500" (10 ^ (500 ∷ Word))
  , I "1e1000" (10 ^ (1000 ∷ Word))
  ]

benchDecimalUnbounded ∷ Benchmark
benchDecimalUnbounded =
  bgroup
    "Decimal: detailed unbounded"
    [ mkGroup
        "Append"
        counts
        benchLazyBuilderAppend
        benchUnboundedLazyBuilderBSAppend
        benchUnboundedLinearBuilderAppend
        integers
    , mkGroup
        "Prepend"
        counts
        benchLazyBuilderPrepend
        benchUnboundedLazyBuilderBSPrepend
        benchUnboundedLinearBuilderPrepend
        integers
    , mkGroup
        "Both"
        counts
        benchLazyBuilder
        benchUnboundedLazyBuilderBS
        benchUnboundedLinearBuilder
        integers
    ]
  where
    counts ∷ [Int]
    counts = [1e0, 1e1, 1e2]