Commit acfbf762 authored by Mark Florisson's avatar Mark Florisson

Add openmp tag to test runner

parent 88db4139
...@@ -54,6 +54,7 @@ CY3_DIR = None ...@@ -54,6 +54,7 @@ CY3_DIR = None
from distutils.dist import Distribution from distutils.dist import Distribution
from distutils.core import Extension from distutils.core import Extension
from distutils.command.build_ext import build_ext as _build_ext from distutils.command.build_ext import build_ext as _build_ext
from distutils import sysconfig
distutils_distro = Distribution() distutils_distro = Distribution()
if sys.platform == 'win32': if sys.platform == 'win32':
...@@ -78,8 +79,60 @@ def update_numpy_extension(ext): ...@@ -78,8 +79,60 @@ def update_numpy_extension(ext):
import numpy import numpy
ext.include_dirs.append(numpy.get_include()) ext.include_dirs.append(numpy.get_include())
def update_openmp_extension(ext):
language = ext.language
if language == 'cpp':
flags = OPENMP_CPP_COMPILER_FLAGS
else:
flags = OPENMP_C_COMPILER_FLAGS
if flags:
compile_flags, link_flags = flags
ext.extra_compile_args.extend(compile_flags.split())
ext.extra_link_args.extend(link_flags.split())
return ext
return EXCLUDE_EXT
def get_openmp_compiler_flags(language):
"""
As of gcc 4.2, it supports OpenMP 2.5. Gcc 4.4 implements 3.0. We don't
(currently) check for other compilers.
returns a two-tuple of (CFLAGS, LDFLAGS) to build the OpenMP extension
"""
if language == 'cpp':
cc = sysconfig.get_config_var('CXX')
else:
cc = sysconfig.get_config_var('CC')
matcher = re.compile(r"gcc version (\d+\.\d+)").search
try:
import subprocess
except ImportError:
in_, out, err = os.popen(cc = " -v")
output = out.read() or err.read()
else:
p = subprocess.Popen([cc, "-v"], stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output = p.stdout.read()
compiler_version = matcher(output).group(1)
if compiler_version and compiler_version.split('.') >= ['4', '2']:
return '-fopenmp', '-fopenmp'
OPENMP_C_COMPILER_FLAGS = get_openmp_compiler_flags('c')
OPENMP_CPP_COMPILER_FLAGS = get_openmp_compiler_flags('cpp')
# Return this from the EXT_EXTRAS matcher callback to exclude the extension
EXCLUDE_EXT = object()
EXT_EXTRAS = { EXT_EXTRAS = {
'tag:numpy' : update_numpy_extension, 'tag:numpy' : update_numpy_extension,
'tag:openmp': update_openmp_extension,
} }
# TODO: use tags # TODO: use tags
...@@ -519,13 +572,21 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -519,13 +572,21 @@ class CythonCompileTestCase(unittest.TestCase):
extra_compile_args = ext_compile_flags, extra_compile_args = ext_compile_flags,
**extra_extension_args **extra_extension_args
) )
if self.language == 'cpp':
# Set the language now as the fixer might need it
extension.language = 'c++'
for matcher, fixer in EXT_EXTRAS.items(): for matcher, fixer in EXT_EXTRAS.items():
if isinstance(matcher, str): if isinstance(matcher, str):
del EXT_EXTRAS[matcher] del EXT_EXTRAS[matcher]
matcher = string_selector(matcher) matcher = string_selector(matcher)
EXT_EXTRAS[matcher] = fixer EXT_EXTRAS[matcher] = fixer
if matcher(module, tags): if matcher(module, tags):
extension = fixer(extension) or extension newext = fixer(extension)
if newext is EXCLUDE_EXT:
return
extension = newext or extension
if self.language == 'cpp': if self.language == 'cpp':
extension.language = 'c++' extension.language = 'c++'
build_extension.extensions = [extension] build_extension.extensions = [extension]
...@@ -646,6 +707,7 @@ def run_forked_test(result, run_func, test_name, fork=True): ...@@ -646,6 +707,7 @@ def run_forked_test(result, run_func, test_name, fork=True):
try: try:
cid, result_code = os.waitpid(child_id, 0) cid, result_code = os.waitpid(child_id, 0)
module_name = test_name.split()[-1]
# os.waitpid returns the child's result code in the # os.waitpid returns the child's result code in the
# upper byte of result_code, and the signal it was # upper byte of result_code, and the signal it was
# killed by in the lower byte # killed by in the lower byte
......
# tag: numpy # tag: numpy
# distutils: libraries = gomp # tag: openmp
# distutils: extra_compile_args = -fopenmp
cimport cython cimport cython
from cython.parallel import prange from cython.parallel import prange
......
# tag: run # tag: run
# distutils: libraries = gomp # tag: openmp
# distutils: extra_compile_args = -fopenmp
cimport cython.parallel cimport cython.parallel
from cython.parallel import prange, threadid from cython.parallel import prange, threadid
cimport openmp cimport openmp
from libc.stdlib cimport malloc, free from libc.stdlib cimport malloc, free
from libc.stdio cimport puts
import sys
try:
from builtins import next # Py3k
except ImportError:
def next(it):
return it.next()
#@cython.test_assert_path_exists(
# "//ParallelWithBlockNode//ParallelRangeNode[@schedule = 'dynamic']",
# "//GILStatNode[@state = 'nogil]//ParallelRangeNode")
def test_prange():
"""
>>> test_prange()
(9, 9, 45, 45)
"""
cdef Py_ssize_t i, j, sum1 = 0, sum2 = 0
with nogil, cython.parallel.parallel:
for i in prange(10, schedule='dynamic'):
sum1 += i
for j in prange(10, nogil=True):
sum2 += j
return i, j, sum1, sum2
def test_descending_prange():
"""
>>> test_descending_prange()
5
"""
cdef int i, start = 5, stop = -5, step = -2
cdef int sum = 0
for i in prange(start, stop, step, nogil=True):
sum += i
return sum
def test_propagation():
"""
>>> test_propagation()
(9, 9, 9, 9, 450, 450)
"""
cdef int i, j, x, y
cdef int sum1 = 0, sum2 = 0
for i in prange(10, nogil=True):
for j in prange(10):
sum1 += i
with nogil, cython.parallel.parallel:
for x in prange(10):
with cython.parallel.parallel:
for y in prange(10):
sum2 += y
return i, j, x, y, sum1, sum2
def test_parallel(): def test_parallel():
""" """
...@@ -87,114 +24,4 @@ def test_parallel(): ...@@ -87,114 +24,4 @@ def test_parallel():
free(buf) free(buf)
def test_unsigned_operands(): include "sequential_parallel.pyx"
"""
This test is disabled, as this currently does not work (neither does it
for 'for i from x < i < y:'. I'm not sure we should strife to support
this, at least the C compiler gives a warning.
test_unsigned_operands()
10
"""
cdef int i
cdef int start = -5
cdef unsigned int stop = 5
cdef int step = 1
cdef int steps_taken = 0
for i in prange(start, stop, step, nogil=True):
steps_taken += 1
return steps_taken
def test_reassign_start_stop_step():
"""
>>> test_reassign_start_stop_step()
20
"""
cdef int start = 0, stop = 10, step = 2
cdef int i
cdef int sum = 0
for i in prange(start, stop, step, nogil=True):
start = -2
stop = 2
step = 0
sum += i
return sum
def test_closure_parallel_privates():
"""
>>> test_closure_parallel_privates()
9 9
45 45
0 0 9 9
"""
cdef int x
def test_target():
nonlocal x
for x in prange(10, nogil=True):
pass
return x
print test_target(), x
def test_reduction():
nonlocal x
cdef int i
x = 0
for i in prange(10, nogil=True):
x += i
return x
print test_reduction(), x
def test_generator():
nonlocal x
cdef int i
x = 0
yield x
x = 2
for i in prange(10, nogil=True):
x = i
yield x
g = test_generator()
print next(g), x, next(g), x
def test_pure_mode():
"""
>>> test_pure_mode()
0
1
2
3
4
4
3
2
1
0
0
"""
import Cython.Shadow
pure_parallel = sys.modules['cython.parallel']
for i in pure_parallel.prange(5):
print i
for i in pure_parallel.prange(4, -1, -1, schedule='dynamic', nogil=True):
print i
with pure_parallel.parallel:
print pure_parallel.threadid()
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