|
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads -----------------------------------------+---------------------------------- Reporter: joeyadams | Owner: Type: bug | Status: new Priority: normal | Component: libraries/base Version: 7.2.2 | Keywords: Os: Unknown/Multiple | Architecture: Unknown/Multiple Failure: Incorrect result at runtime | Testcase: Blockedby: | Blocking: Related: | -----------------------------------------+---------------------------------- When the following code is compiled with -O1 or -O2, the interleaved computation (putStrLn "eval") is performed 1000 times, rather than once: {{{ import Control.Concurrent import Control.Exception (evaluate) import Control.Monad import System.IO.Unsafe main :: IO () main = do x <- unsafeInterleaveIO $ putStrLn "eval" replicateM_ 1000 $ forkIO $ evaluate x >> return () threadDelay 1000000 }}} Taking a look at the source to unsafeInterleaveIO: {{{ {-# INLINE unsafeInterleaveIO #-} unsafeInterleaveIO :: IO a -> IO a unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m) -- We believe that INLINE on unsafeInterleaveIO is safe, because the -- state from this IO thread is passed explicitly to the interleaved -- IO, so it cannot be floated out and shared. }}} It seems the comment about INLINE is not true. If I define the following function: {{{ interleave :: IO a -> IO a interleave = unsafeInterleaveIO {-# NOINLINE interleave #-} }}} and replace unsafeInterleaveIO with interleave, "eval" is printed only once. If I change NOINLINE to INLINE, or if I remove the pragma altogether, "eval" is printed 1000 times. I believe unsafeInterleaveIO should ''guarantee'' that computations are not repeated. Otherwise, we end up with strangeness like this: {{{ import Control.Applicative import Control.Concurrent import Control.Monad main :: IO () main = do chan <- newChan :: IO (Chan Int) mapM_ (writeChan chan) [0..999] items <- take 10 <$> getChanContents chan replicateM_ 5 $ forkIO $ putStrLn $ "items = " ++ show items threadDelay 1000000 }}} which prints: {{{ items = [0,1,2,3,4,5,6,7,8,9] items = [10,11,12,13,14,15,16,17,18,19] items = [20,21,22,23,24,25,26,27,28,29] items = [30,31,32,33,34,35,36,37,38,39] items = [40,41,42,43,44,45,46,47,48,49] }}} For the time being, programs can work around this by using a NOINLINE wrapper: {{{ getChanContents' :: Chan a -> IO [a] getChanContents' = getChanContents {-# NOINLINE getChanContents' #-} }}} I tested this on Linux 64-bit with GHC 7.2.2 and ghc-7.4.0.20120111, and on Windows 32-bit with GHC 7.0.3 and 7.2.2. All of these platforms and versions exhibit the same behavior. The bug goes away when the program is compiled with -O0, or when functions returning interleaved computations are marked NOINLINE (e.g. getChanContents'). -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads -----------------------------------------+---------------------------------- Reporter: joeyadams | Owner: Type: bug | Status: new Priority: normal | Component: libraries/base Version: 7.2.2 | Keywords: Os: Unknown/Multiple | Architecture: Unknown/Multiple Failure: Incorrect result at runtime | Testcase: Blockedby: | Blocking: Related: | -----------------------------------------+---------------------------------- Changes (by PHO): * cc: pho@… (added) -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: Type: bug | Status: new Priority: high | Milestone: 7.4.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Changes (by simonmar): * priority: normal => high * difficulty: => Unknown * milestone: => 7.4.2 Comment: Thanks for the report. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: Type: bug | Status: new Priority: high | Milestone: 7.4.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonpj): This does indeed look bogus. I've done a little investigation, which I'm going to record here so I don't forget it. Fundamentally the problem is the "state hack". (Compile with `-fno-state- hack` and the problem goes away.) Consider {{{ let x = factorial 1000 in replicate 10 (print x) }}} After a bit of inlining we get something like {{{ let x = factorial 1000 in replicate 10 (\s. wprint x s) }}} where `s :: State# RealWorld` is a state token. Now the float-in pass pushes the let-binding inwards, to give {{{ replicate 10 (\s. wprint (factorial 1000) s) }}} and we are dead: we evaluate `(factorial 1000)` each time round the loop. Why does float-in do this? Because the state hack says that the type of `s` means it is only applied once, which is patently false. I think the solution is the narrow (once more) teh scope of the state hack, so that it's only used in arity expansion. I know how to do this but have to set up nofib runs to compare before and after. Thanks for the report. Hacks usually bit you in the end. Simon -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: simonpj Type: bug | Status: new Priority: high | Milestone: 7.4.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Changes (by simonmar): * owner: => simonpj -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: simonpj Type: bug | Status: new Priority: high | Milestone: 7.4.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonpj): I tried disabling the use of the state hack (`isStateHackType`, via `isOneShotBndr`) in {{{ simplCore/Simplify.lhs simplCore/OccurAnal.lhs simplCore/FloatIn.lhs }}} (the only other state hack uses are in `coreSyn/CoreArity.lhs`). This resulted in `perf/compiler/parsing001` failing slightly, and `perf/should_run/T5536` failing a lot. I looked into the latter. The attached program has {{{ 484268840 bytes allocated with the full state hack 2085048512 bytes allocated with the state hack modified as above }}} Replacing either of the "if" expressions in the last few lines with just its "else" branch fixes the problem. I've also attached the `-ddump-simpl` output. -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: simonpj Type: bug | Status: new Priority: high | Milestone: 7.4.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Comment(by simonpj): Cf #5943 -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ Glasgow-haskell-bugs mailing list [hidden email] http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs |
|
In reply to this post by GHC
#5859: unsafeInterleaveIO duplicates computation when evaluated by multiple
threads ---------------------------------+------------------------------------------ Reporter: joeyadams | Owner: simonpj Type: bug | Status: new Priority: high | Milestone: 7.6.2 Component: libraries/base | Version: 7.2.2 Keywords: | Os: Unknown/Multiple Architecture: Unknown/Multiple | Failure: Incorrect result at runtime Difficulty: Unknown | Testcase: Blockedby: | Blocking: Related: | ---------------------------------+------------------------------------------ Changes (by liyang): * cc: hackage.haskell.org@… (added) -- Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5859#comment:9> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler _______________________________________________ ghc-tickets mailing list [hidden email] http://www.haskell.org/mailman/listinfo/ghc-tickets |
| Powered by Nabble | Edit this page |
