[commit: ghc] wip/dfeuer-interleave-null: Speed up unsafeInterleaveIO (a53064e)

git at git.haskell.org git at git.haskell.org
Wed May 3 16:42:47 UTC 2017


Repository : ssh://git@git.haskell.org/ghc

On branch  : wip/dfeuer-interleave-null
Link       : http://ghc.haskell.org/trac/ghc/changeset/a53064ee44d398ba175fdca3bec551e7db62aa26/ghc

>---------------------------------------------------------------

commit a53064ee44d398ba175fdca3bec551e7db62aa26
Author: David Feuer <David.Feuer at gmail.com>
Date:   Tue May 2 17:09:00 2017 -0400

    Speed up unsafeInterleaveIO
    
    Summary:
    Use an `MVar` and a "null pointer" trick I learned from Edward
    Kmett to try to make `unsafeInterleaveIO` faster in the threaded
    runtime, where `noDuplicate#` is not always cheap.
    
    Reviewers: austin, hvr, bgamari
    
    Subscribers: rwbarton, thomie
    
    Differential Revision: https://phabricator.haskell.org/D3529


>---------------------------------------------------------------

a53064ee44d398ba175fdca3bec551e7db62aa26
 libraries/base/GHC/IO/Unsafe.hs | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/libraries/base/GHC/IO/Unsafe.hs b/libraries/base/GHC/IO/Unsafe.hs
index c1c07ae..376412b 100644
--- a/libraries/base/GHC/IO/Unsafe.hs
+++ b/libraries/base/GHC/IO/Unsafe.hs
@@ -26,7 +26,9 @@ module GHC.IO.Unsafe (
   ) where
 
 import GHC.Base
-
+import GHC.MVar
+import GHC.IORef
+import GHC.STRef
 
 {-|
 This is the \"back door\" into the 'IO' monad, allowing
@@ -111,12 +113,33 @@ file reading, see 'System.IO.hGetContents'.
 -}
 {-# INLINE unsafeInterleaveIO #-}
 unsafeInterleaveIO :: IO a -> IO a
-unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)
+unsafeInterleaveIO m = do
+  v <- case unclaimed of
+         IORef (STRef r) -> unsafeCoerce# newMVar r
+  unsafeDupableInterleaveIO $ do
+  a <- takeMVar v
+  if isUnclaimed a
+    then do
+      res <- m
+      putMVar v res
+      pure res
+    else a <$ putMVar v a
+
+-- We use 'unclaimed' as a "null pointer" in 'unsafeInterleaveIO'.
+-- It must not be exported!
+{-# NOINLINE unclaimed #-}
+unclaimed :: IORef ()
+unclaimed = unsafePerformIO $ newIORef ()
+
+isUnclaimed :: a -> Bool
+isUnclaimed a = case unclaimed of
+  IORef (STRef r) -> isTrue# (unsafeCoerce# reallyUnsafePtrEquality# a r)
+
 
 -- Note [unsafeDupableInterleaveIO should not be inlined]
 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 --
--- We used to believe that INLINE on unsafeInterleaveIO was safe,
+-- We used to believe that INLINE on unsafeDupableInterleaveIO was safe,
 -- because the state from this IO thread is passed explicitly to the
 -- interleaved IO, so it cannot be floated out and shared.
 --



More information about the ghc-commits mailing list