[GHC] #9349: excessive inlining with -fpre-inlining

#9349: excessive inlining with -fpre-inlining --------------------------------------------+------------------------------ Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Keywords: | Differential: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime performance bug | Unknown/Multiple Test Case: | Difficulty: Unknown Blocking: | Blocked By: | Related Tickets: --------------------------------------------+------------------------------ The program at https://gist.github.com/jorendorff/a3005968adc8f054baf7 runs very slowly when compiled with `-O` or higher. It seems that `arr` and/or `rangeMap` is being inlined into the do block on lines 89-91 and recomputed for each iteration of the loop. The program runs nearly instantly when compiled with `-O0` or with `-O -fno-pre-inlining`. (Of course, this does not mean `-fpre-inlining` is necessary the culprit; it could be enabling some subsequent misoptimization.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining with -fpre-inlining -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by klao): * cc: klao@… (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining with -fpre-inlining -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by rwbarton): Aha, it is the state hack marking the argument to `replicateM_` as one- shot, followed by pre-inlining. What was rather surprising to me as an end user was that `{-# NOINLINE rangeMap #-}` had no effect. I guess the pre-inlining does not care about such pragmas. Simon, any comments? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining with -fpre-inlining -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by klao): Here's a simplified example for this bug: {{{ import Control.Monad import Control.Concurrent.MVar expensive :: Int -> Int -> Int expensive n0 a = go n0 a where go 0 x = x go n x = go (n-1) ((x * 37 + 1973) `rem` 177) main :: IO () main = do mv <- newMVar (10 :: Int) let ex = expensive 100000 3 replicateM_ 30000 $ do x <- readMVar mv print $ x + ex }}} You could probably simplify it further. The important thing is that `ex` is the result of some expensive computation that incorrectly gets evaluated over and over again. And you have to put some "real" IO into the `replicateM_` for the bug to kick in (in the original example it was reading from the stdin, here I just read an MVar). Unlike the original example, here marking `ex` as `NOINLINE` does make the issue disappear. (Otherwise it's the same as the original example: nearly instantaneous with `-O0` or `-O -fno-pre-inlining`, but takes a looong time with `-O`.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining with -fpre-inlining -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by simonpj): First, I believe that `-fno-state-hack` would be better than `-fno-pre- inlining`, because it's less drastic. You might want to check that it does indeed cure the problem. I understand why NOINLINE is not working. The work is being duplicated by float-in, not by inlining! Consider {{{ let {-# NOINLINE rangeMap #-} rangeMap = expensive in replicateM_ n (\s -> ...rangeMap...) }}} The float-in pass picks up let-bindings and floats them inward as far as possible, but not inside a lambda (unless it's a one-shot lambda). So float-in does this: {{{ replicateM n (\s -> ....(let rangeMap = expensive in rangeMap)...) ... }}} The real culprit is, of course that the `\s` isn't one-shot. But that's why NOINLINE doesn't help. I suppose we could say that float-in should not move a NOINLINE binding; or at least should not move it in past a lambda, whether one-shot or not. I suppose that might be a finer-grained way of allowing you to fix the thing, a little less brutal than `-fno-state-hack`. The other thing that occurs to me is that for this `\s` we can ''see'' (via cardinality analysis) that it is called more than once. So maybe that can override the state-hack nonsense. Needs more looking at. Anyway I thought I'd write down what is going on. Is this a show-stopper for anyone? Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining with -fpre-inlining -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by klao): I can confirm that `-fno-state-hack` does cure the problem; both in the original example and my simplified test case. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining due to state hack -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by rwbarton):
Is this a show-stopper for anyone?
No, I don't believe so. Should I close it as a duplicate of #1168? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining due to state hack -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by klao): I'd like to point out before we close this issue, that it is (at least in part) a `7.8`-specific regression. My little example works perfectly fine with `7.6.3` regardless of optimization levels and flags. So, in the least, it has become easier to trigger this bug (even if some similar instances were present before). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining due to state hack -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: Runtime | Blocked By: performance bug | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by simonpj): I'm afraid I have no idea why it's become easier to trigger, but it's definitely very sensitive to how much inlining is done. Although Trac lets you close as duplicate, I tend to leave these things open (but linked) to remind us that there are a cloud of related examples. Closed things tend to imply "no need to look at me any more". But we are inconsistent about this at the moment. Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining due to state hack -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by nomeata): http://stackoverflow.com/questions/29404065/why-does-this-haskell-code- run-slower-with-o is another somewhat real-live example of this problem. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9349: excessive inlining due to state hack -------------------------------------+------------------------------------- Reporter: rwbarton | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by edsko): * cc: edsko (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9349#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC