rrnewton / haskell-lockfree Goto Github PK
View Code? Open in Web Editor NEWA collection of different packages for CAS based data structures.
A collection of different packages for CAS based data structures.
Currently the portable code (inline assembly) is in the GHC RTS, and Haskell code needs to make a call into the RTS to issue a barrier. This is wasteful.
Here I create a new IORef
, get a ticket and immediately compare-and-swap. I expect that to succeed and thus the resulting boolean to be True
, but it is actually False
, regardless of optimization levels. The following features seem relevant, and removing any of them results in the output being True
again:
T
IORef
) as an INLINE
variable (surprisingly, either removing the INLINE
pragma or inlining zero
by hand make the result True
)What is wrong here?
import Data.IORef
import Data.Atomics
newtype T = T Int
zero :: T
zero = T 0
{-# INLINE zero #-}
main = do
x <- newIORef zero
ticket <- readForCAS x
(b, _) <- ticket `seq` casIORef x ticket (T 1)
print b
Tested with 0.4 and whatever's currently in this repo
import Control.Concurrent
import Data.Atomics.Counter
import Control.Monad
import GHC.Conc
main = do
n0 <- test newCounter readCounter incrCounter
n1 <- test newMVar takeMVar (\n v-> modifyMVar_ v (return . (+1)) )
if n0 /= n1
then putStrLn $ "Counter broken: expecting "++(show n1)++" got "++(show n0)
else putStrLn "OK"
test new read incr = do
let n = 100000
procs <- getNumCapabilities
counter <- new (1::Int)
dones <- replicateM procs newEmptyMVar ; starts <- replicateM procs newEmptyMVar
mapM_ (\(start1,done1)-> forkIO $ takeMVar start1 >> replicateM_ (n `div` procs) (incr 1 counter) >> putMVar done1 ()) $ zip starts dones
mapM_ (\v-> putMVar v ()) starts ; mapM_ (\v-> takeMVar v) dones
read counter
On GHC 7.6.3, compiled with cabal 1.18.0.2
with:
executable test-atomics
main-is: TestAtomics.hs
build-depends: base >=4.6 && <4.7
, stm
, async
, atomic-primops == 0.4
ghc-options: -O2 -rtsopts -threaded -with-rtsopts=-N2
ghc-options: -fforce-recomp
default-language: Haskell2010
In haddocks for atomicModifyIORefCAS
I see
A drop-in replacement for `atomicModifyIORefCAS` that...
How is it possible? I there some fixpoint operator for haddocks? :)
GHC 7.10.3, stackage lts-5.1, atomic-primops 8.0.2, architecture: aarch64 (armv8)
[1 of 1] Compiling Main ( /tmp/stack6984/atomic-primops-0.8.0.2/Setup.hs, /tmp/stack6984/atomic-primops-0.8.0.2/.stack-work/dist/aarch64-linux/Cabal-1.22.7.0/setup/Main.o )
Linking /tmp/stack6984/atomic-primops-0.8.0.2/.stack-work/dist/aarch64-linux/Cabal-1.22.7.0/setup/setup ...
Configuring atomic-primops-0.8.0.2...
Building atomic-primops-0.8.0.2...
Preprocessing library atomic-primops-0.8.0.2...
[1 of 3] Compiling Data.Atomics.Internal ( Data/Atomics/Internal.hs, .stack-work/dist/aarch64-linux/Cabal-1.22.7.0/build/Data/Atomics/Internal.o )
Data/Atomics/Internal.hs:69:20: Warning:
Defined but not used: data constructor ‘Ticket’
[2 of 3] Compiling Data.Atomics.Counter ( Data/Atomics/Counter.hs, .stack-work/dist/aarch64-linux/Cabal-1.22.7.0/build/Data/Atomics/Counter.o )
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/tmp/ghc7100_0/ghc_14.hc: In function ‘c1Ni_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:452:13:
note: in expansion of macro ‘BaseReg’
#define Sp (BaseReg->rSp)
^
/tmp/ghc7100_0/ghc_14.hc:59:93:
note: in expansion of macro ‘Sp’
_s1LV = hs_atomic_add64((((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x) + 0x10UL, Sp[1]);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/tmp/ghc7100_0/ghc_14.hc: In function ‘c1NY_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_14.hc:143:70:
note: in expansion of macro ‘R1’
_s1M5 = hs_atomic_add64((((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x) + 0x10UL, _s1M0);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/tmp/ghc7100_0/ghc_14.hc: In function ‘r1LH_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_cmpxchg64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:452:13:
note: in expansion of macro ‘BaseReg’
#define Sp (BaseReg->rSp)
^
/tmp/ghc7100_0/ghc_14.hc:466:45:
note: in expansion of macro ‘Sp’
_s1MD = hs_cmpxchg64((*Sp) + 0x10UL, _s1My, Sp[2]);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_14.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:45:9:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord hs_cmpxchg64(volatile StgWord64 *x, StgWord64 old, StgWord64 new_);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/tmp/ghc7100_0/ghc_18.hc: In function ‘c1Ua_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:452:13:
note: in expansion of macro ‘BaseReg’
#define Sp (BaseReg->rSp)
^
/tmp/ghc7100_0/ghc_18.hc:59:93:
note: in expansion of macro ‘Sp’
_s1SN = hs_atomic_add64((((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x) + 0x10UL, Sp[1]);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/tmp/ghc7100_0/ghc_18.hc: In function ‘c1UQ_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_18.hc:143:70:
note: in expansion of macro ‘R1’
_s1SX = hs_atomic_add64((((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x) + 0x10UL, _s1SS);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/tmp/ghc7100_0/ghc_18.hc: In function ‘r1LH_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_cmpxchg64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:452:13:
note: in expansion of macro ‘BaseReg’
#define Sp (BaseReg->rSp)
^
/tmp/ghc7100_0/ghc_18.hc:466:45:
note: in expansion of macro ‘Sp’
_s1Tv = hs_cmpxchg64((*Sp) + 0x10UL, _s1Tq, Sp[2]);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_18.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:45:9:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord hs_cmpxchg64(volatile StgWord64 *x, StgWord64 old, StgWord64 new_);
^
[3 of 3] Compiling Data.Atomics ( Data/Atomics.hs, .stack-work/dist/aarch64-linux/Cabal-1.22.7.0/build/Data/Atomics.o )
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3dY_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:452:13:
note: in expansion of macro ‘BaseReg’
#define Sp (BaseReg->rSp)
^
/tmp/ghc7100_0/ghc_23.hc:239:38:
note: in expansion of macro ‘Sp’
_s37V = hs_atomic_add64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), _s37S);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3eQ_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_xor64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:349:110:
note: in expansion of macro ‘R1’
_s38a = hs_atomic_xor64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:41:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_xor64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3fF_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_or64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:459:109:
note: in expansion of macro ‘R1’
_s38o = hs_atomic_or64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:37:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_or64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3gu_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_nand64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:569:111:
note: in expansion of macro ‘R1’
_s38C = hs_atomic_nand64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:33:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_nand64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3hj_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_and64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:679:110:
note: in expansion of macro ‘R1’
_s38Q = hs_atomic_and64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:29:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_and64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3i8_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_sub64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:789:110:
note: in expansion of macro ‘R1’
_s394 = hs_atomic_sub64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:25:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_sub64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3iX_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_atomic_add64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:899:110:
note: in expansion of macro ‘R1’
_s39i = hs_atomic_add64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:21:11:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord64 hs_atomic_add64(volatile StgWord64 *x, StgWord64 val);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:262:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/tmp/ghc7100_0/ghc_23.hc: In function ‘c3jU_entry’:
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:445:28:
warning: passing argument 1 of ‘hs_cmpxchg64’ makes pointer from integer without a cast [enabled by default]
#define BaseReg (&((struct PartCapability_ *)MainCapability)->r)
^
/usr/local/lib/ghc-7.10.3/include/stg/Regs.h:162:14:
note: in expansion of macro ‘BaseReg’
# define R1 (BaseReg->rR1)
^
/tmp/ghc7100_0/ghc_23.hc:1031:114:
note: in expansion of macro ‘R1’
_s39z = hs_cmpxchg64((Sp[1]) + (((Sp[2]) << 0x3UL) + 0x10UL), Sp[3], ((struct {W_ x;} __attribute__((packed))*) (R1.w+7))->x);
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:273:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/Prim.h:45:9:
note: expected ‘volatile StgWord64 *’ but argument is of type ‘long unsigned int’
StgWord hs_cmpxchg64(volatile StgWord64 *x, StgWord64 old, StgWord64 new_);
^
In file included from /tmp/ghc7100_0/ghc_23.hc:3:0:
/tmp/ghc7100_0/ghc_23.hc: At top level:
/tmp/ghc7100_0/ghc_23.hc:2704:5:
error: conflicting types for ‘store_load_barrier’
EF_(store_load_barrier);
^
/usr/local/lib/ghc-7.10.3/include/Stg.h:220:36:
note: in definition of macro ‘EF_’
#define EF_(f) extern StgFunPtr f() /* See Note [External function prototypes] */
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:274:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/SMP.h:422:20:
note: previous definition of ‘store_load_barrier’ was here
EXTERN_INLINE void store_load_barrier() {} /* nothing */
^
In file included from /tmp/ghc7100_0/ghc_23.hc:3:0:
/tmp/ghc7100_0/ghc_23.hc:2741:5:
error: conflicting types for ‘load_load_barrier’
EF_(load_load_barrier);
^
/usr/local/lib/ghc-7.10.3/include/Stg.h:220:36:
note: in definition of macro ‘EF_’
#define EF_(f) extern StgFunPtr f() /* See Note [External function prototypes] */
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:274:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/SMP.h:423:20:
note: previous definition of ‘load_load_barrier’ was here
EXTERN_INLINE void load_load_barrier () {} /* nothing */
^
In file included from /tmp/ghc7100_0/ghc_23.hc:3:0:
/tmp/ghc7100_0/ghc_23.hc:2778:5:
error: conflicting types for ‘write_barrier’
EF_(write_barrier);
^
/usr/local/lib/ghc-7.10.3/include/Stg.h:220:36:
note: in definition of macro ‘EF_’
#define EF_(f) extern StgFunPtr f() /* See Note [External function prototypes] */
^
In file included from /usr/local/lib/ghc-7.10.3/include/Stg.h:274:0:
0,
from /tmp/ghc7100_0/ghc_23.hc:3:
/usr/local/lib/ghc-7.10.3/include/stg/SMP.h:421:20:
note: previous definition of ‘write_barrier’ was here
EXTERN_INLINE void write_barrier () {} /* nothing */
^
I'm updating all my packages for ghc 8-rc1 support, and am stuck on all of them that depend on atomic-primops
. This seems likely to just be a bump and push.
The casArrayElem
provide a low-level atomic operations based on Ticket
, Is there any possibilities to provide a loop wrapper similar to atomicModifyIORef
? As an user i only care about swapping a new result into array and get the old value out rather than manually compare pointer and looping.
Data.Atomics has writeBarrier
(store-store), storeLoadBarrier
, and loadLoadBarrier
, but seems to be missing a load-store barrier. This would be a no-op at the hardware level on x86, but it would still need to prevent compiler reordering, like writeBarrier
and loadLoadBarrier
.
(I know enough about memory models to be aware that my understanding could be completely wrong—please correct me if so.)
This was a bug up until version 0.5. Fortunately, there was no reason to use the reference implementation!
I've spotted this commit that suggests the Any
type should not cause issues with GHC-7.4. However, at least on Linux, the following is me trying with 7.4 and failing, then 7.6 and succeeding:
$ export PATH=~/sw/ghc/7.4.1/x86_64/bin:$PATH
bash-4.1$ cabal clean
cleaning...
Error while removing dist/: dist/setup: removeDirectory: unsatisified constraints (Directory not empty)
bash-4.1$ cabal install
Resolving dependencies...
[1 of 1] Compiling Main ( Setup.hs, dist/setup/Main.o )
Linking ./dist/setup/setup ...
Configuring atomic-primops-0.2.2.1...
Building atomic-primops-0.2.2.1...
Preprocessing library atomic-primops-0.2.2.1...
[1 of 6] Compiling Data.Atomics.Counter.Foreign ( Data/Atomics/Counter/Foreign.hs, dist/build/Data/Atomics/Counter/Foreign.o )
[2 of 6] Compiling Data.Atomics.Counter.Reference ( Data/Atomics/Counter/Reference.hs, dist/build/Data/Atomics/Counter/Reference.o )
[3 of 6] Compiling Data.Atomics.Internal ( Data/Atomics/Internal.hs, dist/build/Data/Atomics/Internal.o )
Data/Atomics/Internal.hs:115:1:
Unacceptable argument type in foreign declaration: Any (* -> *) ()
When checking declaration:
foreign import prim safe "static stg_casArrayzh" casArrayTypeErased#
:: MutableArray# RealWorld ()
-> Int#
-> Any ()
-> Any ()
-> State# RealWorld -> (# State# RealWorld, Int#, Any () #)
Data/Atomics/Internal.hs:115:1:
Unacceptable argument type in foreign declaration: Any (* -> *) ()
When checking declaration:
foreign import prim safe "static stg_casArrayzh" casArrayTypeErased#
:: MutableArray# RealWorld ()
-> Int#
-> Any ()
-> Any ()
-> State# RealWorld -> (# State# RealWorld, Int#, Any () #)
Data/Atomics/Internal.hs:123:1:
Unacceptable argument type in foreign declaration: Any (* -> *) ()
When checking declaration:
foreign import prim safe "static stg_casMutVar2zh" casMutVar_TypeErased#
:: MutVar# RealWorld ()
-> Any ()
-> Any ()
-> State# RealWorld -> (# State# RealWorld, Int#, Any () #)
Data/Atomics/Internal.hs:123:1:
Unacceptable argument type in foreign declaration: Any (* -> *) ()
When checking declaration:
foreign import prim safe "static stg_casMutVar2zh" casMutVar_TypeErased#
:: MutVar# RealWorld ()
-> Any ()
-> Any ()
-> State# RealWorld -> (# State# RealWorld, Int#, Any () #)
cabal: Error: some packages failed to install:
atomic-primops-0.2.2.1 failed during the building phase. The exception was:
ExitFailure 1
$ export PATH=~/sw/ghc/ghc-7.6.3-BUILD/bin:$PATH
bash-4.1$ cabal clean
cleaning...
Error while removing dist/: dist/setup: removeDirectory: unsatisified constraints (Directory not empty)
bash-4.1$ cabal install
Resolving dependencies...
[1 of 1] Compiling Main ( /tmp/bits-atomic-0.1.3-19929/bits-atomic-0.1.3/Setup.hs, /tmp/bits-atomic-0.1.3-19929/bits-atomic-0.1.3/dist/setup/Main.o )
/tmp/bits-atomic-0.1.3-19929/bits-atomic-0.1.3/Setup.hs:15:35: Warning:
In the use of `runTests'
(imported from Distribution.Simple, but defined in Distribution.Simple.UserHooks):
Deprecated: "Please use the new testing interface instead!"
Linking /tmp/bits-atomic-0.1.3-19929/bits-atomic-0.1.3/dist/setup/setup ...
Configuring bits-atomic-0.1.3...
Building bits-atomic-0.1.3...
Preprocessing library bits-atomic-0.1.3...
[1 of 1] Compiling Data.Bits.Atomic ( Data/Bits/Atomic.hs, dist/build/Data/Bits/Atomic.o )
cbits/atomic-bitops-gcc.c: In function ‘nand_and_fetch_word’:
cbits/atomic-bitops-gcc.c:260:0:
note: ‘__sync_nand_and_fetch’ changed semantics in GCC 4.4
cbits/atomic-bitops-gcc.c: In function ‘fetch_and_nand_word’:
cbits/atomic-bitops-gcc.c:242:0:
note: ‘__sync_fetch_and_nand’ changed semantics in GCC 4.4
In-place registering bits-atomic-0.1.3...
Installing library in ~/.cabal/lib/bits-atomic-0.1.3/ghc-7.6.3
Registering bits-atomic-0.1.3...
[1 of 1] Compiling Main ( Setup.hs, dist/setup/Main.o )
Linking ./dist/setup/setup ...
Configuring atomic-primops-0.2.2.1...
Building atomic-primops-0.2.2.1...
Preprocessing library atomic-primops-0.2.2.1...
[1 of 6] Compiling Data.Atomics.Counter.Foreign ( Data/Atomics/Counter/Foreign.hs, dist/build/Data/Atomics/Counter/Foreign.o )
[2 of 6] Compiling Data.Atomics.Counter.Reference ( Data/Atomics/Counter/Reference.hs, dist/build/Data/Atomics/Counter/Reference.o )
[3 of 6] Compiling Data.Atomics.Internal ( Data/Atomics/Internal.hs, dist/build/Data/Atomics/Internal.o )
[4 of 6] Compiling Data.Atomics ( Data/Atomics.hs, dist/build/Data/Atomics.o )
[5 of 6] Compiling Data.Atomics.Counter.IORef ( Data/Atomics/Counter/IORef.hs, dist/build/Data/Atomics/Counter/IORef.o )
[6 of 6] Compiling Data.Atomics.Counter ( Data/Atomics/Counter.hs, dist/build/Data/Atomics/Counter.o )
In-place registering atomic-primops-0.2.2.1...
Installing library in ~/.cabal/lib/atomic-primops-0.2.2.1/ghc-7.6.3
Registering atomic-primops-0.2.2.1...
When doing a cabal install
on yesod-core
the following error is thrown when linking atomic-primops
:
$ cabal install -j
Resolving dependencies...
Notice: installing into a sandbox located at
X:\Projects\yesod\yesod-core\.cabal-sandbox
Configuring ansi-terminal-0.6.1.1...
Configuring auto-update-0.1.1.4...
Configuring atomic-primops-0.6.0.6...
Configuring byteable-0.1.1...
Configuring byteorder-1.0.4...
Configuring base64-bytestring-1.0.0.1...
Configuring blaze-builder-0.3.3.4...
Configuring cereal-0.4.0.1...
Building auto-update-0.1.1.4...
Building byteorder-1.0.4...
Building byteable-0.1.1...
Building blaze-builder-0.3.3.4...
Building ansi-terminal-0.6.1.1...
Building cereal-0.4.0.1...
Building base64-bytestring-1.0.0.1...
Installed byteable-0.1.1
Configuring data-default-class-0.0.1...
Building atomic-primops-0.6.0.6...
Configuring dlist-0.7.1...
Installed auto-update-0.1.1.4
Building data-default-class-0.0.1...
Installed byteorder-1.0.4
Configuring easy-file-0.2.0...
Building dlist-0.7.1...
Configuring entropy-0.3.3...
Installed base64-bytestring-1.0.0.1
Building easy-file-0.2.0...
Configuring exceptions-0.6.1...
Installed atomic-primops-0.6.0.6
Configuring mmorph-1.0.4...
Installed data-default-class-0.0.1
Building exceptions-0.6.1...
Configuring monad-loops-0.4.2.1...
Installed ansi-terminal-0.6.1.1
Building mmorph-1.0.4...
Building entropy-0.3.3...
Configuring nats-0.2...
Installed blaze-builder-0.3.3.4
Building monad-loops-0.4.2.1...
Configuring path-pieces-0.1.4...
Installed dlist-0.7.1
Building nats-0.2...
Configuring safe-0.3.8...
Installed easy-file-0.2.0
Building path-pieces-0.1.4...
Configuring scientific-0.2.0.2...
Installed cereal-0.4.0.1
Building safe-0.3.8...
Configuring setenv-0.1.1.1...
Installed exceptions-0.6.1
Building scientific-0.2.0.2...
Configuring stm-chans-3.0.0.2...
Installed mmorph-1.0.4
Building setenv-0.1.1.1...
Configuring stringsearch-0.3.6.5...
Installed entropy-0.3.3
Configuring system-filepath-0.4.12...
Installed monad-loops-0.4.2.1
Building stringsearch-0.3.6.5...
Configuring tagged-0.7.2...
Installed nats-0.2
Building stm-chans-3.0.0.2...
Configuring transformers-base-0.4.3...
Installed path-pieces-0.1.4
Building tagged-0.7.2...
Configuring unix-compat-0.4.1.3...
Installed safe-0.3.8
Building system-filepath-0.4.12...
Building transformers-base-0.4.3...
Configuring vault-0.3.0.3...
Installed setenv-0.1.1.1
Building unix-compat-0.4.1.3...
Configuring word8-0.1.1...
Installed scientific-0.2.0.2
Building vault-0.3.0.3...
Configuring securemem-0.1.3...
Installed stm-chans-3.0.0.2
Building word8-0.1.1...
Installed tagged-0.7.2
Configuring data-default-instances-base-0.0.1...
Building securemem-0.1.3...
Installed transformers-base-0.4.3
Configuring data-default-instances-containers-0.0.1...
Building data-default-instances-base-0.0.1...
Configuring data-default-instances-old-locale-0.0.1...
Installed word8-0.1.1
Building data-default-instances-containers-0.0.1...
Configuring blaze-markup-0.6.1.1...
Installed stringsearch-0.3.6.5
Building data-default-instances-old-locale-0.0.1...
Configuring fast-logger-2.2.0...
Installed vault-0.3.0.3
Building blaze-markup-0.6.1.1...
Configuring http-types-0.8.5...
Installed securemem-0.1.3
Building fast-logger-2.2.0...
Configuring streaming-commons-0.1.5...
Installed data-default-instances-base-0.0.1
Building http-types-0.8.5...
Configuring data-default-instances-dlist-0.0.1...
Installed unix-compat-0.4.1.3
Building streaming-commons-0.1.5...
Configuring semigroups-0.15.3...
Installed data-default-instances-containers-0.0.1
Building data-default-instances-dlist-0.0.1...
Configuring aeson-0.7.0.4...
Installed data-default-instances-old-locale-0.0.1
Building semigroups-0.15.3...
Configuring crypto-api-0.13.2...
Installed fast-logger-2.2.0
Building aeson-0.7.0.4...
Installed blaze-markup-0.6.1.1
Configuring monad-control-0.3.3.0...
Building crypto-api-0.13.2...
Configuring crypto-cipher-types-0.0.9...
Installed data-default-instances-dlist-0.0.1
Building monad-control-0.3.3.0...
Installed http-types-0.8.5
Configuring crypto-random-0.0.8...
Building crypto-cipher-types-0.0.9...
Building crypto-random-0.0.8...
Installed monad-control-0.3.3.0
Configuring blaze-html-0.7.0.3...
Configuring data-default-0.5.3...
Installed streaming-commons-0.1.5
Building blaze-html-0.7.0.3...
Installed crypto-cipher-types-0.0.9
Configuring wai-3.0.2...
Building data-default-0.5.3...
Installed semigroups-0.15.3
Configuring lifted-base-0.2.3.0...
Building wai-3.0.2...
Installed crypto-random-0.0.8
Configuring cipher-aes-0.2.8...
Building lifted-base-0.2.3.0...
Configuring void-0.6.1...
Installed crypto-api-0.13.2
Building cipher-aes-0.2.8...
Installed system-filepath-0.4.12
Configuring skein-1.0.9...
Building void-0.6.1...
Configuring system-fileio-0.3.14...
Installed data-default-0.5.3
Building skein-1.0.9...
Installed wai-3.0.2
Configuring cookie-0.4.1.4...
Building system-fileio-0.3.14...
Configuring wai-logger-2.2.3...
Installed lifted-base-0.2.3.0
Building cookie-0.4.1.4...
Configuring resourcet-1.1.2.3...
Installed void-0.6.1
Building wai-logger-2.2.3...
Installed cipher-aes-0.2.8
Configuring cprng-aes-0.5.2...
Building resourcet-1.1.2.3...
Installed system-fileio-0.3.14
Building cprng-aes-0.5.2...
Installed skein-1.0.9
Installed cookie-0.4.1.4
Installed wai-logger-2.2.3
Installed blaze-html-0.7.0.3
Installed cprng-aes-0.5.2
Configuring clientsession-0.9.1...
Installed resourcet-1.1.2.3
Configuring conduit-1.2.1...
Configuring wai-extra-3.0.2.1...
Building clientsession-0.9.1...
Installed aeson-0.7.0.4
Configuring shakespeare-2.0.1.1...
Building conduit-1.2.1...
Building wai-extra-3.0.2.1...
Building shakespeare-2.0.1.1...
Installed clientsession-0.9.1
Installed conduit-1.2.1
Configuring conduit-extra-1.1.4...
Installed wai-extra-3.0.2.1
Building conduit-extra-1.1.4...
Installed conduit-extra-1.1.4
Configuring monad-logger-0.3.7.2...
Configuring simple-sendfile-0.2.18...
Building simple-sendfile-0.2.18...
Building monad-logger-0.3.7.2...
Installed simple-sendfile-0.2.18
Configuring warp-3.0.2.2...
Installed monad-logger-0.3.7.2
Building warp-3.0.2.2...
Installed shakespeare-2.0.1.1
Installed warp-3.0.2.2
Configuring yesod-core-1.4.1.1...
Building yesod-core-1.4.1.1...
Failed to install yesod-core-1.4.1.1
Build log ( X:\Projects\yesod\yesod-core\.cabal-sandbox\logs\yesod-core-1.4.1.1.log ):
Building yesod-core-1.4.1.1...
Preprocessing library yesod-core-1.4.1.1...
[ 1 of 30] Compiling Yesod.Routes.TH.Types ( Yesod\Routes\TH\Types.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH\Types.o )
[ 2 of 30] Compiling Yesod.Routes.TH.Dispatch ( Yesod\Routes\TH\Dispatch.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH\Dispatch.o )
[ 3 of 30] Compiling Yesod.Routes.Overlap ( Yesod\Routes\Overlap.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\Overlap.o )
[ 4 of 30] Compiling Yesod.Core.TypeCache ( Yesod\Core\TypeCache.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\TypeCache.o )
[ 5 of 30] Compiling Yesod.Routes.Class ( Yesod\Routes\Class.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\Class.o )
[ 6 of 30] Compiling Yesod.Routes.TH.RenderRoute ( Yesod\Routes\TH\RenderRoute.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH\RenderRoute.o )
[ 7 of 30] Compiling Yesod.Routes.TH.ParseRoute ( Yesod\Routes\TH\ParseRoute.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH\ParseRoute.o )
[ 8 of 30] Compiling Yesod.Routes.TH.RouteAttrs ( Yesod\Routes\TH\RouteAttrs.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH\RouteAttrs.o )
[ 9 of 30] Compiling Yesod.Routes.TH ( Yesod\Routes\TH.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\TH.o )
[10 of 30] Compiling Yesod.Routes.Parse ( Yesod\Routes\Parse.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Routes\Parse.o )
[11 of 30] Compiling Paths_yesod_core ( dist\dist-sandbox-ea28e1ab\build\autogen\Paths_yesod_core.hs, dist\dist-sandbox-ea28e1ab\build\Paths_yesod_core.o )
[12 of 30] Compiling Yesod.Core.Internal.Util ( Yesod\Core\Internal\Util.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Internal\Util.o )
[13 of 30] Compiling Yesod.Core.Types ( Yesod\Core\Types.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Types.o )
[14 of 30] Compiling Yesod.Core.Class.Handler ( Yesod\Core\Class\Handler.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Class\Handler.o )
[15 of 30] Compiling Yesod.Core.Internal.Request ( Yesod\Core\Internal\Request.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Internal\Request.o )
[16 of 30] Compiling Yesod.Core.Internal.Session ( Yesod\Core\Internal\Session.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Internal\Session.o )
[17 of 30] Compiling Yesod.Core.Content ( Yesod\Core\Content.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Content.o )
[18 of 30] Compiling Yesod.Core.Handler ( Yesod\Core\Handler.hs, dist\dist-sandbox-ea28e1ab\build\Yesod\Core\Handler.o )
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package array-0.5.0.0 ... linking ... done.
Loading package primitive-0.5.2.1 ... linking ... done.
Loading package atomic-primops-0.6.0.6 ... linking ... ghc.exe: unable to load package `atomic-primops-0.6.0.6'
ghc.exe: X:\Projects\yesod\yesod-core\.cabal-sandbox\x86_64-windows-ghc-7.8.3\atomic-primops-0.6.0.6\HSatomic-primops-0.6.0.6.o: unknown symbol `store_load_barrier'
cabal.exe: Error: some packages failed to install:
yesod-core-1.4.1.1 failed during the building phase. The exception was:
ExitFailure 1
Version: atomic-primops-0.6.0.6, yesod-core 1.4.1.1
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.8.3
$ cabal --version
cabal-install version 1.20.0.3
using version 1.20.0.2 of the Cabal library
Operating system: Windows 8.1
As mentioned in #40, this was one of the two tests that failed under GHC 7.10. It needs to be investigated.
Currently, cf85070, it needs a big stack size bump to pass its tests.
Building a large number of configs in the matrix build seems to reveal random spurious failures. Wiping workspaces completely each time may help.
Here is a sampling of failures:
Relevant log excerpts:
Final sum: 4999950000, producer/consumer/leftover sums: ([(98076,4949033504)],[(1924,50916496)],[(0,0)])
test-abstract-deque: internal error: setNumCapabilities: reducing the number of Capabilities is not currently supported.
(GHC version 7.4.2 for x86_64_unknown_linux)
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
This is affecting my 7.4.2 Stackage run. If this is not something you intend on resolving, I'll add abstract-deque to the expected failures list, please let me know what you'd prefer.
For implementing work stealing on networks of machines, a common technique is to use minimum watermarks. That is, on receiving a message from another PE to ask for work, the scheduler may want to know if it has a minimum number of sparks before they give some away.
The current ChaseLev implementation does not allow a scheduler to inspect the number of elements (sparks in this case). It might look like:
lengthQ :: ChaseLevDeque a -> IO Int
What are the costs of adding this function? Would it be lock-free?
The cited paper does report a size()
method for the CircularArray class.
It seems it never got added?
We need base
4.8 If we manually ignore the base constraint, we get:
jberryman /tmp/atomic-primops-0.6.1 » cabal install --only-dependencies -w /usr/local/bin/ghc-7.10.0.20141222 --allow-newer 1 ↵
Resolving dependencies...
Notice: installing into a sandbox located at
/tmp/atomic-primops-0.6.1/.cabal-sandbox
Configuring primitive-0.5.4.0...
Failed to install primitive-0.5.4.0
Build log ( /tmp/atomic-primops-0.6.1/.cabal-sandbox/logs/primitive-0.5.4.0.log ):
unrecognized 'configure' option `--disable-executable-profiling'
cabal: Error: some packages failed to install:
primitive-0.5.4.0 failed during the configure step. The exception was:
ExitFailure 1
I have no idea where the hell that --disable-executable-profiling
is coming from or why it's unrecognized.
chaselev-deque-0.5.0.3 doesn't seem to compile with GHC 7.8.4 on Linux/x86_64: http://hydra.cryp.to/build/467361/nixlog/1/raw.
The log from this run can be found here.
The error was:
Final sum: 4999950000, producer/consumer/leftover sums: ([(43142,3221214597)],[(56427,1739950903)],[(431,38784500)])
test-chaselev-deque: internal error: wakeup_gc_threads
(GHC version 7.6.3 for x86_64_unknown_linux)
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
Test suite test-chaselev-deque: FAIL
In particular, with respect to clarifying the issues #18 and #20. For example, the docs here don't fully cover it:
http://hackage.haskell.org/package/atomic-primops-0.5/docs/Data-Atomics.html
I played with a branch jberryman/haskell-lockfree@23497b4 that implements the atomic counter with a padding of 64bytes on either side, so that it always sits in its own cache line (at least hopefully on x86, where AtomicCounter
is most useful anyway).
In criterion benchmarks of a counter-based queue I'm working on I get a 17 - 23% improvement in runtime on those benchmarks where we start to use the heap (maxing out at 1,000,000 Int
s and 1,000 arrays of size 1,000... whatever that amounts to).
I modified the test slightly to run with perf, and some of the cache metrics do appear to be better (but others a bit worse, maybe that's just expected variance).
Here's the slow version with current counter:
Performance counter stats for './multi_cache_slow' (100 runs):
401.063542 task-clock (msec) # 3.745 CPUs utilized ( +- 0.64% )
300 context-switches # 0.747 K/sec ( +- 27.94% )
20 cpu-migrations # 0.049 K/sec ( +- 1.70% )
2,999 page-faults # 0.007 M/sec ( +- 0.01% )
726,617,399 cycles # 1.812 GHz ( +- 1.11% ) [24.21%]
623,872,915 stalled-cycles-frontend # 85.86% frontend cycles idle ( +- 0.94% ) [28.13%]
427,867,935 instructions # 0.59 insns per cycle
# 1.46 stalled cycles per insn ( +- 1.83% ) [37.28%]
268,108 cache-misses # 5.209 % of all cache refs ( +- 0.99% ) [40.43%]
5,146,579 cache-references # 12.832 M/sec ( +- 1.08% ) [43.64%]
5,616,736 L1-dcache-load-misses # 14.005 M/sec ( +- 1.07% ) [43.16%]
497,307 L1-dcache-store-misses # 1.240 M/sec ( +- 1.03% ) [40.69%]
1,470,803 L1-dcache-prefetch-misses # 3.667 M/sec ( +- 2.46% ) [29.46%]
102,164 L1-icache-load-misses # 0.255 M/sec ( +- 1.71% ) [27.00%]
1,939,392 LLC-loads # 4.836 M/sec ( +- 1.74% ) [24.80%]
2,696,163 LLC-stores # 6.723 M/sec ( +- 1.81% ) [23.33%]
6,026,990 LLC-prefetches # 15.028 M/sec ( +- 2.52% ) [10.68%]
12,353 iTLB-loads # 0.031 M/sec ( +- 10.40% ) [25.89%]
9,746 iTLB-load-misses # 78.89% of all iTLB cache hits ( +- 2.94% ) [25.01%]
88,551,617 branch-loads # 220.792 M/sec ( +- 2.43% ) [23.60%]
89,617 branch-load-misses # 0.223 M/sec ( +- 6.05% ) [22.22%]
0.107099418 seconds time elapsed ( +- 0.72% )
And fast version:
Performance counter stats for './multi_cache_fast' (100 runs):
333.044322 task-clock (msec) # 3.701 CPUs utilized ( +- 0.81% )
221 context-switches # 0.663 K/sec ( +- 16.25% )
20 cpu-migrations # 0.059 K/sec ( +- 1.70% )
2,999 page-faults # 0.009 M/sec ( +- 0.02% )
748,219,452 cycles # 2.247 GHz ( +- 0.96% ) [23.82%]
634,355,295 stalled-cycles-frontend # 84.78% frontend cycles idle ( +- 1.08% ) [27.57%]
471,072,726 instructions # 0.63 insns per cycle
# 1.35 stalled cycles per insn ( +- 1.15% ) [35.37%]
301,361 cache-misses # 6.418 % of all cache refs ( +- 1.59% ) [37.17%]
* 4,695,679 cache-references # 14.099 M/sec ( +- 1.19% ) [38.81%]
* 4,828,687 L1-dcache-load-misses # 14.499 M/sec ( +- 1.38% ) [37.72%]
654,043 L1-dcache-store-misses # 1.964 M/sec ( +- 1.89% ) [35.95%]
* 592,677 L1-dcache-prefetch-misses # 1.780 M/sec ( +- 2.59% ) [29.03%]
* 66,387 L1-icache-load-misses # 0.199 M/sec ( +- 3.89% ) [34.49%]
* 573,885 LLC-loads # 1.723 M/sec ( +- 4.69% ) [34.30%]
* 1,865,970 LLC-stores # 5.603 M/sec ( +- 2.98% ) [32.93%]
4,460,103 LLC-prefetches # 13.392 M/sec ( +- 1.99% ) [15.90%]
16,509 iTLB-loads # 0.050 M/sec ( +- 9.41% ) [27.67%]
* 7,565 iTLB-load-misses # 45.82% of all iTLB cache hits ( +- 1.98% ) [25.46%]
97,310,210 branch-loads # 292.184 M/sec ( +- 2.42% ) [23.51%]
* 74,815 branch-load-misses # 0.225 M/sec ( +- 7.71% ) [21.80%]
0.089992717 seconds time elapsed ( +- 0.91% )
I also have a version that uses a pinned, aligned MutableByteArray
and has the same benefits at just 64 bytes, but I think that would be a mistake and could contribute to memory fragmentation.
If my benchmarks aren't deceiving me I think this change would probably be worth the wasted 127 bytes for most uses of the AtomicCounter
that I can think of. Any interest in this sort of change? If not, it's no trouble for me to create my own fat counter.
This was another API discrepancy between the different versions of the counter.
It's not totally clear which behavior we should standardize on here. The real implementation that you actually want to use is Unboxed. The others are there mostly for testing and benchmarking. For Unboxed, there's really no reason to have a CTicket
type in the first place.
It would be unfortunate, therefore, to lose performance in the Unboxed casCounter
, just to accommodate the implementation constraints of the other versions.
Precedent doesn't help very much because the precedent from the boxed CAS operations (IORef, Array) is to use the return-new-as-ticket interface, whereas for the unboxed ByteArray CAS, it's the usual "return-read-value" interface.
We've done this switch for LVish and should do it here too.
Do storeLoadBarrier and friends have the same compiler reordering guarantees described for the atomic operations in issue 39 (#39)? From what I've read it seems like "foreign import prim" prevents compiler reordering during C-- optimizations, but I have no idea whether "foreign import ccall" also does. Thanks!
I'm experiencing a linking error, with ghc failing to find the cas
symbol.
Prelude> :m Data.Atomics
Prelude Data.Atomics> writeBarrier
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package containers-0.5.0.0 ... linking ... done.
Loading package filepath-1.3.0.1 ... linking ... done.
Loading package old-locale-1.0.0.5 ... linking ... done.
Loading package time-1.4.0.1 ... linking ... done.
Loading package bytestring-0.10.0.2 ... linking ... done.
Loading package unix-2.6.0.1 ... linking ... done.
Loading package directory-1.2.0.1 ... linking ... done.
Loading package old-time-1.1.0.1 ... linking ... done.
Loading package pretty-1.1.1.0 ... linking ... done.
Loading package process-1.1.0.2 ... linking ... done.
Loading package Cabal-1.16.0 ... linking ... done.
Loading package bits-atomic-0.1.3 ... linking ... done.
Loading package primitive-0.5.0.1 ... linking ... done.
Loading package atomic-primops-0.2.2 ... linking ... <interactive>: $HOME/.cabal/lib/atomic-primops-0.2.2/ghc-7.6.3/HSatomic-primops-0.2.2.o: unknown symbol `cas'
Having read this , I see that the cas
symbol is defined on my Linux machine in $HOME/sw/ghc/ghc-7.6.3-BUILD/lib/ghc-7.6.3/include/stg/SMP.h
. I've tried (to no avail) the --extra-include-dirs
flag when compiling programs that uses Data.Atomic
, which throws the same error. This is a ghc that I use on a regular basis for other business. How should I resolve this unknown symbol error?
Here is a standalone test
It can be reproduced with something like this:
GHC=ghc-7.6.3
cd ChaseLev
cabal-1.17.0_HEAD install --disable-executable-profiling --disable-library-profiling --disable-documentation --force-reinstalls ../AbstractDeque/ --with-ghc=$GHC
cabal-1.17.0_HEAD install --disable-executable-profiling --disable-library-profiling --disable-documentation --force-reinstalls ../AtomicPrimops/ --with-ghc=$GHC
$GHC -O2 --make RegressionTests/Issue5.hs -o Issue5.exe -main-is RegressionTests.Issue5.standalone_single_CAS
./Issue5.exe
The -O2 is required to make it fail (notice that --threaded
is not). That's a big hint. (In fact, -O1 fails too.)
Most of our failures are jenkins/cabal problems. But the 7.6.3/profiling/-O0/threads build in the matrix here is a genuine test failure:
test_all_hammer_one_1_500000:: [Failed]
Runs [500000] (GCs 0), had enough successes?: [499999] >= 500000
111111111111111111111111111111111111111111111111111111111111111111111111111111...
GHC 7.10 includes several new primops. You can see which by comparing these two interfaces:
Each one of these needs to be exposed in and end-user friendly way in the IO monad, and tested accordingly. @tibbe, do you have any interest in helping expose these?
I figure while we are making breaking changes to handle #41 and #42, that we should make these additions an the same time, and make one new major release to be timed with the official GHC 7.10 release -- it will be the greatest GHC yet for lock-free concurrency!
Johan (@tibbe) pointed out something I didn't know, "MutableByteArray#" can be sent through the FFI. Thus it should be possible to move the logic we have in Cmm code into C code, and avoid a DOUBLE function call overhead.
Because the GHC 7.8 primops have this double funcall overhead, they may end up as useless from the perspective of this package. The hope was to at last avoid the fragility of foreign primops by including them in GHC. Still, that problem is eliminated just as well by eliminating the Cmm itself.
jberryman /tmp » cabal install atomic-primops
Resolving dependencies...
Configuring primitive-0.5.2.1...
Building primitive-0.5.2.1...
Installed primitive-0.5.2.1
Configuring atomic-primops-0.6...
Building atomic-primops-0.6...
Installed atomic-primops-0.6
jberryman /tmp » ghci
GHCi, version 7.8.20140130: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> import Data.Atomics
Prelude Data.Atomics> import Data.IORef
Prelude Data.Atomics Data.IORef> r <- newIORef 'a'
Prelude Data.Atomics Data.IORef> t <- readForCAS r
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package bytestring-0.10.4.0 ... linking ... done.
Loading package containers-0.5.4.0 ... linking ... done.
Loading package filepath-1.3.0.2 ... linking ... done.
Loading package old-locale-1.0.0.6 ... linking ... done.
Loading package time-1.4.1 ... linking ... done.
Loading package unix-2.7.0.0 ... linking ... done.
Loading package directory-1.2.0.2 ... linking ... done.
Loading package pretty-1.1.1.1 ... linking ... done.
Loading package process-1.2.0.0 ... linking ... done.
Loading package Cabal-1.18.1.3 ... linking ... done.
Loading package primitive-0.5.2.1 ... linking ... done.
Loading package atomic-primops-0.6 ... linking ... done.
Prelude Data.Atomics Data.IORef> (b,t') <- casIORef r t 'b'
Prelude Data.Atomics Data.IORef> b
False
Prelude Data.Atomics Data.IORef> peekTicket t'
'a'
I tried the same in 7.6.3 but get a linker error (I think that's documented). And when I load code (using cabal repl
in my project) that uses casIORef
internally I'm seeing this same behavior, but intermittently; very strange.
I haven't yet checked correct behavior in compiled code.
Finally, a question: barring bugs, is it safe in my code to reason that if a casIORef
returns False
that another thread has beat us with a write? Or can casIORef
be expected to fail nondeterministically?
It's not just an optimization, but rather is needed for correctness.
Ok, it looks like maybe this is an intentional change in behavior for fetchAddIntArray#
, @tibbe?
Following some precedent or existing code (I forgot which!), I'd made the original version return the AFTER value not the BEFORE value. Thus the code for incrCounter was:
{-# INLINE incrCounter #-}
-- | Increment the counter by a given amount. Returns the value AFTER the increment
-- (in contrast with the behavior of the underlying instruction on architectures
-- like x86.)
--
-- Note that UNLIKE with boxed implementations of counters, where increment is
-- based on CAS, this increment is /O(1)/. Fetch-and-add does not require a retry
-- loop like CAS.
incrCounter :: Int -> AtomicCounter -> IO Int
incrCounter (I# incr#) (AtomicCounter mba#) = IO $ \ s1# ->
let (# s2#, res #) = fetchAddIntArray# mba# 0# incr# s1# in
(# s2#, (I# res) #)
It looks like the 7.10+ version of fetchAddIntArray# returns the BEFORE value. GCC provides both, fetch_and_add
and add_and_fetch
. It's true that the primop we export matches the name of the former more closely, and it thus is fine for it to have that behavior.
Uh... it looks like we need another ifdef, eh, to support this change? Oh well, that's the goal of the atomic-primops package. To abstract over these varying levels of support in different GHC versions.
But I do think we should go ahead and bump the major version and change the interface for this Counter lib to return the BEFORE value (and support that behavior across the last 3 GHC versions), what do you think?
E.g.:
These tests do a bunch of fork-join rounds. Maybe there's some way we should be waiting for OS threads to be GC'd before moving on to the next fork-join round?
This might be related to #24
Either too low or too high. This has been the main bug that I've been investigating in the DEVLOG.
I was hopeful that it would have the same underlying cause as Issue #5, but it is closed and this bug remains. As mentioned in the DEVLOG, running this enough times will trigger it:
NUMELEMS=1000000 NOWRAPPER=1 NUMTHREADS=4 ./dist/build/test-chaselev-deque/test-chaselev-deque -t random_work_steal
An example revision where this fails is: 8050a58
It would be nice to know whether or not casIORef
, fetchAddByteArray
, etc. represent memory barriers, or not, at the compiler level. In other words, may GHC reorder stores or loads across these operations, regardless of whether the underlying primop is a barrier on a particular architecture? Or like atomicModifyIORef
do they guarantee some ordering?
There's mention of how the read operations don't imply any barriers, which suggests that maybe the atomic ops do. If this isn't defined in GHC then it would be nice to clarify that there, obviously. Thanks!
Libraries or programs that use Template Haskell will not be able to use the atomic-primops library. The root cause is a combination of two things. First, need to use -threaded
for code that ultimately uses atomic-primops, as described in this issue. Second, Template Haskell runs at compile time, via a bytecode interpreter, GHCi. This does not invoke -threaded
, so the error is thrown, once GHCI attempts to load packages:
Loading package atomic-primops-0.2.2.1 ... linking ... ghc: ~/.cabal/lib/atomic-primops-0.2.2.1/ghc-7.6.1/HSatomic-primops-0.2.2.1.o: unknown symbol `cas'
As a simply example, try compiling this demo library I put together: chaselev-user-libX-0.0.1.tar.gz. The case is straight forward: if you comment out remotable
on line 17 of Foo.Bar
, the library compiles. If you leave it in, the library does not compile.
Does the library (not the included test suite) need to depend on test-framework? Right now test-framework doesn't build so neither does abstract-deque-0.2.2 and a few dependencies later criterion (which I need right now) doesn't build.
Aside: could you add a
bug-reports: https://github.com/rrnewton/haskell-lockfree/issues
section to the .cabal file so it's easier to find this page.
How can we construct a test for this?
They use the strategy of comparing against the "old" value to see if the CAS succeeded. Alas, this doesn't work. You have to actually read the zero flag with sete
, which is what __sync_bool_compare_and_swap
does.
For example if 100 threads attempt to change a counter from 0 to 1, only one can succeed, but with the current version more than one may think they succeeded.
This is ultimately the cause of Issue 70 in the lvars repo:
iu-parfunc/lvars#70
This is going to require significant changes to fix.
HVR and Brent Yorgey have some neat tooling to auto run test suites on several GHC versions, I think this should be adapted to this set of libs (though the fact that they're all in the same repo complicates the scripting I think...)
test-atomic-primops
(TODO)
For example, this with --run-tests
on a profiling build in either cabal 1.20 or 1.22:
Loading package atomic-primops-0.8 ... linking ... done.
ghci-test.hs:18:16:
cannot find normal object file ‘dist/dist-sandbox-a2a4e32d/build/template-haskell-atomic-primops/template-haskell-atomic-primops-tmp/TemplateHaskellSplices.dyn_o’
Vs this with a discrete cabal-1.20 test
:
++ cabal-1.20 test --show-details=always
cabal-1.20: dist/setup-config: invalid argument
On 1.22.3.0, I'm seeing it complain about lack of configure when it just ran configure. And somehow it thinks the version of GHC has changed, when it should pick it up from the configure.
++ cabal-1.22 configure --with-ghc=ghc-7.6.3 --enable-tests -O0 --disable-library-profiling --disable-profiling --disable-coverage -fthreaded --ghc-options=-threaded
Resolving dependencies...
[1 of 1] Compiling Main ( dist/setup/setup.hs, dist/setup/Main.o )
Linking ./dist/setup/setup ...
Configuring atomic-primops-0.8...
++ cabal-1.22 test --show-details=streaming
cabal-1.22: You need to re-run the 'configure' command. The version of Cabal being used has changed (was Cabal-1.20.0.2, now Cabal-1.22.3.0). Additionally the compiler is different (was ghc-7.6, now ghc-7.8) which is probably the cause of the problem.
But specifying the GHC version to cabal test
doesn't help either:
Configuring atomic-primops-0.8...
++ cabal-1.22 test --with-ghc=ghc-7.6.3 --show-details=streaming
cabal-1.22: You need to re-run the 'configure' command. The version of Cabal being used has changed (was Cabal-1.20.0.2, now Cabal-1.22.3.0). Additionally the compiler is different (was ghc-7.6, now ghc-7.8) which is probably the cause of the problem.
But even if I remove all uses of --with-ghc
, I still get the exact same error message above.
After tweaking it a few times I get the same missing ".dyn_o" failure on ghci-test.hs above when using a discrete cabal configure / cabal test
per package. It's possible that now in cabal 1.20+, recombining test-atomic-primops
into the atomic-primops
library could work around this bug....
Any chance of getting chaselev-deque on stackage? It's a dependency of accelerate-llvm.
Multi-item CAS or CASN is the basis for some interesting concurrent data structures. It would be nice if atomic-primops
provides a CASN (or perhaps CAS2, CAS3 ... CAS10?).
I took a look A Practical Multi-Word Compare-And-Swap, but I was unable to implement it. Perhaps someone else can ... or maybe there is more modern method?
On a mostly fresh ghc-7.6.3 Ubuntu 13.04 machine running the install_all script as CABAL=cabal-dev ./install_all.sh
fails with:
cabal: Error: some packages failed to install:
test-atomic-primops-0.1.0.0 failed during the building phase. The exception
was:
ExitFailure 1
The specific error for test-atomic-primops was:
Configuring test-atomic-primops-0.1.0.0...
Building test-atomic-primops-0.1.0.0...
Preprocessing executable 'hello-world-atomic-primops' for
test-atomic-primops-0.1.0.0...
cabal: can't find source for hello in .
Failed to install test-atomic-primops-0.1.0.0
I'd love to be able to depend on this.
Currently, cf85070, the ChaseLev implementation doesn't work reliably.
No leads at the moment on where the bug might be.
The implementation is a straightforward transcription of the psuedocode in the original paper:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf
This can be found in the following log:
This failure is nondeterministic. Other test runs immediately before and after that one passed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.