Changes between Version 5 and Version 6 of NestedCPR


Ignore:
Timestamp:
Dec 11, 2013 4:34:43 PM (21 months ago)
Author:
nomeata
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • NestedCPR

    v5 v6  
    3434Baseline: 49832, `better-ho-cardinality`: 49968. Unfortunately, the changes to, for example, `GHC.Read` are not small, and probably mostly benign...
    3535
    36 Trying to minimize the problem. This code has an increase in allocation (from 49448 to 49544)
     36Trying to minimize and isolate the problem. After some agressive code deleting, this is where I ended up:
    3737{{{
    3838#!haskell
    39 import Text.Read
    40 import Text.ParserCombinators.ReadPrec
    41 main = (readPrec_to_S readPrec 0 "True":: [(Bool, String)]) `seq` return ()
     39{-# LANGUAGE RankNTypes #-}
     40
     41data P a
     42  = Get (Char -> P a)
     43  | Result a
     44
     45Get f1     `mplus` Get f2     = undefined
     46Result x   `mplus` _          = Result x
     47
     48newtype ReadP a = R (forall b . (a -> P b) -> P b)
     49
     50instance Monad ReadP where
     51  return x  = R (\k -> k x)
     52  R m >>= f = R (\k -> m (\a -> let R m' = f a in m' k))
     53
     54readP_to_S (R f) = f Result `seq` ()
     55
     56ppp :: ReadP a -> ReadP a -> ReadP a
     57ppp (R f1) (R f2) = R (\k -> f1 k `mplus` f2 k)
     58
     59paren :: ReadP () -> ReadP ()
     60paren p = p >> return ()
     61
     62parens :: ReadP () -> ReadP ()
     63parens p = optional
     64 where
     65  optional  = ppp p mandatory
     66  mandatory = paren optional
     67
     68foo = paren ( return () )
     69
     70foo2 = ppp (parens ( return () )) (parens (return ()))
     71
     72main = readP_to_S foo `seq` readP_to_S foo2 `seq` return ()
    4273}}}
    43 while copying the definition of `readPrec` here, i.e.
    44 {{{
    45 #!haskell
     74it is important that both `paren` and `parens` are used more than once; if there is only one use-site, the problem disappears (which made it hard to find). Also, most other changes prevent the increase in allocations: Removing the `Monad` instance and turning its methods into regular functions; adding `NOINLINE` annotations to `paren` or `parens`; changing `foo2` to `ppp foo foo`; even removing the dead code that is the first line of the `mplus` function.
    4675
    47 import qualified Text.Read.Lex as L
    48 
    49 import Text.Read
    50 import Text.ParserCombinators.ReadPrec
    51 
    52 foo=parens
    53     ( do L.Ident s <- lexP
    54          case s of
    55            "True"  -> return True
    56            "False" -> return False
    57            _       -> pfail
    58     )
    59 
    60 
    61 main = (readPrec_to_S readPrec 0 "True":: [(Bool, String)]) `seq` return ()
    62 }}}
    63 yields a decrease (49240 → 49224).
    64 
    65 
    66 It even happens with `read "True" :: Bool` So I tried to minimize the problem, which somehow seems to occur in the depths of the `Read` code. But after manually pasting all the related pieces from `GHC.Read` and `Text.ParserCombinators.ReadP*` in one file, the differences in allocations go away.
    67 
    68 Maybe it is related to what inlining information about various functions cross module boundaries. For example, `fMonadP_$cfail` and other functions from `Text.ParserCombinators.ReadP` lose the `InlineRule (1, True, True)` annotation. Is that expected? Also, functions returning a `ShowS` have their arity increased. Can that be a reason for the increase of allocations?
     76I think I’ll leave it at this point, this is hopefully enough information for someone (likely SPJ) to know whats going on.
    6977
    7078=== Side tracks ===