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