barrier more efficient

This commit is contained in:
Araq 2014-06-03 08:25:42 +02:00
commit a4323b06b3

View file

@ -40,31 +40,37 @@ proc signal(cv: var CondVar) =
release(cv.L) release(cv.L)
signal(cv.c) signal(cv.c)
const CacheLineSize = 32 # true for most archs
type type
Barrier* {.compilerProc.} = object Barrier {.compilerProc.} = object
entered: int entered: int
cv: CondVar cv: CondVar # condvar takes 3 words at least
cacheAlign: array[0..20, byte] # ensure 'left' is not on the same when sizeof(int) < 8:
# cache line as 'entered' cacheAlign: array[CacheLineSize-4*sizeof(int), byte]
left: int left: int
cacheAlign2: array[CacheLineSize-sizeof(int), byte]
interest: bool ## wether the master is interested in the "all done" event
proc barrierEnter*(b: ptr Barrier) {.compilerProc.} = proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} =
atomicInc b.entered ## due to the signaling between threads, it is ensured we are the only
## one with access to 'entered' so we don't need 'atomicInc' here:
inc b.entered
proc barrierLeave*(b: ptr Barrier) {.compilerProc.} = proc barrierLeave(b: ptr Barrier) {.compilerProc, inline.} =
atomicInc b.left atomicInc b.left
# these can only be equal if 'closeBarrier' already signaled its interest if b.interest and b.left == b.entered: signal(b.cv)
# in this event:
if b.left == b.entered: signal(b.cv)
proc openBarrier*(b: ptr Barrier) {.compilerProc.} = proc openBarrier(b: ptr Barrier) {.compilerProc, inline.} =
b.entered = 0 b.entered = 0
b.cv = createCondVar() b.left = 0
b.left = -1 b.interest = false
proc closeBarrier*(b: ptr Barrier) {.compilerProc.} = proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
# signal interest in the "all done" event: if b.left != b.entered:
atomicInc b.left b.cv = createCondVar()
b.interest = true # XXX we really need to ensure no re-orderings are done
# by the C compiler here
while b.left != b.entered: await(b.cv) while b.left != b.entered: await(b.cv)
destroyCondVar(b.cv) destroyCondVar(b.cv)