|
| 1 | +-- | A hot ST loop through a *two*-argument effect step that is always |
| 2 | +-- | fully applied and immediately run — the case the late uncurry run |
| 3 | +-- | (issue #200) cannot reach. With two real arguments the step's spine |
| 4 | +-- | is already saturated when the early uncurry run measures it, so the |
| 5 | +-- | split fires at the real arity and magicDo then rewrites the worker's |
| 6 | +-- | body into a thunk: every iteration allocates that closure and pays |
| 7 | +-- | the second call that forces it. Absorbing the thunk parameter into |
| 8 | +-- | the worker makes the iteration one n-ary call with no allocation. |
| 9 | +-- | `Bench.EffectStep` is the unary sibling, which the late run already |
| 10 | +-- | handles. |
| 11 | +module Bench.EffectStep2 where |
| 12 | + |
| 13 | +import Prelude |
| 14 | + |
| 15 | +import Control.Monad.ST (ST) |
| 16 | +import Control.Monad.ST as ST |
| 17 | +import Control.Monad.ST.Ref (STRef) |
| 18 | +import Control.Monad.ST.Ref as STRef |
| 19 | + |
| 20 | +-- Two real arguments, so the early run splits it and the thunk ends up |
| 21 | +-- inside the worker. The body is deliberately over the call-site inline |
| 22 | +-- budget, so the call shape survives to be measured — built from |
| 23 | +-- read/write pairs, which unlike @modify@ allocate no per-iteration |
| 24 | +-- lambda that would drown the thunk-allocation delta this bench exposes. |
| 25 | +step :: forall r. Int -> STRef r Int -> ST r Unit |
| 26 | +step k ref = do |
| 27 | + a <- STRef.read ref |
| 28 | + _ <- STRef.write (a + k) ref |
| 29 | + b <- STRef.read ref |
| 30 | + _ <- STRef.write (b + k) ref |
| 31 | + c <- STRef.read ref |
| 32 | + _ <- STRef.write (c + k) ref |
| 33 | + d <- STRef.read ref |
| 34 | + _ <- STRef.write (d + k) ref |
| 35 | + e <- STRef.read ref |
| 36 | + _ <- STRef.write (e + k) ref |
| 37 | + pure unit |
| 38 | + |
| 39 | +go :: forall r. Int -> STRef r Int -> ST r Int |
| 40 | +go i ref = do |
| 41 | + step 3 ref |
| 42 | + if i <= 1 then STRef.read ref else go (i - 1) ref |
| 43 | + |
| 44 | +run :: Int -> Int |
| 45 | +run n = ST.run do |
| 46 | + ref <- STRef.new 0 |
| 47 | + go n ref |
0 commit comments