#5715: Inliner fails to inline a function, causing 20x slowdown
-------------------------------------+--------------------------------------
 Reporter:  bos                      |          Owner:                  
     Type:  bug                      |         Status:  new             
 Priority:  normal                   |      Component:  Compiler        
  Version:  7.2.1                    |       Keywords:                  
       Os:  Unknown/Multiple         |   Architecture:  Unknown/Multiple
  Failure:  Runtime performance bug  |       Testcase:                  
Blockedby:                           |       Blocking:                  
  Related:                           |  
-------------------------------------+--------------------------------------
 Alexey filed [https://github.com/bos/mwc-random/pull/6 a bug against the
 mwc-random package recently], indicating a 20x to 40x slowdown on a
 function named `uniformRange` - [https://github.com/bos/mwc-
 random/blob/d7fda635bdd7a4d03ad8649e26ffa6d2b9b4c400/System/Random/MWC.hs#L487
 you can see its source here].

 In the original definition, there was an `INLINE` pragma, but Alexey
 noticed that it wasn't firing and so performance was predictably terrible.
 He added the `SPECIALIZE` pragmas that now follow the body of the
 function.

 I looked at `-ddump-simpl` output with the `SPECIALIZE` pragmas removed,
 and sure enough there are no inlining annotations on the function.

 The whole purpose of `uniformRange` is to be used in instance declarations
 such as the following:

 {{{
 instance Variate Int8 where
     uniform  = uniform1 fromIntegral
     uniformR = uniformRange
     {-# INLINE uniform  #-}
     {-# INLINE uniformR #-}
 }}}

 I have a suspicion that what's going on is that GHC's inliner is declining
 to do anything because some call site or other (or perhaps several?) isn't
 fully saturated.

 The behaviour of the new inliner is subtle to understand at times - it's
 not at all obvious when I should rewrite an instance like this, just to
 satisfy it:

 {{{
 instance Variate Int8 where
     uniform  = uniform1 fromIntegral
     uniformR inliner sacrifice = uniformRange inliner sacrifice
     {-# INLINE uniform  #-}
     {-# INLINE uniformR #-}
 }}}

 Saturating as above turned out to be the solution to the performance
 problem. I've been able to remove the `SPECIALIZE` pragmas. However, I'm
 still worried.

 It would be helpful if GHC had a mode that dumped out when (and why)
 inlinings do *not* take place on functions that have been annotated with
 `INLINE`, because I'm surely not the only person who gets caught by this.

 Also, aesthetically I find that saturating an application as above makes
 for tricky-to-read "why are those arguments there?" code, sort of the
 inliner's version of the dreaded monomorphism restriction: a lexical tic
 that's tremendously important, but for reasons that most readers will not
 know about.

-- 
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5715>
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