Commit 6bb8b78a authored by Stefan Behnel's avatar Stefan Behnel

Use "fast_gil" calls in line tracing code when available, and actually test it.

parent b9eaba7c
......@@ -2228,6 +2228,12 @@ class CCodeWriter(object):
# GIL methods
def use_fast_gil_utility_code(self):
if self.globalstate.directives['fast_gil']:
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
else:
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
def put_ensure_gil(self, declare_gilstate=True, variable=None):
"""
Acquire the GIL. The generated code is safe even when no PyThreadState
......@@ -2237,10 +2243,7 @@ class CCodeWriter(object):
"""
self.globalstate.use_utility_code(
UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
if self.globalstate.directives['fast_gil']:
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
else:
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
self.use_fast_gil_utility_code()
self.putln("#ifdef WITH_THREAD")
if not variable:
variable = '__pyx_gilstate_save'
......@@ -2253,10 +2256,7 @@ class CCodeWriter(object):
"""
Releases the GIL, corresponds to `put_ensure_gil`.
"""
if self.globalstate.directives['fast_gil']:
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
else:
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
self.use_fast_gil_utility_code()
if not variable:
variable = '__pyx_gilstate_save'
self.putln("#ifdef WITH_THREAD")
......@@ -2268,10 +2268,7 @@ class CCodeWriter(object):
Acquire the GIL. The thread's thread state must have been initialized
by a previous `put_release_gil`
"""
if self.globalstate.directives['fast_gil']:
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
else:
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
self.use_fast_gil_utility_code()
self.putln("#ifdef WITH_THREAD")
self.putln("__Pyx_FastGIL_Forget();")
if variable:
......@@ -2281,10 +2278,7 @@ class CCodeWriter(object):
def put_release_gil(self, variable=None):
"Release the GIL, corresponds to `put_acquire_gil`."
if self.globalstate.directives['fast_gil']:
self.globalstate.use_utility_code(UtilityCode.load_cached("FastGil", "ModuleSetupCode.c"))
else:
self.globalstate.use_utility_code(UtilityCode.load_cached("NoFastGil", "ModuleSetupCode.c"))
self.use_fast_gil_utility_code()
self.putln("#ifdef WITH_THREAD")
self.putln("PyThreadState *_save;")
self.putln("Py_UNBLOCK_THREADS")
......
......@@ -2350,6 +2350,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
profile = code.globalstate.directives['profile']
linetrace = code.globalstate.directives['linetrace']
if profile or linetrace:
if linetrace:
code.use_fast_gil_utility_code()
code.globalstate.use_utility_code(UtilityCode.load_cached("Profile", "Profile.c"))
code.put_declare_refcount_context()
......
......@@ -1788,6 +1788,8 @@ class FuncDefNode(StatNode, BlockNode):
profile = code.globalstate.directives['profile']
linetrace = code.globalstate.directives['linetrace']
if profile or linetrace:
if linetrace:
code.use_fast_gil_utility_code()
code.globalstate.use_utility_code(
UtilityCode.load_cached("Profile", "Profile.c"))
......
......@@ -197,12 +197,12 @@
if (CYTHON_TRACE_NOGIL) { \
int ret = 0; \
PyThreadState *tstate; \
PyGILState_STATE state = PyGILState_Ensure(); \
PyGILState_STATE state = __Pyx_PyGILState_Ensure(); \
tstate = __Pyx_PyThreadState_Current; \
if (unlikely(tstate->use_tracing && tstate->c_tracefunc && $frame_cname->f_trace)) { \
ret = __Pyx_call_line_trace_func(tstate, $frame_cname, lineno); \
} \
PyGILState_Release(state); \
__Pyx_PyGILState_Release(state); \
if (unlikely(ret)) goto_error; \
} \
} else { \
......
# mode: run
# tag: coverage,trace,nogil
# tag: coverage,trace,nogil,fastgil
"""
PYTHON setup.py build_ext -i
......@@ -21,22 +21,34 @@ setup(ext_modules = cythonize([
plugins = Cython.Coverage
######## coverage_test_nogil.pyx ########
# cython: linetrace=True
######## coverage_test_nogil_fastgil.pyx ########
# cython: linetrace=True,fast_gil=True
# distutils: define_macros=CYTHON_TRACE=1 CYTHON_TRACE_NOGIL=1
include "_coverage_test_nogil.pxi"
######## coverage_test_nogil_nofastgil.pyx ########
# cython: linetrace=True,fast_gil=False
# distutils: define_macros=CYTHON_TRACE=1 CYTHON_TRACE_NOGIL=1
include "_coverage_test_nogil.pxi"
######## _coverage_test_nogil.pxi ########
# 1
# 2
# 3
cdef int func1(int a, int b) nogil: # 4
cdef int x # 5
with gil: # 6
x = 1 # 7
cdef int c = func2(a) + b # 8
return x + c # 9
# 10
# 11
cdef int func2(int a) with gil: # 12
return a * 2 # 13
# 14
# 15
def call(int a, int b): # 16
a, b = b, a # 17
with nogil: # 18
......@@ -56,11 +68,12 @@ except ImportError:
from coverage import coverage
def run_coverage():
def run_coverage(module_name):
print("Testing module %s" % module_name)
cov = coverage()
cov.start()
import coverage_test_nogil as module
module = __import__(module_name)
module_name = module.__name__
module_path = module_name + '.pyx'
assert not any(module.__file__.endswith(ext)
......@@ -69,7 +82,6 @@ def run_coverage():
assert module.call(1, 2) == (1 * 2) + 2 + 1
cov.stop()
out = StringIO()
cov.report(file=out)
#cov.report([module], file=out)
......@@ -77,15 +89,17 @@ def run_coverage():
assert any(module_path in line for line in lines), \
"'%s' not found in coverage report:\n\n%s" % (module_path, out.getvalue())
mod_file, exec_lines, excl_lines, missing_lines, _ = cov.analysis2(os.path.abspath(module_path))
assert module_path in mod_file
module_pxi = "_coverage_test_nogil.pxi"
mod_file, exec_lines, excl_lines, missing_lines, _ = cov.analysis2(os.path.abspath(module_pxi))
assert module_pxi in mod_file
executed = set(exec_lines) - set(missing_lines)
# check that everything that runs with the gil owned was executed
assert all(line in executed for line in [12, 13, 16, 17, 18, 20]), '%s / %s' % (exec_lines, missing_lines)
# check that everything that runs with the gil owned was executed (missing due to pxi: 4, 12, 16)
assert all(line in executed for line in [13, 17, 18, 20]), '%s / %s' % (exec_lines, missing_lines)
# check that everything that runs in nogil sections was executed
assert all(line in executed for line in [4, 6, 7, 8, 9]), '%s / %s' % (exec_lines, missing_lines)
assert all(line in executed for line in [6, 7, 8, 9]), '%s / %s' % (exec_lines, missing_lines)
if __name__ == '__main__':
run_coverage()
for module_name in ["coverage_test_nogil_fastgil", "coverage_test_nogil_nofastgil"]:
run_coverage(module_name)
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