Skip to content

Commit

Permalink
Replace some uses of atomicModifyIORef with STM
Browse files Browse the repository at this point in the history
This seems to cure the problem of the thread-delay benchmark behaving
pathologically due to contention on IORef blackholes at times.

Committer: Bryan O'Sullivan <bos@serpentine.com>
  • Loading branch information
simonmar committed Feb 18, 2010
1 parent f54920e commit a0b1a19
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 14 deletions.
2 changes: 1 addition & 1 deletion benchmarks/Makefile
Expand Up @@ -5,7 +5,7 @@ cc-opt-flags = -O2
include ../tests/common.mk include ../tests/common.mk


ghc-bench-flags := -package network -package network-bytestring \ ghc-bench-flags := -package network -package network-bytestring \
-package attoparsec -package bytestring-show -package mtl -package attoparsec -package bytestring-show -package mtl -package stm


ifdef USE_GHC_IO_MANAGER ifdef USE_GHC_IO_MANAGER
ghc-bench-flags += -DUSE_GHC_IO_MANAGER ghc-bench-flags += -DUSE_GHC_IO_MANAGER
Expand Down
21 changes: 13 additions & 8 deletions benchmarks/ThreadDelay.hs
Expand Up @@ -5,14 +5,13 @@


import Args (ljust, parseArgs, positive, theLast) import Args (ljust, parseArgs, positive, theLast)
import Control.Concurrent (forkIO, runInUnboundThread) import Control.Concurrent (forkIO, runInUnboundThread)
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)
import Control.Monad (when) import Control.Monad (when)
import Data.Function (on) import Data.Function (on)
import Data.Monoid (Monoid(..), Last(..)) import Data.Monoid (Monoid(..), Last(..))
import Data.IORef (atomicModifyIORef, newIORef)
import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(..)) import System.Console.GetOpt (ArgDescr(ReqArg), OptDescr(..))
import System.Environment (getArgs) import System.Environment (getArgs)
import System.Event.Thread (ensureIOManagerIsRunning) import System.Event.Thread (ensureIOManagerIsRunning)
import Control.Concurrent.STM


#ifdef USE_GHC_IO_MANAGER #ifdef USE_GHC_IO_MANAGER
import Control.Concurrent (threadDelay) import Control.Concurrent (threadDelay)
Expand All @@ -25,18 +24,24 @@ main = do
let numThreads = theLast cfgNumThreads cfg let numThreads = theLast cfgNumThreads cfg


ensureIOManagerIsRunning ensureIOManagerIsRunning
done <- newEmptyMVar done <- newTVarIO False
ref <- newIORef 0 ref <- newTVarIO 0
let loop :: Int -> IO () let loop :: Int -> IO ()
loop i = do loop i = do
when (i < numThreads) $ do when (i < numThreads) $ do
_ <- forkIO $ do _ <- forkIO $ do
threadDelay 1000 threadDelay 1000
a <- atomicModifyIORef ref $ \a -> atomically $ do
let !b = a+1 in (b,b) a <- readTVar ref
when (a == numThreads) $ putMVar done () let !b = a+1
writeTVar ref b
when (b == numThreads) $ writeTVar done True
loop (i + 1) loop (i + 1)
runInUnboundThread $ loop 0 >> takeMVar done runInUnboundThread $ do
loop 0
atomically $ do
b <- readTVar done
when (not b) retry


------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Configuration -- Configuration
Expand Down
1 change: 1 addition & 0 deletions event.cabal
Expand Up @@ -40,6 +40,7 @@ library


build-depends: build-depends:
base >= 4 && < 5, base >= 4 && < 5,
stm,
ghc-prim ghc-prim


ghc-prof-options: -auto-all ghc-prof-options: -auto-all
Expand Down
13 changes: 8 additions & 5 deletions src/System/Event/Unique.hs
Expand Up @@ -7,10 +7,10 @@ module System.Event.Unique
, newUnique , newUnique
) where ) where


import Data.IORef (IORef, atomicModifyIORef, newIORef)
import Data.Int (Int64) import Data.Int (Int64)
import Control.Concurrent.STM


newtype UniqueSource = US (IORef Int64) newtype UniqueSource = US (TVar Int64)


newtype Unique = Unique { asInt64 :: Int64 } newtype Unique = Unique { asInt64 :: Int64 }
deriving (Eq, Ord, Num) deriving (Eq, Ord, Num)
Expand All @@ -19,10 +19,13 @@ instance Show Unique where
show = show . asInt64 show = show . asInt64


newSource :: IO UniqueSource newSource :: IO UniqueSource
newSource = US `fmap` newIORef 0 newSource = US `fmap` newTVarIO 0


newUnique :: UniqueSource -> IO Unique newUnique :: UniqueSource -> IO Unique
newUnique (US ref) = do newUnique (US ref) = do
!v <- atomicModifyIORef ref $ \u -> let !u' = u+1 in (u', Unique u) atomically $ do
return v -- be careful with modify functions! u <- readTVar ref
let !u' = u+1
writeTVar ref u'
return (Unique u')
{-# INLINE newUnique #-} {-# INLINE newUnique #-}

0 comments on commit a0b1a19

Please sign in to comment.