wiki:NestedCPR/wave4main

Version 4 (modified by nomeata, 14 months ago) (diff)

--

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 and ENTERS increasing by ~100000
  • RETURNS doubling from 140745 to 280795
  • ALLOC_FUN_ctr and ALLOC_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