Commit 17d04e6d authored by Mark Florisson's avatar Mark Florisson Committed by Vitja Makarov

Disallow nested parallel blocks and propagate sharing attributes

parent 300120ee
This diff is collapsed.
...@@ -978,6 +978,10 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations): ...@@ -978,6 +978,10 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
# Keep track of whether we are in a parallel range section # Keep track of whether we are in a parallel range section
in_prange = False in_prange = False
# One of 'prange' or 'with parallel'. This is used to disallow closely
# nested 'with parallel:' blocks
state = None
directive_to_node = { directive_to_node = {
u"cython.parallel.parallel": Nodes.ParallelWithBlockNode, u"cython.parallel.parallel": Nodes.ParallelWithBlockNode,
# u"cython.parallel.threadsavailable": ExprNodes.ParallelThreadsAvailableNode, # u"cython.parallel.threadsavailable": ExprNodes.ParallelThreadsAvailableNode,
...@@ -1070,9 +1074,16 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations): ...@@ -1070,9 +1074,16 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
# There was an error, stop here and now # There was an error, stop here and now
return None return None
if self.state == 'parallel with':
error(node.manager.pos,
"Closely nested 'with parallel:' blocks are disallowed")
self.state = 'parallel with'
self.visit(node.body) self.visit(node.body)
self.state = None
newnode = Nodes.ParallelWithBlockNode(node.pos, body=node.body) newnode = Nodes.ParallelWithBlockNode(node.pos, body=node.body)
else: else:
newnode = node newnode = node
...@@ -1088,6 +1099,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations): ...@@ -1088,6 +1099,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
was_in_prange = self.in_prange was_in_prange = self.in_prange
self.in_prange = isinstance(node.iterator.sequence, self.in_prange = isinstance(node.iterator.sequence,
Nodes.ParallelRangeNode) Nodes.ParallelRangeNode)
previous_state = self.state
if self.in_prange: if self.in_prange:
# This will replace the entire ForInStatNode, so copy the # This will replace the entire ForInStatNode, so copy the
...@@ -1104,11 +1116,13 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations): ...@@ -1104,11 +1116,13 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
error(node.target.pos, error(node.target.pos,
"Can only iterate over an iteration variable") "Can only iterate over an iteration variable")
self.visit(node.body) self.state = 'prange'
self.visit(node.body)
self.state = previous_state
self.in_prange = was_in_prange self.in_prange = was_in_prange
self.visit(node.else_clause)
self.visit(node.else_clause)
return node return node
def ensure_not_in_prange(name): def ensure_not_in_prange(name):
......
...@@ -30,6 +30,12 @@ with nogil, cython.parallel.parallel: ...@@ -30,6 +30,12 @@ with nogil, cython.parallel.parallel:
for x[1] in prange(10): for x[1] in prange(10):
pass pass
for x in prange(10):
pass
with cython.parallel.parallel:
pass
_ERRORS = u""" _ERRORS = u"""
e_cython_parallel.pyx:3:8: cython.parallel.parallel is not a module e_cython_parallel.pyx:3:8: cython.parallel.parallel is not a module
e_cython_parallel.pyx:4:0: No such directive: cython.parallel.something e_cython_parallel.pyx:4:0: No such directive: cython.parallel.something
...@@ -41,4 +47,6 @@ e_cython_parallel.pyx:18:19: Invalid schedule argument to prange: 'invalid_sched ...@@ -41,4 +47,6 @@ e_cython_parallel.pyx:18:19: Invalid schedule argument to prange: 'invalid_sched
e_cython_parallel.pyx:21:5: The parallel section may only be used without the GIL e_cython_parallel.pyx:21:5: The parallel section may only be used without the GIL
e_cython_parallel.pyx:27:10: target may not be a Python object as we don't have the GIL e_cython_parallel.pyx:27:10: target may not be a Python object as we don't have the GIL
e_cython_parallel.pyx:30:9: Can only iterate over an iteration variable e_cython_parallel.pyx:30:9: Can only iterate over an iteration variable
e_cython_parallel.pyx:33:10: Must be of numeric type, not int *
e_cython_parallel.pyx:36:24: Closely nested 'with parallel:' blocks are disallowed
""" """
...@@ -43,30 +43,25 @@ def test_descending_prange(): ...@@ -43,30 +43,25 @@ def test_descending_prange():
return sum return sum
def test_nested_prange(): def test_propagation():
""" """
Reduction propagation is not (yet) supported. >>> test_propagation()
(9, 9, 9, 9, 450, 450)
>>> test_nested_prange()
50
""" """
cdef int i, j cdef int i, j, x, y
cdef int sum = 0 cdef int sum1 = 0, sum2 = 0
for i in prange(5, nogil=True):
for j in prange(5):
sum += i
# The value of sum is undefined here
sum = 0 for i in prange(10, nogil=True):
for j in prange(10):
sum1 += i
for i in prange(5, nogil=True): with nogil, cython.parallel.parallel:
for j in prange(5): for x in prange(10):
sum += i with cython.parallel.parallel:
sum += 0 for y in prange(10):
sum2 += y
return sum return i, j, x, y, sum1, sum2
def test_parallel(): def test_parallel():
...@@ -225,11 +220,11 @@ def test_parallel_numpy_arrays(): ...@@ -225,11 +220,11 @@ def test_parallel_numpy_arrays():
print i print i
return return
x = numpy.zeros(10, dtype=np.int) x = numpy.zeros(10, dtype=numpy.int)
for i in prange(x.shape[0], nogil=True): for i in prange(x.shape[0], nogil=True):
x[i] = i - 5 x[i] = i - 5
for i in x: for i in x:
print x print i
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment