Changes between Version 5 and Version 6 of NestedCPR


Ignore:
Timestamp:
Dec 11, 2013 4:34:43 PM (15 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 ===