wave4main
Baseline: [0e2fd3/ghc], Tested: nested-cpr (without nesting inside sum-types, without join-point detection).
Found a 11% increase in allocation, around 9000000
bytes.
The most obvious change in ticky-ticky-number are:
-
FUNCTION ENTRIES
andENTERS
increasing by ~100000 -
RETURNS
doubling from 140745 to 280795 -
ALLOC_FUN_ctr
andALLOC_FUN_gds
almost doubling, by ~18000 resp. 9000000
So we are allocating more function closures. First guess: Join point property destroyed somewhere.
The ticky output shows a $wgo{v s60k} (main:Main)
appearing that was not there before, with 140016
enters and 23522688
allocations. This appears in $wtabulate
, and indeed corresponds to a go1
that is a join-point before. So what is happening? We are changing
go1 [Occ=LoopBreaker]
:: GHC.Prim.Int#
-> GHC.Prim.State# s
-> (# GHC.Prim.State# s, GHC.Arr.Array GHC.Types.Int x #)
to
$wgo [Occ=LoopBreaker]
:: GHC.Prim.Int#
-> GHC.Prim.State# s
-> (# GHC.Prim.State# s,
GHC.Prim.Int#,
GHC.Prim.Int#,
GHC.Prim.Int#,
GHC.Prim.Array# x #)
go1
is recursive, but tail-recursive, so the worker and wrapper indeed cancel for the recursive call. But where it is being used, we simply apply the Array
constructor to the second component. So nothing is gained, but a join-point is lost.
My attempt below to detect join points does not help: The CPR information for go1
is the same as for let go1 = rhs in body
, as body
is just go1 ww ipv
.
The problem is that this is being passed as an argument to a function (in this case runSTRep
), and there is not much that can be done about this at this point.
Summary with simple expressions
Original code:
f a x = case a of
True -> case foo of b -> foo $
let go 0 = (1,(2,3))
go n = go (n-1)
in go b
False -> undefined
which after CPR transformation yields, where $go
is no longer a join-point for the argument to snd
.
f a x = case a of
True -> case foo of b -> foo $
let $wgo 0 = (# 1, 2, 3 #)
$wgo n = go (n-1)
in case $wgo b of (# a, b, c #) -> (a, (b,c))
False -> undefined