Skip to content

Commit 0d72be1

Browse files
committed
README: axe 'Case study' section
1 parent e298d32 commit 0d72be1

File tree

1 file changed

+0
-84
lines changed

1 file changed

+0
-84
lines changed

README.md

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -52,90 +52,6 @@ but may suffer from insufficient inlining, allocating a tree of thunks. It is st
5252
significantly faster than `Data.Text.Lazy.Builder`, as witnessed by benchmarks
5353
for `blaze-builder` below.
5454

55-
## Case study
56-
57-
Let's benchmark builders, which concatenate all `Char` from `minBound` to `maxBound`, producing a large `Text`:
58-
59-
```haskell
60-
#!/usr/bin/env cabal
61-
{- cabal:
62-
build-depends: base, tasty-bench, text, text-builder >= 1.0, text-builder-linear
63-
ghc-options: -O2
64-
-}
65-
66-
import qualified Data.Text as T
67-
import qualified Data.Text.Lazy as TL
68-
import qualified Data.Text.Lazy.Builder as TLB
69-
import qualified TextBuilder as TB
70-
import qualified Data.Text.Builder.Linear as TBL
71-
import System.Environment (getArgs)
72-
import Test.Tasty.Bench
73-
74-
mkBench :: Monoid a => String -> (Char -> a) -> (a -> Int) -> Benchmark
75-
mkBench s f g = bench s $ nf (g . foldMap f . enumFromTo minBound) maxBound
76-
{-# INLINE mkBench #-}
77-
78-
main :: IO ()
79-
main = defaultMain
80-
[ mkBench "text, lazy" TLB.singleton (fromIntegral . TL.length . TLB.toLazyText)
81-
, mkBench "text, strict" TLB.singleton (T.length . TL.toStrict . TLB.toLazyText)
82-
, mkBench "text-builder" TB.char (T.length . TB.toText)
83-
, mkBench "text-builder-linear" TBL.fromChar (T.length . TBL.runBuilder)
84-
]
85-
```
86-
87-
Running this program with `cabal run Main.hs -- +RTS -T` yields following results:
88-
89-
```
90-
text, lazy:
91-
4.25 ms ± 107 μs, 11 MB allocated, 912 B copied
92-
text, strict:
93-
7.18 ms ± 235 μs, 24 MB allocated, 10 MB copied
94-
text-builder:
95-
80.1 ms ± 3.0 ms, 218 MB allocated, 107 MB copied
96-
text-builder-linear:
97-
5.37 ms ± 146 μs, 44 MB allocated, 78 KB copied
98-
```
99-
100-
The first result seems the best both in time and memory and corresponds to the
101-
usual `Text` builder, where we do not materialize the entire result at all.
102-
It builds chunks of lazy `Text` lazily and consumes them at once by
103-
`TL.length`. Thus there are 11 MB of allocations in nursery, none of which
104-
survive generation 0 garbage collector, so nothing is copied.
105-
106-
The second result is again the usual `Text` builder, but emulates a strict
107-
consumer: we materialize a strict `Text` before computing length. Allocation
108-
are doubled, and half of them (corresponding to the strict `Text`) survive to
109-
the heap. Time is also almost twice longer, but still quite good.
110-
111-
The third result is for `text-builder` and demonstrates how bad things could
112-
go with strict builders, aiming to precompute the precise length of the
113-
buffer: allocating a thunk per char is tremendously slow and expensive.
114-
115-
The last result corresponds to the current package. We generate a strict
116-
`Text` by growing and reallocating the buffer, thus allocations are quite
117-
high. Nevertheless, it is already faster than the usual `Text` builder with
118-
strict consumer and does not strain the garbage collector.
119-
120-
As of GHC 9.10, things get very different if we remove `{-# INLINE mkBench #-}`:
121-
122-
```
123-
text, lazy:
124-
36.9 ms ± 599 μs, 275 MB allocated, 30 KB copied
125-
text, strict:
126-
44.7 ms ± 1.3 ms, 287 MB allocated, 25 MB copied
127-
text-builder:
128-
77.6 ms ± 2.2 ms, 218 MB allocated, 107 MB copied
129-
text-builder-linear:
130-
5.35 ms ± 212 μs, 44 MB allocated, 79 KB copied
131-
```
132-
133-
Builders from `text` package degrade rapidly, 6-8x slower and 10-20x more
134-
allocations. That's because their constant factors rely crucially on
135-
everything getting inlined, which makes their performance fragile and
136-
unreliable in large-scale applications. On the bright side of things, our
137-
builder remains as fast as before and now is a clear champion.
138-
13955
## Benchmarks for `Text`
14056

14157
Measured with GHC 9.12 on aarch64:

0 commit comments

Comments
 (0)