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):
self.analyse_sharing_attributes(env)
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,
"num_threads already declared in outer section")
elif self.parent:
elif self.parent and not self.parent.is_prange:
error(self.pos,
"num_threads must be declared in the parent parallel section")
elif (self.num_threads.type.is_int and
......@@ -7113,11 +7114,15 @@ class ParallelStatNode(StatNode, ParallelNode):
begin_code = self.begin_of_parallel_block
end_code = code
begin_code.putln("#ifdef _OPENMP")
begin_code.put_ensure_gil(declare_gilstate=True)
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.put_release_ensured_gil()
end_code.putln("#endif /* _OPENMP */")
def trap_parallel_exit(self, code, should_flush=False):
"""
......@@ -7216,8 +7221,13 @@ class ParallelStatNode(StatNode, ParallelNode):
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
c.putln("%s %s;" % (type_decl, temp_cname))
c.putln("%s %s%s;" % (type_decl, temp_cname, init))
# Initialize before escaping
code.putln("%s = %s;" % (temp_cname, private_cname))
......@@ -7434,6 +7444,7 @@ class ParallelRangeNode(ParallelStatNode):
start = stop = step = None
is_prange = True
is_nested_prange = False
nogil = None
schedule = None
......@@ -7544,6 +7555,16 @@ class ParallelRangeNode(ParallelStatNode):
if self.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):
names = 'start', 'stop', 'step', 'target'
nodes = self.start, self.stop, self.step, self.target
......@@ -7670,7 +7691,10 @@ class ParallelRangeNode(ParallelStatNode):
self.release_closure_privates(code)
def generate_loop(self, code, fmt_dict):
code.putln("#ifdef _OPENMP")
if self.is_nested_prange:
code.putln("#if 0")
else:
code.putln("#ifdef _OPENMP")
if not self.is_parallel:
code.put("#pragma omp for")
......@@ -7688,7 +7712,10 @@ class ParallelRangeNode(ParallelStatNode):
# Initialize the GIL if needed for this thread
self.begin_parallel_block(code)
code.putln("#ifdef _OPENMP")
if self.is_nested_prange:
code.putln("#if 0")
else:
code.putln("#ifdef _OPENMP")
code.put("#pragma omp for")
for entry, (op, lastprivate) in self.privates.iteritems():
......
......@@ -1099,7 +1099,7 @@ class ParallelRangeTransform(CythonTransform, SkipDeclarations):
if isinstance(newnode, Nodes.ParallelWithBlockNode):
if self.state == 'parallel with':
error(node.manager.pos,
"Closely nested parallel with blocks are disallowed")
"Nested parallel with blocks are disallowed")
self.state = 'parallel with'
body = self.visit(node.body)
......
......@@ -196,10 +196,8 @@ class MarkAssignments(CythonTransform):
self.parallel_block_stack.append(node)
nested = nested or len(self.parallel_block_stack) > 2
if not self.parallel_errors and nested:
error(node.pos,
"Parallel nesting not supported due to bugs in gcc 4.5")
if not self.parallel_errors and nested and not node.is_prange:
error(node.pos, "Only prange() may be nested")
self.parallel_errors = True
if node.is_prange:
......
......@@ -145,6 +145,10 @@ cdef int chunksize():
for i in prange(10, nogil=True, schedule='static', chunksize=chunksize()):
pass
with nogil, cython.parallel.parallel():
with cython.parallel.parallel():
pass
_ERRORS = u"""
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
......@@ -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: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: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:45:10: 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
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: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:98:19: Cannot assign to private of outer parallel block
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
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: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():
return sum
'''
def test_propagation():
"""
>>> test_propagation()
......@@ -61,12 +60,10 @@ def test_propagation():
with nogil, cython.parallel.parallel():
for x in prange(10):
with cython.parallel.parallel():
for y in prange(10):
sum2 += y
for y in prange(10):
sum2 += y
return i, j, x, y, sum1, sum2
'''
def test_unsigned_operands():
"""
......@@ -349,7 +346,6 @@ def test_prange_continue():
free(p)
'''
def test_nested_break_continue():
"""
>>> test_nested_break_continue()
......@@ -371,16 +367,14 @@ def test_nested_break_continue():
print i, j, result1, result2
with nogil, cython.parallel.parallel():
for i in prange(10, num_threads=2, schedule='static'):
with cython.parallel.parallel():
if i == 8:
break
else:
continue
with nogil, cython.parallel.parallel(num_threads=2):
for i in prange(10, schedule='static'):
if i == 8:
break
else:
continue
print i
'''
cdef int parallel_return() nogil:
cdef int i
......@@ -400,11 +394,10 @@ def test_return():
"""
print parallel_return()
'''
def test_parallel_exceptions():
"""
>>> test_parallel_exceptions()
('I am executed first', 0)
I am executed first
('propagate me',) 0
"""
cdef int i, j, sum = 0
......@@ -422,11 +415,10 @@ def test_parallel_exceptions():
sum += i
finally:
with gil:
mylist.append(("I am executed first", sum))
mylist.append("I am executed first")
except Exception, e:
print mylist[0]
print e.args, sum
'''
def test_parallel_exceptions_unnested():
"""
......@@ -453,7 +445,6 @@ def test_parallel_exceptions_unnested():
print mylist[0]
print e.args, sum
'''
cdef int parallel_exc_cdef() except -3:
cdef int i, j
for i in prange(10, nogil=True):
......@@ -462,7 +453,6 @@ cdef int parallel_exc_cdef() except -3:
raise Exception("propagate me")
return 0
'''
cdef int parallel_exc_cdef_unnested() except -3:
cdef int i
......@@ -480,9 +470,8 @@ def test_parallel_exc_cdef():
Exception: propagate me
"""
parallel_exc_cdef_unnested()
#parallel_exc_cdef()
parallel_exc_cdef()
'''
cpdef int parallel_exc_cpdef() except -3:
cdef int i, j
for i in prange(10, nogil=True):
......@@ -491,7 +480,6 @@ cpdef int parallel_exc_cpdef() except -3:
raise Exception("propagate me")
return 0
'''
cpdef int parallel_exc_cpdef_unnested() except -3:
cdef int i, j
......@@ -510,9 +498,8 @@ def test_parallel_exc_cpdef():
Exception: propagate me
"""
parallel_exc_cpdef_unnested()
#parallel_exc_cpdef()
parallel_exc_cpdef()
'''
cdef int parallel_exc_nogil_swallow() except -1:
cdef int i, j
for i in prange(10, nogil=True):
......@@ -524,7 +511,6 @@ cdef int parallel_exc_nogil_swallow() except -1:
return i
return 0
'''
cdef int parallel_exc_nogil_swallow_unnested() except -1:
cdef int i
......@@ -542,13 +528,13 @@ def test_parallel_exc_nogil_swallow():
"""
>>> test_parallel_exc_nogil_swallow()
execute me
execute me
"""
parallel_exc_nogil_swallow_unnested()
print 'execute me'
#parallel_exc_nogil_swallow()
#print 'execute me'
parallel_exc_nogil_swallow()
print 'execute me'
'''
def parallel_exc_replace():
"""
>>> parallel_exc_replace()
......@@ -569,7 +555,13 @@ def parallel_exc_replace():
return 0
def _parallel_exceptions2():
def parallel_exceptions2():
"""
>>> parallel_exceptions2()
Traceback (most recent call last):
...
Exception: propagate me
"""
cdef int i, j, k
for i in prange(10, nogil=True):
......@@ -582,59 +574,6 @@ def _parallel_exceptions2():
continue
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():
"""
>>> test_parallel_with_gil_return()
......@@ -654,25 +593,6 @@ def test_parallel_with_gil_return():
with gil:
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():
"""
>>> 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