Commit 2675a89c authored by Mark Florisson's avatar Mark Florisson

Allow nested prange() & less warnings

parent d532f26a
...@@ -6834,10 +6834,11 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -6834,10 +6834,11 @@ class ParallelStatNode(StatNode, ParallelNode):
self.analyse_sharing_attributes(env) self.analyse_sharing_attributes(env)
if self.num_threads is not None: if self.num_threads is not None:
if self.parent and self.parent.num_threads is not None: if (self.parent and self.parent.num_threads is not None and not
self.parent.is_prange):
error(self.pos, error(self.pos,
"num_threads already declared in outer section") "num_threads already declared in outer section")
elif self.parent: elif self.parent and not self.parent.is_prange:
error(self.pos, error(self.pos,
"num_threads must be declared in the parent parallel section") "num_threads must be declared in the parent parallel section")
elif (self.num_threads.type.is_int and elif (self.num_threads.type.is_int and
...@@ -7113,11 +7114,15 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -7113,11 +7114,15 @@ class ParallelStatNode(StatNode, ParallelNode):
begin_code = self.begin_of_parallel_block begin_code = self.begin_of_parallel_block
end_code = code end_code = code
begin_code.putln("#ifdef _OPENMP")
begin_code.put_ensure_gil(declare_gilstate=True) begin_code.put_ensure_gil(declare_gilstate=True)
begin_code.putln("Py_BEGIN_ALLOW_THREADS") begin_code.putln("Py_BEGIN_ALLOW_THREADS")
begin_code.putln("#endif /* _OPENMP */")
end_code.putln("#ifdef _OPENMP")
end_code.putln("Py_END_ALLOW_THREADS") end_code.putln("Py_END_ALLOW_THREADS")
end_code.put_release_ensured_gil() end_code.put_release_ensured_gil()
end_code.putln("#endif /* _OPENMP */")
def trap_parallel_exit(self, code, should_flush=False): def trap_parallel_exit(self, code, should_flush=False):
""" """
...@@ -7216,8 +7221,13 @@ class ParallelStatNode(StatNode, ParallelNode): ...@@ -7216,8 +7221,13 @@ class ParallelStatNode(StatNode, ParallelNode):
temp_count += 1 temp_count += 1
invalid_value = entry.type.invalid_value()
if invalid_value:
init = ' = ' + invalid_value
else:
init = ''
# Declare the parallel private in the outer block # Declare the parallel private in the outer block
c.putln("%s %s;" % (type_decl, temp_cname)) c.putln("%s %s%s;" % (type_decl, temp_cname, init))
# Initialize before escaping # Initialize before escaping
code.putln("%s = %s;" % (temp_cname, private_cname)) code.putln("%s = %s;" % (temp_cname, private_cname))
...@@ -7434,6 +7444,7 @@ class ParallelRangeNode(ParallelStatNode): ...@@ -7434,6 +7444,7 @@ class ParallelRangeNode(ParallelStatNode):
start = stop = step = None start = stop = step = None
is_prange = True is_prange = True
is_nested_prange = False
nogil = None nogil = None
schedule = None schedule = None
...@@ -7544,6 +7555,16 @@ class ParallelRangeNode(ParallelStatNode): ...@@ -7544,6 +7555,16 @@ class ParallelRangeNode(ParallelStatNode):
if self.nogil: if self.nogil:
env.nogil = was_nogil env.nogil = was_nogil
self.is_nested_prange = self.parent and self.parent.is_prange
if self.is_nested_prange:
parent = self
while parent.parent and parent.parent.is_prange:
parent = parent.parent
parent.assignments.update(self.assignments)
parent.privates.update(self.privates)
parent.assigned_nodes.extend(self.assigned_nodes)
def nogil_check(self, env): def nogil_check(self, env):
names = 'start', 'stop', 'step', 'target' names = 'start', 'stop', 'step', 'target'
nodes = self.start, self.stop, self.step, self.target nodes = self.start, self.stop, self.step, self.target
...@@ -7670,6 +7691,9 @@ class ParallelRangeNode(ParallelStatNode): ...@@ -7670,6 +7691,9 @@ class ParallelRangeNode(ParallelStatNode):
self.release_closure_privates(code) self.release_closure_privates(code)
def generate_loop(self, code, fmt_dict): def generate_loop(self, code, fmt_dict):
if self.is_nested_prange:
code.putln("#if 0")
else:
code.putln("#ifdef _OPENMP") code.putln("#ifdef _OPENMP")
if not self.is_parallel: if not self.is_parallel:
...@@ -7688,6 +7712,9 @@ class ParallelRangeNode(ParallelStatNode): ...@@ -7688,6 +7712,9 @@ class ParallelRangeNode(ParallelStatNode):
# Initialize the GIL if needed for this thread # Initialize the GIL if needed for this thread
self.begin_parallel_block(code) self.begin_parallel_block(code)
if self.is_nested_prange:
code.putln("#if 0")
else:
code.putln("#ifdef _OPENMP") code.putln("#ifdef _OPENMP")
code.put("#pragma omp for") code.put("#pragma omp for")
......
...@@ -1099,7 +1099,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations): ...@@ -1099,7 +1099,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
if isinstance(newnode, Nodes.ParallelWithBlockNode): if isinstance(newnode, Nodes.ParallelWithBlockNode):
if self.state == 'parallel with': if self.state == 'parallel with':
error(node.manager.pos, error(node.manager.pos,
"Closely nested parallel with blocks are disallowed") "Nested parallel with blocks are disallowed")
self.state = 'parallel with' self.state = 'parallel with'
body = self.visit(node.body) body = self.visit(node.body)
......
...@@ -196,10 +196,8 @@ class MarkAssignments(CythonTransform): ...@@ -196,10 +196,8 @@ class MarkAssignments(CythonTransform):
self.parallel_block_stack.append(node) self.parallel_block_stack.append(node)
nested = nested or len(self.parallel_block_stack) > 2 nested = nested or len(self.parallel_block_stack) > 2
if not self.parallel_errors and nested: if not self.parallel_errors and nested and not node.is_prange:
error(node.pos, "Only prange() may be nested")
error(node.pos,
"Parallel nesting not supported due to bugs in gcc 4.5")
self.parallel_errors = True self.parallel_errors = True
if node.is_prange: if node.is_prange:
......
...@@ -145,6 +145,10 @@ cdef int chunksize(): ...@@ -145,6 +145,10 @@ cdef int chunksize():
for i in prange(10, nogil=True, schedule='static', chunksize=chunksize()): for i in prange(10, nogil=True, schedule='static', chunksize=chunksize()):
pass pass
with nogil, cython.parallel.parallel():
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
...@@ -157,7 +161,7 @@ c_cython_parallel.pyx:21:29: The parallel section may only be used without the G ...@@ -157,7 +161,7 @@ c_cython_parallel.pyx:21:29: The parallel section may only be used without the G
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:33:10: Must be of numeric type, not int *
e_cython_parallel.pyx:36:33: Closely nested parallel with blocks are disallowed e_cython_parallel.pyx:36:33: Nested parallel with blocks are disallowed
e_cython_parallel.pyx:39:12: The parallel directive must be called e_cython_parallel.pyx:39:12: The parallel directive must be called
e_cython_parallel.pyx:45:10: local variable 'y' referenced before assignment e_cython_parallel.pyx:45:10: local variable 'y' referenced before assignment
e_cython_parallel.pyx:55:9: local variable 'y' referenced before assignment e_cython_parallel.pyx:55:9: local variable 'y' referenced before assignment
...@@ -166,8 +170,6 @@ e_cython_parallel.pyx:62:36: cython.parallel.parallel() does not take positional ...@@ -166,8 +170,6 @@ e_cython_parallel.pyx:62:36: cython.parallel.parallel() does not take positional
e_cython_parallel.pyx:65:36: Invalid keyword argument: invalid e_cython_parallel.pyx:65:36: Invalid keyword argument: invalid
e_cython_parallel.pyx:73:12: Yield not allowed in parallel sections e_cython_parallel.pyx:73:12: Yield not allowed in parallel sections
e_cython_parallel.pyx:77:16: Yield not allowed in parallel sections e_cython_parallel.pyx:77:16: Yield not allowed in parallel sections
e_cython_parallel.pyx:82:19: Parallel nesting not supported due to bugs in gcc 4.5
e_cython_parallel.pyx:87:23: Parallel nesting not supported due to bugs in gcc 4.5
e_cython_parallel.pyx:97:19: Cannot assign to private of outer parallel block e_cython_parallel.pyx:97:19: Cannot assign to private of outer parallel block
e_cython_parallel.pyx:98:19: Cannot assign to private of outer parallel block e_cython_parallel.pyx:98:19: Cannot assign to private of outer parallel block
e_cython_parallel.pyx:104:6: Reductions not allowed for parallel blocks e_cython_parallel.pyx:104:6: Reductions not allowed for parallel blocks
...@@ -180,4 +182,5 @@ e_cython_parallel.pyx:133:42: Must provide schedule with chunksize ...@@ -180,4 +182,5 @@ e_cython_parallel.pyx:133:42: Must provide schedule with chunksize
e_cython_parallel.pyx:136:62: Chunksize must not be negative e_cython_parallel.pyx:136:62: Chunksize must not be negative
e_cython_parallel.pyx:139:62: Chunksize not valid for the schedule runtime e_cython_parallel.pyx:139:62: Chunksize not valid for the schedule runtime
e_cython_parallel.pyx:145:70: Calling gil-requiring function not allowed without gil e_cython_parallel.pyx:145:70: Calling gil-requiring function not allowed without gil
e_cython_parallel.pyx:149:33: Nested parallel with blocks are disallowed
""" """
...@@ -46,7 +46,6 @@ def test_descending_prange(): ...@@ -46,7 +46,6 @@ def test_descending_prange():
return sum return sum
'''
def test_propagation(): def test_propagation():
""" """
>>> test_propagation() >>> test_propagation()
...@@ -61,12 +60,10 @@ def test_propagation(): ...@@ -61,12 +60,10 @@ def test_propagation():
with nogil, cython.parallel.parallel(): with nogil, cython.parallel.parallel():
for x in prange(10): for x in prange(10):
with cython.parallel.parallel():
for y in prange(10): for y in prange(10):
sum2 += y sum2 += y
return i, j, x, y, sum1, sum2 return i, j, x, y, sum1, sum2
'''
def test_unsigned_operands(): def test_unsigned_operands():
""" """
...@@ -349,7 +346,6 @@ def test_prange_continue(): ...@@ -349,7 +346,6 @@ def test_prange_continue():
free(p) free(p)
'''
def test_nested_break_continue(): def test_nested_break_continue():
""" """
>>> test_nested_break_continue() >>> test_nested_break_continue()
...@@ -371,16 +367,14 @@ def test_nested_break_continue(): ...@@ -371,16 +367,14 @@ def test_nested_break_continue():
print i, j, result1, result2 print i, j, result1, result2
with nogil, cython.parallel.parallel(): with nogil, cython.parallel.parallel(num_threads=2):
for i in prange(10, num_threads=2, schedule='static'): for i in prange(10, schedule='static'):
with cython.parallel.parallel():
if i == 8: if i == 8:
break break
else: else:
continue continue
print i print i
'''
cdef int parallel_return() nogil: cdef int parallel_return() nogil:
cdef int i cdef int i
...@@ -400,11 +394,10 @@ def test_return(): ...@@ -400,11 +394,10 @@ def test_return():
""" """
print parallel_return() print parallel_return()
'''
def test_parallel_exceptions(): def test_parallel_exceptions():
""" """
>>> test_parallel_exceptions() >>> test_parallel_exceptions()
('I am executed first', 0) I am executed first
('propagate me',) 0 ('propagate me',) 0
""" """
cdef int i, j, sum = 0 cdef int i, j, sum = 0
...@@ -422,11 +415,10 @@ def test_parallel_exceptions(): ...@@ -422,11 +415,10 @@ def test_parallel_exceptions():
sum += i sum += i
finally: finally:
with gil: with gil:
mylist.append(("I am executed first", sum)) mylist.append("I am executed first")
except Exception, e: except Exception, e:
print mylist[0] print mylist[0]
print e.args, sum print e.args, sum
'''
def test_parallel_exceptions_unnested(): def test_parallel_exceptions_unnested():
""" """
...@@ -453,7 +445,6 @@ def test_parallel_exceptions_unnested(): ...@@ -453,7 +445,6 @@ def test_parallel_exceptions_unnested():
print mylist[0] print mylist[0]
print e.args, sum print e.args, sum
'''
cdef int parallel_exc_cdef() except -3: cdef int parallel_exc_cdef() except -3:
cdef int i, j cdef int i, j
for i in prange(10, nogil=True): for i in prange(10, nogil=True):
...@@ -462,7 +453,6 @@ cdef int parallel_exc_cdef() except -3: ...@@ -462,7 +453,6 @@ cdef int parallel_exc_cdef() except -3:
raise Exception("propagate me") raise Exception("propagate me")
return 0 return 0
'''
cdef int parallel_exc_cdef_unnested() except -3: cdef int parallel_exc_cdef_unnested() except -3:
cdef int i cdef int i
...@@ -480,9 +470,8 @@ def test_parallel_exc_cdef(): ...@@ -480,9 +470,8 @@ def test_parallel_exc_cdef():
Exception: propagate me Exception: propagate me
""" """
parallel_exc_cdef_unnested() parallel_exc_cdef_unnested()
#parallel_exc_cdef() parallel_exc_cdef()
'''
cpdef int parallel_exc_cpdef() except -3: cpdef int parallel_exc_cpdef() except -3:
cdef int i, j cdef int i, j
for i in prange(10, nogil=True): for i in prange(10, nogil=True):
...@@ -491,7 +480,6 @@ cpdef int parallel_exc_cpdef() except -3: ...@@ -491,7 +480,6 @@ cpdef int parallel_exc_cpdef() except -3:
raise Exception("propagate me") raise Exception("propagate me")
return 0 return 0
'''
cpdef int parallel_exc_cpdef_unnested() except -3: cpdef int parallel_exc_cpdef_unnested() except -3:
cdef int i, j cdef int i, j
...@@ -510,9 +498,8 @@ def test_parallel_exc_cpdef(): ...@@ -510,9 +498,8 @@ def test_parallel_exc_cpdef():
Exception: propagate me Exception: propagate me
""" """
parallel_exc_cpdef_unnested() parallel_exc_cpdef_unnested()
#parallel_exc_cpdef() parallel_exc_cpdef()
'''
cdef int parallel_exc_nogil_swallow() except -1: cdef int parallel_exc_nogil_swallow() except -1:
cdef int i, j cdef int i, j
for i in prange(10, nogil=True): for i in prange(10, nogil=True):
...@@ -524,7 +511,6 @@ cdef int parallel_exc_nogil_swallow() except -1: ...@@ -524,7 +511,6 @@ cdef int parallel_exc_nogil_swallow() except -1:
return i return i
return 0 return 0
'''
cdef int parallel_exc_nogil_swallow_unnested() except -1: cdef int parallel_exc_nogil_swallow_unnested() except -1:
cdef int i cdef int i
...@@ -542,13 +528,13 @@ def test_parallel_exc_nogil_swallow(): ...@@ -542,13 +528,13 @@ def test_parallel_exc_nogil_swallow():
""" """
>>> test_parallel_exc_nogil_swallow() >>> test_parallel_exc_nogil_swallow()
execute me execute me
execute me
""" """
parallel_exc_nogil_swallow_unnested() parallel_exc_nogil_swallow_unnested()
print 'execute me' print 'execute me'
#parallel_exc_nogil_swallow() parallel_exc_nogil_swallow()
#print 'execute me' print 'execute me'
'''
def parallel_exc_replace(): def parallel_exc_replace():
""" """
>>> parallel_exc_replace() >>> parallel_exc_replace()
...@@ -569,7 +555,13 @@ def parallel_exc_replace(): ...@@ -569,7 +555,13 @@ def parallel_exc_replace():
return 0 return 0
def _parallel_exceptions2(): def parallel_exceptions2():
"""
>>> parallel_exceptions2()
Traceback (most recent call last):
...
Exception: propagate me
"""
cdef int i, j, k cdef int i, j, k
for i in prange(10, nogil=True): for i in prange(10, nogil=True):
...@@ -582,59 +574,6 @@ def _parallel_exceptions2(): ...@@ -582,59 +574,6 @@ def _parallel_exceptions2():
continue continue
return return
def test_parallel_exceptions2():
"""
DISABLED
test_parallel_exceptions2()
read: start
propagate me
exiting...
Exit status: 0
"""
if not hasattr(os, 'fork'):
print 'start'
print 'propagate me'
print 'Exit status: 0'
return
r, w = os.pipe()
fr = os.fdopen(r, 'r')
fw = os.fdopen(w, 'w', 0)
pid = os.fork()
if pid == 0:
try:
fr.close()
os.dup2(w, 1)
os.dup2(w, 2)
print >>fw, 'start'
try:
_parallel_exceptions2()
except Exception, e:
print >>fw, e.args[0]
else:
print >>fw, 'No exception caught'
except:
import traceback
print >>fw, traceback.format_exc()
finally:
print >>fw, 'exiting...'
os._exit(0)
else:
fw.close()
print 'read:', fr.read(),
pid, status = os.waitpid(pid, 0)
if os.WIFSIGNALED(status):
print 'Got signal', os.WTERMSIG(status)
print 'Exit status:', os.WEXITSTATUS(status)
'''
def test_parallel_with_gil_return(): def test_parallel_with_gil_return():
""" """
>>> test_parallel_with_gil_return() >>> test_parallel_with_gil_return()
...@@ -654,25 +593,6 @@ def test_parallel_with_gil_return(): ...@@ -654,25 +593,6 @@ def test_parallel_with_gil_return():
with gil: with gil:
return sum return sum
'''
def test_parallel_with_gil_continue():
"""
>>> test_parallel_with_gil_continue()
20
"""
cdef int i, sum = 0
for i in prange(10, nogil=True):
with cython.parallel.parallel():
with gil:
if i % 2:
continue
sum += i
print sum
'''
def test_parallel_with_gil_continue_unnested(): def test_parallel_with_gil_continue_unnested():
""" """
>>> test_parallel_with_gil_continue_unnested() >>> test_parallel_with_gil_continue_unnested()
......
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