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]
|