packages feed

atomic-primops 0.1.0.2 → 0.2.2

raw patch · 11 files changed

+350/−144 lines, 11 filesdep +bits-atomicbuild-type:Customsetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: bits-atomic

API changes (from Hackage documentation)

+ Data.Atomics: loadLoadBarrier :: IO ()
+ Data.Atomics: storeLoadBarrier :: IO ()
+ Data.Atomics: writeBarrier :: IO ()
+ Data.Atomics.Counter.Foreign: casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
+ Data.Atomics.Counter.Foreign: incrCounter :: AtomicCounter -> IO Int
+ Data.Atomics.Counter.Foreign: newCounter :: IO AtomicCounter
+ Data.Atomics.Counter.Foreign: peekCTicket :: CTicket -> Int
+ Data.Atomics.Counter.Foreign: readCounter :: AtomicCounter -> IO Int
+ Data.Atomics.Counter.Foreign: readCounterForCAS :: AtomicCounter -> IO CTicket
+ Data.Atomics.Counter.Foreign: type AtomicCounter = ForeignPtr Int
+ Data.Atomics.Counter.Foreign: type CTicket = Int
+ Data.Atomics.Counter.Foreign: writeCounter :: AtomicCounter -> Int -> IO ()
+ Data.Atomics.Counter.IORef: AtomicCounter :: (IORef Int) -> AtomicCounter
+ Data.Atomics.Counter.IORef: casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
+ Data.Atomics.Counter.IORef: newCounter :: IO AtomicCounter
+ Data.Atomics.Counter.IORef: newtype AtomicCounter
+ Data.Atomics.Counter.IORef: peekCTicket :: CTicket -> Int
+ Data.Atomics.Counter.IORef: readCounter :: AtomicCounter -> IO Int
+ Data.Atomics.Counter.IORef: readCounterForCAS :: AtomicCounter -> IO CTicket
+ Data.Atomics.Counter.IORef: type CTicket = Ticket Int
+ Data.Atomics.Counter.IORef: writeCounter :: AtomicCounter -> Int -> IO ()
+ Data.Atomics.Counter.Reference: AtomicCounter :: (IORef Int) -> AtomicCounter
+ Data.Atomics.Counter.Reference: casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)
+ Data.Atomics.Counter.Reference: newCounter :: IO AtomicCounter
+ Data.Atomics.Counter.Reference: newtype AtomicCounter
+ Data.Atomics.Counter.Reference: peekCTicket :: CTicket -> Int
+ Data.Atomics.Counter.Reference: readCounter :: AtomicCounter -> IO Int
+ Data.Atomics.Counter.Reference: readCounterForCAS :: AtomicCounter -> IO CTicket
+ Data.Atomics.Counter.Reference: type CTicket = Int
+ Data.Atomics.Counter.Reference: writeCounter :: AtomicCounter -> Int -> IO ()
+ Data.Atomics.Internal: stg_loadLoadBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #)
+ Data.Atomics.Internal: stg_storeLoadBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #)
+ Data.Atomics.Internal: stg_writeBarrier# :: State# RealWorld -> (# State# RealWorld, Int# #)

Files

Data/Atomics.hs view
@@ -1,15 +1,5 @@ {-# LANGUAGE  MagicHash, UnboxedTuples, BangPatterns, ScopedTypeVariables, CPP #-} -#ifdef GHC_PROFILING_ON-#ifndef MIN_VERSION_Cabal-#error "MIN_VERSION_Cabal should be defined!"-#endif-#if MIN_VERSION_Cabal(1,17,0)-#else-#error "Before Cabal 1.17 there was a bug that prevents you from building this library with profiling.  See cabal issue 1284."-#endif-#endif- -- | Provides atomic memory operations on IORefs and Mutable Arrays. -- --   Pointer equality need not be maintained by a Haskell compiler.  For example, Int@@ -31,13 +21,15 @@    readForCAS, casIORef, casIORef2,         -- * Atomic operations on raw MutVars-   readMutVarForCAS, casMutVar, casMutVar2-      +   readMutVarForCAS, casMutVar, casMutVar2,++   -- * Memory barriers+   storeLoadBarrier, loadLoadBarrier, writeBarrier  ) where  import Control.Monad.ST (stToIO) import Data.Primitive.Array (MutableArray(MutableArray))-import Data.Atomics.Internal (casArray#, readForCAS#, casMutVarTicketed#, Ticket)+import Data.Atomics.Internal import Data.Int -- TEMPORARY  import Data.IORef@@ -50,9 +42,33 @@ import GHC.IO (IO(IO)) import GHC.Word (Word(W#)) ---------------------------------------------------------------------------------+#ifdef DEBUG_ATOMICS+#warning "Activating DEBUG_ATOMICS... NOINLINE's and more"+{-# NOINLINE seal #-} +{-# NOINLINE casIORef #-}+{-# NOINLINE casArrayElem2 #-}   +{-# NOINLINE readArrayElem #-}+{-# NOINLINE readForCAS #-}+{-# NOINLINE casArrayElem #-}+{-# NOINLINE casIORef2 #-}+{-# NOINLINE readMutVarForCAS #-}+{-# NOINLINE casMutVar #-}+{-# NOINLINE casMutVar2 #-}+#else+{-# INLINE casIORef #-}+{-# INLINE casArrayElem2 #-}   +{-# INLINE readArrayElem #-}+{-# INLINE readForCAS #-} {-# INLINE casArrayElem #-}+{-# INLINE casIORef2 #-}+{-# INLINE readMutVarForCAS #-}+{-# INLINE casMutVar #-}+{-# INLINE casMutVar2 #-}+#endif++--------------------------------------------------------------------------------+ -- | Compare-and-swap  casArrayElem :: MutableArray RealWorld a -> Int -> Ticket a -> a -> IO (Bool, Ticket a) -- casArrayElem (MutableArray arr#) (I# i#) old new = IO$ \s1# ->@@ -60,7 +76,6 @@ --    (# s2#, x#, res #) -> (# s2#, (x# ==# 0#, res) #) casArrayElem arr i old new = casArrayElem2 arr i old (seal new) -{-# INLINE casArrayElem2 #-}    -- | This variant takes two tickets: the 'new' value is a ticket rather than an -- arbitrary, lifted, Haskell value. casArrayElem2 :: MutableArray RealWorld a -> Int -> Ticket a -> Ticket a -> IO (Bool, Ticket a)@@ -69,7 +84,6 @@    (# s2#, x#, res #) -> (# s2#, (x# ==# 0#, res) #)  -{-# INLINE readArrayElem #-} readArrayElem :: forall a . MutableArray RealWorld a -> Int -> IO (Ticket a) -- readArrayElem = unsafeCoerce# readArray# readArrayElem (MutableArray arr#) (I# i#) = IO $ \ st -> unsafeCoerce# (fn st)@@ -80,11 +94,9 @@  -------------------------------------------------------------------------------- -{-# INLINE readForCAS #-} readForCAS :: IORef a -> IO ( Ticket a ) readForCAS (IORef (STRef mv)) = readMutVarForCAS mv -{-# INLINE casIORef #-} -- | Performs a machine-level compare and swap operation on an -- 'IORef'. Returns a tuple containing a 'Bool' which is 'True' when a -- swap is performed, along with the 'current' value from the 'IORef'.@@ -97,8 +109,6 @@          -> IO (Bool, Ticket a) casIORef (IORef (STRef var)) old new = casMutVar var old new  --{-# INLINE casIORef2 #-} -- | This variant takes two tickets, i.e. the 'new' value is a ticket rather than an -- arbitrary, lifted, Haskell value. casIORef2 :: IORef a @@ -111,6 +121,9 @@ --------------------------------------------------------------------------------  -- | A ticket contains or can get the usable Haskell value.+{-# NOINLINE peekTicket #-}+-- At least this function MUST remain NOINLINE.  Issue5 is an example of a bug that+-- ensues otherwise. peekTicket :: Ticket a -> a  peekTicket = unsafeCoerce# @@ -119,19 +132,14 @@ seal :: a -> Ticket a  seal = unsafeCoerce# --{-# INLINE readMutVarForCAS #-} readMutVarForCAS :: MutVar# RealWorld a -> IO ( Ticket a ) readMutVarForCAS !mv = IO$ \ st -> readForCAS# mv st - -- | MutVar counterpart of `casIORef`. -- casMutVar :: MutVar# RealWorld a -> Ticket a -> a -> IO (Bool, Ticket a) casMutVar !mv !tick !new = casMutVar2 mv tick (seal new)-{-# INLINE casMutVar #-} - -- | This variant takes two tickets, i.e. the 'new' value is a ticket rather than an -- arbitrary, lifted, Haskell value. casMutVar2 :: MutVar# RealWorld a -> Ticket a -> Ticket a -> IO (Bool, Ticket a)@@ -141,7 +149,27 @@       (# st, (flag ==# 0#, tick') #) --      (# st, if flag ==# 0# then Succeed tick' else Fail tick' #) --      if flag ==# 0#    then       else (# st, Fail (W# tick')  #)-{-# INLINE casMutVar2 #-}  +--------------------------------------------------------------------------------+-- Memory barriers+-------------------------------------------------------------------------------- ++-- | Memory barrier implemented by the GHC rts (SMP.h).+storeLoadBarrier :: IO ()+storeLoadBarrier = IO$ \st ->+  case stg_storeLoadBarrier# st of+    (# st', _ #) -> (# st', () #)++-- | Memory barrier implemented by the GHC rts (SMP.h).+loadLoadBarrier :: IO ()+loadLoadBarrier = IO$ \st ->+  case stg_loadLoadBarrier# st of+    (# st', _ #) -> (# st', () #)++-- | Memory barrier implemented by the GHC rts (SMP.h).+writeBarrier :: IO ()+writeBarrier = IO$ \st ->+  case stg_writeBarrier# st of+    (# st', _ #) -> (# st', () #)
+ Data/Atomics/Counter.hs view
@@ -0,0 +1,8 @@+++module Data.Atomics.Counter+       (+         module Data.Atomics.Counter.IORef+       ) where++import Data.Atomics.Counter.IORef
+ Data/Atomics/Counter/Foreign.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE BangPatterns #-}++-- | This implementation stores an unboxed counter and uses FFI+-- operations to modify its contents.++module Data.Atomics.Counter.Foreign+   where++import Data.Bits.Atomic+import Foreign.ForeignPtr+import Foreign.Storable++-- newtype AtomicCounter = AtomicCounter (ForeignPtr Int)+type AtomicCounter = ForeignPtr Int++type CTicket = Int++-- | Create a new counter initialized to zero.+newCounter :: IO AtomicCounter+newCounter = do x <- mallocForeignPtr+                writeCounter x 0+                return x++-- | Try repeatedly until we successfully increment the counter.+-- Returns the original value before the increment.+incrCounter :: AtomicCounter -> IO Int+incrCounter r = withForeignPtr r$ \r' -> fetchAndAdd r' 1 ++readCounterForCAS :: AtomicCounter -> IO CTicket+readCounterForCAS = readCounter++peekCTicket :: CTicket -> Int+peekCTicket x = x++readCounter :: AtomicCounter -> IO Int+readCounter r = withForeignPtr r peek ++-- | Make a non-atomic write to the counter.  No memory-barrier.+writeCounter :: AtomicCounter -> Int -> IO ()+writeCounter r !new = withForeignPtr r $ \r' -> poke r' new++casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)+casCounter r !tick !new = withForeignPtr r $ \r' -> do+   b <- compareAndSwap r' tick new+   -- if b then return (True,new)+   --      else do x <- peek r'+   --              return (False,x)+   return (b==tick, b)
+ Data/Atomics/Counter/IORef.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE BangPatterns #-}++-- | This version uses a boxed IORef representation, but it can be+-- somewhat cheaper because it uses raw CAS rather than full atomicModifyIORef.++module Data.Atomics.Counter.IORef+       where++import Data.IORef+import Data.Atomics as A++--------------------------------------------------------------------------------++-- type AtomicCounter = IORef Int+newtype AtomicCounter = AtomicCounter (IORef Int)++type CTicket = Ticket Int++-- | Create a new counter initialized to zero.+newCounter :: IO AtomicCounter+newCounter = fmap AtomicCounter $ newIORef 0++-- | Try repeatedly until we successfully increment the counter.+-- incrCounter =++readCounterForCAS :: AtomicCounter -> IO CTicket+readCounterForCAS (AtomicCounter r) = readForCAS r++peekCTicket :: CTicket -> Int+peekCTicket = peekTicket ++readCounter :: AtomicCounter -> IO Int+readCounter (AtomicCounter r) = readIORef r++-- | Make a non-atomic write to the counter.  No memory-barrier.+writeCounter :: AtomicCounter -> Int -> IO ()+writeCounter (AtomicCounter r) !new = writeIORef r new++casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)+casCounter (AtomicCounter r) tick !new = casIORef r tick new
+ Data/Atomics/Counter/Reference.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE BangPatterns #-}++-- | This reference version is implemented with atomicModifyIORef and can be a useful+-- fallback if one of the other implementations needs to be debugged.+module Data.Atomics.Counter.Reference+       where++import Data.IORef+-- import Data.Atomics+import System.IO.Unsafe (unsafePerformIO)++--------------------------------------------------------------------------------++-- type AtomicCounter = IORef Int+newtype AtomicCounter = AtomicCounter (IORef Int)++type CTicket = Int++-- | Create a new counter initialized to zero.+newCounter :: IO AtomicCounter+newCounter = fmap AtomicCounter $ newIORef 0++-- | Try repeatedly until we successfully increment the counter.+-- incrCounter =++readCounterForCAS :: AtomicCounter -> IO CTicket+readCounterForCAS = readCounter++peekCTicket :: CTicket -> Int+peekCTicket x = x++readCounter :: AtomicCounter -> IO Int+readCounter (AtomicCounter r) = readIORef r++-- | Make a non-atomic write to the counter.  No memory-barrier.+writeCounter :: AtomicCounter -> Int -> IO ()+writeCounter (AtomicCounter r) !new = writeIORef r new++casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket)+casCounter (AtomicCounter r) oldT !new =++   -- This approach for faking it requires proper equality, it doesn't use pointer+   -- equality at all.  That makes it not a true substitute but useful for some+   -- debugging.+   -- fakeCAS :: Eq a => IORef a -> Ticket a -> a -> IO (Bool,Ticket a)+  +  -- let old = peekTicket oldT+  let old = oldT in +  atomicModifyIORef r $ \val -> +{-+    trace ("    DBG: INSIDE ATOMIC MODIFY, ptr eqs found/expected: " ++ +	   show [ptrEq val old, ptrEq val old, ptrEq val old] ++ +	   " ptr eq self: " ++ +	   show [ptrEq val val, ptrEq old old] +++	   " names: " ++ show (unsafeName old, unsafeName old, unsafeName val, unsafeName val)+	  ) $+-}+    if   (val == old)+    then (new, (True, val))+    else (val, (False,val))+    -- then (new, (True, unsafeCoerce# val))+    -- else (val, (False,unsafeCoerce# val))++{-+{-# NOINLINE unsafeName #-}+unsafeName :: a -> Int+unsafeName x = unsafePerformIO $ do +   sn <- makeStableName x+   return (hashStableName sn)++{-# NOINLINE ptrEq #-}+ptrEq :: a -> a -> Bool+ptrEq !x !y = I# (reallyUnsafePtrEquality# x y) == 1++-}
Data/Atomics/Internal.hs view
@@ -6,30 +6,44 @@ module Data.Atomics.Internal     (casArray#,      readForCAS#, casMutVarTicketed#, -    Ticket )+    Ticket,+    stg_storeLoadBarrier#, stg_loadLoadBarrier#, stg_writeBarrier# )   where   import GHC.Base (Int(I#)) import GHC.Word (Word(W#)) import GHC.Prim (RealWorld, Int#, Word#, State#, MutableArray#, unsafeCoerce#, MutVar#, reallyUnsafePtrEquality#) -#if MIN_VERSION_base(4,6,0)+#if MIN_VERSION_base(4,5,0) -- Any is only in GHC 7.6!!!  We want 7.4 support. import GHC.Prim (readMutVar#, casMutVar#, Any) #else-#error "Need to figure out how to emulate Any () in GHC 7.4."+#error "Need to figure out how to emulate Any () in GHC < 7.4 !" -- type Any a = Word# #endif     +#ifdef DEBUG_ATOMICS+{-# NOINLINE readForCAS# #-}+{-# NOINLINE casArray# #-}+{-# NOINLINE casMutVarTicketed# #-}+#define CASTFUN+#else+{-# INLINE casMutVarTicketed# #-}+{-# INLINE casArray# #-}+-- I *think* inlining may be ok here as long as casting happens on the arrow types:+#define CASTFUN+#endif+ ----------------------------------------------------------------------------------- Entrypoints for end-users+-- CAS and friendsa -------------------------------------------------------------------------------- -{-# INLINE casArray# #-} -- | Unsafe, machine-level atomic compare and swap on an element within an Array.   casArray# :: MutableArray# RealWorld a -> Int# -> Ticket a -> Ticket a            -> State# RealWorld -> (# State# RealWorld, Int#, Ticket a #)+#ifdef CASTFUN+-- WARNING: cast of a function -- need to verify these are safe or eta expand. casArray# = unsafeCoerce# casArrayTypeErased#-+#endif  -- | When performing compare-and-swaps, the /ticket/ encapsulates proof -- that a thread observed a specific previous value of a mutable@@ -59,20 +73,39 @@  -------------------------------------------------------------------------------- --{-# INLINE readForCAS# #-} readForCAS# :: MutVar# RealWorld a ->                State# RealWorld -> (# State# RealWorld, Ticket a #)+-- WARNING: cast of a function -- need to verify these are safe or eta expand:+#ifdef CASTFUN readForCAS# = unsafeCoerce# readMutVar#--- readForCAS# = unsafeCoerce# readMutVar_TypeErased#+#else+readForCAS# mv rw =+  case readMutVar# mv rw of+    (# rw', a #) -> (# rw', unsafeCoerce# a #)+#endif -{-# INLINE casMutVarTicketed# #-}+ casMutVarTicketed# :: MutVar# RealWorld a -> Ticket a -> Ticket a ->                State# RealWorld -> (# State# RealWorld, Int#, Ticket a #)+-- WARNING: cast of a function -- need to verify these are safe or eta expand:+#ifdef CASTFUN casMutVarTicketed# = unsafeCoerce# casMutVar_TypeErased#--- casMutVarTicketed# = unsafeCoerce# casMutVar#+#endif  --------------------------------------------------------------------------------+-- Memory barriers+--------------------------------------------------------------------------------++foreign import prim "stg_store_load_barrier" stg_storeLoadBarrier#+  :: State# RealWorld -> (# State# RealWorld, Int# #)++foreign import prim "stg_load_load_barrier" stg_loadLoadBarrier#+  :: State# RealWorld -> (# State# RealWorld, Int# #)++foreign import prim "stg_write_barrier" stg_writeBarrier#+  :: State# RealWorld -> (# State# RealWorld, Int# #)++-------------------------------------------------------------------------------- -- Type-erased versions that call the raw foreign primops: -------------------------------------------------------------------------------- -- Due to limitations of the "foreign import prim" mechanism, we can't use the@@ -85,7 +118,7 @@ --   out_of_line = True --   has_side_effects = True --- | This alternate version of casMutVar returns a numeric "ticket" for+-- | This alternate version of casMutVar returns an opaque "ticket" for --   future CAS operations. foreign import prim "stg_casMutVar2zh" casMutVar_TypeErased#   :: MutVar# RealWorld () -> Any () -> Any () ->@@ -94,3 +127,4 @@ -- foreign import prim "stg_readMutVar2zh" readMutVar_TypeErased# --   :: MutVar# RealWorld () ->  --      State# RealWorld -> (# State# RealWorld, Any () #)+
Setup.hs view
@@ -1,2 +1,27 @@-import Distribution.Simple-main = defaultMain++import Control.Monad (when)+import Language.Haskell.TH+import Distribution.Simple                (defaultMainWithHooks, simpleUserHooks, UserHooks(postConf), Args)+import Distribution.Simple.Utils          (cabalVersion)+import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.Setup          (ConfigFlags)+import Distribution.Version               (Version(..))+import Distribution.PackageDescription    (PackageDescription)+import Debug.Trace++checkGoodVersion :: IO ()+checkGoodVersion =+  if   cabalVersion >= Version [1,17,0] []+  then putStrLn (" [Setup.hs] This version of Cabal is ok for profiling: "++show cabalVersion)+  else error (" [Setup.hs] This package should not be used in profiling mode with cabal version "+++                        show (versionBranch cabalVersion)++" < 1.17.0\n"+++                        " It will break, see cabal issue #1284")++main :: IO ()+main = do+  let myPostConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()+      myPostConf _args confFlags _descr lbi =+        when (withProfLib lbi)+          checkGoodVersion+      hooks = simpleUserHooks { postConf = myPostConf }+  defaultMainWithHooks hooks
atomic-primops.cabal view
@@ -1,5 +1,5 @@ Name:                atomic-primops-Version:             0.1.0.2+Version:             0.2.2 License:             BSD3 License-file:        LICENSE Author:              Ryan Newton@@ -7,7 +7,7 @@ Category:            Data Stability:           Provisional -- Portability:         non-portabile (x86_64)-Build-type:          Simple+Build-type:          Custom -- TODO: This requirement needs to be bumped to 1.17 when the latest cabal is -- released.  This package triggers issue #1284: Cabal-version:       >=1.8@@ -16,6 +16,8 @@ -- Version History: -- 0.1.0.0 -- initial release -- 0.1.0.2 -- disable profiling+-- 0.2 -- Critical bugfix and add Counter.+-- 0.2.2 -- Add more counters  Synopsis: A safe approach to CAS and other atomic ops in Haskell. @@ -34,14 +36,23 @@                      testing/runTest.hs, testing/Test.hs, testing/test-atomic-primops.cabal --                    Makefile, Test.hs, README.md +Flag debug+    Description: Enable extra internal checks.+    Default: False+ Library   exposed-modules:   Data.Atomics                      Data.Atomics.Internal+                     Data.Atomics.Counter+                     Data.Atomics.Counter.IORef+                     Data.Atomics.Counter.Reference+                     Data.Atomics.Counter.Foreign   ghc-options: -O2 -funbox-strict-fields    -- casMutVar# had a bug in GHC 7.2, thus we require GHC 7.4 or greater-  -- (base 4.5 or greater).-  build-depends:     base >= 4.5.0.0 && < 4.7, ghc-prim, primitive, Cabal+  -- (base 4.5 or greater). We also need the "Any" kind.+  build-depends:     base >= 4.5.0.0 && < 4.7, ghc-prim, primitive, Cabal,+                     bits-atomic    -- TODO: Try to push support back to 7.0:   -- Ah, but if we don't USE casMutVar# in this package we are ok:@@ -55,12 +66,14 @@   --   ghc-prof-options: ERROR_DO_NOT_BUILD_THIS_WITH_PROFILING_YET__SEE_CABAL_ISSUE_1284   -- } +  if flag(debug)+    cpp-options: -DDEBUG_ATOMICS+ -- -- [2013.04.08] This isn't working presently: -- -- I'm having problems with building it along with the library; see DEVLOG. -- -- Switching to a separate package in ./testing/  -- Test-Suite test-atomic-primops --     type:       exitcode-stdio-1.0-   Source-Repository head
cbits/primops.cmm view
@@ -89,3 +89,22 @@ } /* emitPrimOp [res] ReadMutVarOp [mutv] _ */ /*    = stmtC (CmmAssign (CmmLocal res) (cmmLoadIndexW mutv fixedHdrSize gcWord)) */+++// This is already existing functionality in the RTS (SMP.h).  It+// handles the complexity of architecture-portability.  We just need+// to expose it here.+stg_store_load_barrier {+    foreign "C" store_load_barrier();+    RET_N(0);+}++stg_load_load_barrier {+    foreign "C" load_load_barrier();+    RET_N(0);+}++stg_write_barrier {+    foreign "C" write_barrier();+    RET_N(0);+}
testing/Test.hs view
@@ -44,6 +44,9 @@  -- import Test.Framework.TH (defaultMainGenerator) +import CommonTesting +import CounterTests (counterTests)+ ------------------------------------------------------------------------  expect_false_positive_on_GC :: Bool@@ -64,6 +67,7 @@          , testCase "create_and_mutate"       case_create_and_mutate          , testCase "create_and_mutate_twice" case_create_and_mutate_twice          , testCase "n_threads_mutate"        case_n_threads_mutate+         , testCase "run_barriers"            case_run_barriers           , testCase "test_succeed_once Int"   (test_succeed_once (0::Int))          , testCase "test_succeed_once Int64" (test_succeed_once (0::Int64))@@ -88,6 +92,7 @@                       [1, numCapabilities `quot` 2, numCapabilities, 2*numCapabilities]          , size    <- [1, 10, 100]          , iters   <- [10000]]+         ++ counterTests           setify :: [Int] -> [Int] setify = S.toList . S.fromList@@ -259,6 +264,13 @@   ans <- readIORef counter   assertBool "Did the sum end up equal to 120?" (ans == 120) +-- | Just make sure these link and run properly:+case_run_barriers :: Assertion+case_run_barriers = do+  A.storeLoadBarrier+  A.loadLoadBarrier+  A.writeBarrier+ ----------------------------------------------------------------------------------------------------  ----------------------------------------------------------------------------------------------------@@ -364,63 +376,6 @@   ------------------------------------------------------------------------------------------------------- Helpers-------------------------------------------------------------------------------------------------------checkGCStats :: IO ()-checkGCStats = return ()-    -- do b <- getGCStatsEnabled-    --    unless b $ error "Cannot run tests without +RTS -T !!"--dotdot :: Int -> String -> String-dotdot len chars = -  if length chars > len-  then take len chars ++ "..."-  else chars--printBits :: [Bool] -> IO ()-printBits = print . map pb- where pb True  = '1' -       pb False = '0'--forkJoin :: Int -> (Int -> IO b) -> IO [b]-forkJoin numthreads action = -  do-     answers <- sequence (replicate numthreads newEmptyMVar) -- padding?-     dbgPrint 1 $ printf "Forking %d threads.\n" numthreads-    -     forM_ (zip [0..] answers) $ \ (ix,mv) -> - 	forkIO (action ix >>= putMVar mv)--     -- Reading answers:-     ls <- mapM readMVar answers-     dbgPrint 1 $ printf "All %d thread(s) completed\n" numthreads-     return ls---- TODO: Here's an idea.  Describe a structure of forking and joining threads for--- tests, then we can stress test it by running different interleavings explicitly.-data Forkable a = Fork Int (IO a)-                | Parallel (Forkable a) (Forkable a) -- Parallel composition-                | Sequence (Forkable a) (Forkable a) -- Sequential compositon, with barrier---                | Barrier Forkable---timeit :: IO a -> IO a -timeit ioact = do -   start <- getCurrentTime-   res <- ioact-   end   <- getCurrentTime-   putStrLn$ "  Time elapsed: " ++ show (diffUTCTime end start)-   return res--{-# NOINLINE unsafeName #-}-unsafeName :: a -> Int-unsafeName x = unsafePerformIO $ do -   sn <- makeStableName x-   return (hashStableName sn)------------------------------------------------------------------------------------------------------- {-  -- UNFINISHED@@ -519,44 +474,3 @@  -- main = test 3 -}----------------------------------------------------------------------------------------------------------- DEBUGGING--------------------------------------------------------------------------------------------------------- | Debugging flag shared by all accelerate-backend-kit modules.---   This is activated by setting the environment variable DEBUG=1..5-dbg :: Int-dbg = case lookup "DEBUG" unsafeEnv of-       Nothing  -> defaultDbg-       Just ""  -> defaultDbg-       Just "0" -> defaultDbg-       Just s   ->-         trace (" ! Responding to env Var: DEBUG="++s)$-         case reads s of-           ((n,_):_) -> n-           [] -> error$"Attempt to parse DEBUG env var as Int failed: "++show s--defaultDbg :: Int-defaultDbg = 0--unsafeEnv :: [(String,String)]-unsafeEnv = unsafePerformIO getEnvironment---- | Print if the debug level is at or above a threshold.-dbgPrint :: Int -> String -> IO ()-dbgPrint lvl str = if dbg < lvl then return () else do-    hPutStrLn stderr str-    hFlush stderr---- My own forM for numeric ranges (not requiring deforestation optimizations).--- Inclusive start, exclusive end.-{-# INLINE for_ #-}-for_ :: Monad m => Int -> Int -> (Int -> m ()) -> m ()-for_ start end _fn | start > end = error "for_: start is greater than end"-for_ start end fn = loop start-  where-   loop !i | i == end  = return ()-	   | otherwise = do fn i; loop (i+1)
testing/runTest.hs view
@@ -8,6 +8,8 @@ --  p <- getNumProcessors   putStrLn "[TestHarness] Calling compiled test-atomic-primops executable..."   ExitSuccess <- system "./dist/build/test-atomic-primops/test-atomic-primops +RTS -N1"-  ExitSuccess <- system$"./dist/build/test-atomic-primops/test-atomic-primops +RTS -N"+  -- TEMP: Fixing this at four processors because it takes a REALLY long time at larger numbers:+  ExitSuccess <- system$"./dist/build/test-atomic-primops/test-atomic-primops +RTS -N4"+  -- It does 248 test cases and takes 55s at -N16... --  ExitSuccess <- system$"./dist/build/test-atomic-primops/test-atomic-primops +RTS -N"++show p   return ()