1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
# mode: run
# tag: openmp
from cython.parallel cimport prange
cimport cython
from random import randint, random
include "../buffers/mockbuffers.pxi"
# This test is designed to pick up concurrency errors in memoryview reference counting.
# It won't be 100% reliable, but hopefully does enough memoryview reference counting in
# parallel that we should see errors if it isn't thread-safe.
# It has been verified to crash if the atomic reference counting is replaced with non-atomic counting.
@cython.boundscheck(False)
@cython.wraparound(False)
def refcounting_stress_test(int N):
"""
>>> _ = refcounting_stress_test(5000)
acquired a
acquired b
acquired c
released a
released b
released c
"""
selectors = [ randint(0, 3) for _ in range(N) ]
cdef int[::1] selectorsview = IntMockBuffer(None, selectors, (N,))
shape = (10, 3)
size = shape[0]*shape[1]
a = [ random() for _ in range(size) ]
b = [ random() for _ in range(size) ]
c = [ random() for _ in range(size) ]
cdef double[:,:] aview = DoubleMockBuffer("a", a, shape)
cdef double[:,:] bview = DoubleMockBuffer("b", b, shape)
cdef double[:,:] cview = DoubleMockBuffer("c", c, shape)
cdef int i
cdef double total = 0.0
for i in prange(N, nogil=True):
total += loopbody(aview, bview, cview, selectorsview[i])
# make "release" order predictable
del aview
del bview
del cview
return total
@cython.boundscheck(False)
@cython.wraparound(False)
cdef double loopbody(double[:,:] a, double[:,:] b, double[:,:] c, int selector) nogil:
cdef double[:,:] selected
cdef double[:] subslice
cdef double res = 0
if selector % 3 == 1:
selected = a
elif selector % 3 == 2:
selected = b
else:
selected = c
for i in range(selected.shape[0]):
subslice = selected[i, :]
res += subslice[0] + subslice[2]
return res
|