#3458: Allocation where none should happen
-------------------------------+--------------------------------------------
    Reporter:  guest           |        Owner:             
        Type:  bug             |       Status:  new        
    Priority:  normal          |    Milestone:  6.12 branch
   Component:  Compiler        |      Version:  6.10.4     
    Severity:  normal          |   Resolution:             
    Keywords:                  |   Difficulty:  Unknown    
    Testcase:                  |           Os:  Linux      
Architecture:  x86_64 (amd64)  |  
-------------------------------+--------------------------------------------
Comment (by simonpj):

 I've had a look at this.  I ran it with
 {{{
 ./runST 100000 > /dev/null
 }}}
 Interesting.  The allocation you are concerned about arises from the local
 'loop' function in 'pick'.  GHC allocates a function closure for it, once
 per call of 'pick', which isn't really necessary.

 There are two ways to stop this happening.  One way is to make 'loop' a
 top level function like this
 {{{
 pick (c,p) r = myloop c p r 0

 myloop c p r i = if r < unsafeAt p i
                  then fromIntegral $ unsafeAt c i :: Word8
                  else myloop c p r (i+1)
 }}}
 This reduces allocation from 35Mbytes to 3Mbytes, by getting rid of those
 loop closures.

 But this is not very cool.  In fact 'loop' is totally tail-recursive, and
 should never be heap allocated. It's very nearly a let-no-escape thing but
 not quite.  Here is a smaller example:
 {{{
 f x = let g y = if y then x else g y
       in g x
 }}}
 If you compile with -ddump-stg you'll see that `g` gets the "let-no-
 escape" property, which means that it doesn't get a heap closure allocated
 for it.

 But if you make this little change:
 {{{
 f x = let g y = if y then x else g y
       in case g x of
            True -> False
            False -> True
 }}}
 then `g` doesn't get the let-no-escape property. And for good reason: you
 can't just adjust the stack pointer and jump to g.

 But you ''could'' do so if the 'let' was floated inwards, just before
 core-to-stg, thus:
 {{{
 f x = case let g y = if y then x else g y
            in g x
        of
            True -> False
            False -> True
 }}}
 Now it has the let-no-escape property again.

 I'd never really thought of that. Food for thought here.

 (These remarks are intended mainly for me and other over-interested
 parties.  As a workaround to get your performance up, try the lambda-
 lifting thing I show first.)

 Simon

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/3458#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to