Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
3b6ec99c
Commit
3b6ec99c
authored
Feb 20, 2015
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
enable tracing for nogil functions/sections
parent
02d86d70
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
133 additions
and
57 deletions
+133
-57
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/Code.pxd
Cython/Compiler/Code.pxd
+2
-1
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+10
-7
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+16
-18
Cython/Utility/Profile.c
Cython/Utility/Profile.c
+100
-28
tests/run/coverage_nogil.srctree
tests/run/coverage_nogil.srctree
+3
-3
No files found.
CHANGES.rst
View file @
3b6ec99c
...
@@ -11,6 +11,8 @@ Features added
...
@@ -11,6 +11,8 @@ Features added
* Support for coverage.py 4.0+ can be enabled by adding the plugin
* Support for coverage.py 4.0+ can be enabled by adding the plugin
"Cython.Coverage" to the ".coveragerc" config file.
"Cython.Coverage" to the ".coveragerc" config file.
* Tracing is supported in ``nogil`` functions/sections.
Bugs fixed
Bugs fixed
----------
----------
...
...
Cython/Compiler/Code.pxd
View file @
3b6ec99c
...
@@ -31,9 +31,10 @@ cdef class FunctionState:
...
@@ -31,9 +31,10 @@ cdef class FunctionState:
cdef
public
object
return_from_error_cleanup_label
# not used in __init__ ?
cdef
public
object
return_from_error_cleanup_label
# not used in __init__ ?
cdef
public
bint
in_try_finally
cdef
public
object
exc_vars
cdef
public
object
exc_vars
cdef
public
bint
in_try_finally
cdef
public
bint
can_trace
cdef
public
bint
can_trace
cdef
public
bint
gil_owned
cdef
public
list
temps_allocated
cdef
public
list
temps_allocated
cdef
public
dict
temps_free
cdef
public
dict
temps_free
...
...
Cython/Compiler/Code.py
View file @
3b6ec99c
...
@@ -518,6 +518,7 @@ class FunctionState(object):
...
@@ -518,6 +518,7 @@ class FunctionState(object):
self.in_try_finally = 0
self.in_try_finally = 0
self.exc_vars = None
self.exc_vars = None
self.can_trace = False
self.can_trace = False
self.gil_owned = True
self.temps_allocated = [] # of (name, type, manage_ref, static)
self.temps_allocated = [] # of (name, type, manage_ref, static)
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
...
@@ -1572,7 +1573,8 @@ class CCodeWriter(object):
...
@@ -1572,7 +1573,8 @@ class CCodeWriter(object):
if
(
self
.
funcstate
and
self
.
funcstate
.
can_trace
if
(
self
.
funcstate
and
self
.
funcstate
.
can_trace
and
self
.
globalstate
.
directives
[
'linetrace'
]):
and
self
.
globalstate
.
directives
[
'linetrace'
]):
self
.
indent
()
self
.
indent
()
self
.
write
(
'__Pyx_TraceLine(%d)
\
n
'
%
self
.
marker
[
0
])
self
.
write
(
'__Pyx_TraceLine(%d,%d)
\
n
'
%
(
self
.
marker
[
0
],
not
self
.
funcstate
.
gil_owned
))
self
.
last_marker_line
=
self
.
marker
[
0
]
self
.
last_marker_line
=
self
.
marker
[
0
]
self
.
marker
=
None
self
.
marker
=
None
...
@@ -2093,17 +2095,18 @@ class CCodeWriter(object):
...
@@ -2093,17 +2095,18 @@ class CCodeWriter(object):
self
.
globalstate
.
use_utility_code
(
self
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"WriteUnraisableException"
,
"Exceptions.c"
))
UtilityCode
.
load_cached
(
"WriteUnraisableException"
,
"Exceptions.c"
))
def
put_trace_declarations
(
self
,
codeobj
=
None
):
def
put_trace_declarations
(
self
,
codeobj
=
None
,
nogil
=
False
):
self
.
putln
(
'__Pyx_TraceDeclarations(%s
)'
%
(
codeobj
or
'NULL'
))
self
.
putln
(
'__Pyx_TraceDeclarations(%s
, %d)'
%
(
codeobj
or
'NULL'
,
nogil
))
def
put_trace_call
(
self
,
name
,
pos
):
def
put_trace_call
(
self
,
name
,
pos
,
nogil
=
False
):
self
.
putln
(
'__Pyx_TraceCall("%s", %s[%s], %s);'
%
(
name
,
Naming
.
filetable_cname
,
self
.
lookup_filename
(
pos
[
0
]),
pos
[
1
]))
self
.
putln
(
'__Pyx_TraceCall("%s", %s[%s], %s, %d);'
%
(
name
,
Naming
.
filetable_cname
,
self
.
lookup_filename
(
pos
[
0
]),
pos
[
1
],
nogil
))
def
put_trace_exception
(
self
):
def
put_trace_exception
(
self
):
self
.
putln
(
"__Pyx_TraceException();"
)
self
.
putln
(
"__Pyx_TraceException();"
)
def
put_trace_return
(
self
,
retvalue_cname
):
def
put_trace_return
(
self
,
retvalue_cname
,
nogil
=
False
):
self
.
putln
(
"__Pyx_TraceReturn(%s
);"
%
retvalue_cname
)
self
.
putln
(
"__Pyx_TraceReturn(%s
, %d);"
%
(
retvalue_cname
,
nogil
)
)
def
putln_openmp
(
self
,
string
):
def
putln_openmp
(
self
,
string
):
self
.
putln
(
"#ifdef _OPENMP"
)
self
.
putln
(
"#ifdef _OPENMP"
)
...
...
Cython/Compiler/Nodes.py
View file @
3b6ec99c
...
@@ -1698,9 +1698,6 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1698,9 +1698,6 @@ 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
(
linetrace
or
profile
)
and
lenv
.
nogil
:
warning
(
self
.
pos
,
"Cannot profile nogil function."
,
1
)
profile
=
linetrace
=
False
if
profile
or
linetrace
:
if
profile
or
linetrace
:
code
.
globalstate
.
use_utility_code
(
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"Profile"
,
"Profile.c"
))
UtilityCode
.
load_cached
(
"Profile"
,
"Profile.c"
))
...
@@ -1708,6 +1705,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1708,6 +1705,7 @@ class FuncDefNode(StatNode, BlockNode):
# Generate C code for header and body of function
# Generate C code for header and body of function
code
.
enter_cfunc_scope
()
code
.
enter_cfunc_scope
()
code
.
return_from_error_cleanup_label
=
code
.
new_label
()
code
.
return_from_error_cleanup_label
=
code
.
new_label
()
code
.
funcstate
.
gil_owned
=
not
lenv
.
nogil
# ----- Top-level constants used by this function
# ----- Top-level constants used by this function
code
.
mark_pos
(
self
.
pos
)
code
.
mark_pos
(
self
.
pos
)
...
@@ -1764,7 +1762,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1764,7 +1762,7 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
if
profile
or
linetrace
:
code_object
=
self
.
code_object
.
calculate_result_code
(
code
)
if
self
.
code_object
else
None
code_object
=
self
.
code_object
.
calculate_result_code
(
code
)
if
self
.
code_object
else
None
code
.
put_trace_declarations
(
code_object
)
code
.
put_trace_declarations
(
code_object
,
nogil
=
not
code
.
funcstate
.
gil_owned
)
# ----- Extern library function declarations
# ----- Extern library function declarations
lenv
.
generate_library_function_declarations
(
code
)
lenv
.
generate_library_function_declarations
(
code
)
...
@@ -1775,10 +1773,9 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1775,10 +1773,9 @@ class FuncDefNode(StatNode, BlockNode):
# See if we need to acquire the GIL for variable declarations, or for
# See if we need to acquire the GIL for variable declarations, or for
# refnanny only
# refnanny only
# Profiling or closures are not currently possible for cdef nogil
# Closures are not currently possible for cdef nogil functions,
# functions, but check them anyway
# but check them anyway
have_object_args
=
(
self
.
needs_closure
or
self
.
needs_outer_scope
or
have_object_args
=
self
.
needs_closure
or
self
.
needs_outer_scope
profile
or
linetrace
)
for
arg
in
lenv
.
arg_entries
:
for
arg
in
lenv
.
arg_entries
:
if
arg
.
type
.
is_pyobject
:
if
arg
.
type
.
is_pyobject
:
have_object_args
=
True
have_object_args
=
True
...
@@ -1796,6 +1793,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1796,6 +1793,7 @@ class FuncDefNode(StatNode, BlockNode):
if
acquire_gil
or
acquire_gil_for_var_decls_only
:
if
acquire_gil
or
acquire_gil_for_var_decls_only
:
code
.
put_ensure_gil
()
code
.
put_ensure_gil
()
code
.
funcstate
.
gil_owned
=
True
elif
lenv
.
nogil
and
lenv
.
has_with_gil_block
:
elif
lenv
.
nogil
and
lenv
.
has_with_gil_block
:
code
.
declare_gilstate
()
code
.
declare_gilstate
()
...
@@ -1855,7 +1853,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1855,7 +1853,7 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
if
profile
or
linetrace
:
# this looks a bit late, but if we don't get here due to a
# this looks a bit late, but if we don't get here due to a
# fatal error before hand, it's not really worth tracing
# fatal error before hand, it's not really worth tracing
code
.
put_trace_call
(
self
.
entry
.
name
,
self
.
pos
)
code
.
put_trace_call
(
self
.
entry
.
name
,
self
.
pos
,
nogil
=
not
code
.
funcstate
.
gil_owned
)
code
.
funcstate
.
can_trace
=
True
code
.
funcstate
.
can_trace
=
True
# ----- Fetch arguments
# ----- Fetch arguments
self
.
generate_argument_parsing_code
(
env
,
code
)
self
.
generate_argument_parsing_code
(
env
,
code
)
...
@@ -1874,8 +1872,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1874,8 +1872,7 @@ class FuncDefNode(StatNode, BlockNode):
# incref our arguments
# incref our arguments
elif
(
is_cdef
and
entry
.
type
.
is_memoryviewslice
and
elif
(
is_cdef
and
entry
.
type
.
is_memoryviewslice
and
len
(
entry
.
cf_assignments
)
>
1
):
len
(
entry
.
cf_assignments
)
>
1
):
code
.
put_incref_memoryviewslice
(
entry
.
cname
,
code
.
put_incref_memoryviewslice
(
entry
.
cname
,
have_gil
=
code
.
funcstate
.
gil_owned
)
have_gil
=
not
lenv
.
nogil
)
for
entry
in
lenv
.
var_entries
:
for
entry
in
lenv
.
var_entries
:
if
entry
.
is_arg
and
len
(
entry
.
cf_assignments
)
>
1
:
if
entry
.
is_arg
and
len
(
entry
.
cf_assignments
)
>
1
:
code
.
put_var_incref
(
entry
)
code
.
put_var_incref
(
entry
)
...
@@ -1894,6 +1891,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -1894,6 +1891,7 @@ class FuncDefNode(StatNode, BlockNode):
if
acquire_gil_for_var_decls_only
:
if
acquire_gil_for_var_decls_only
:
code
.
put_release_ensured_gil
()
code
.
put_release_ensured_gil
()
code
.
funcstate
.
gil_owned
=
False
# -------------------------
# -------------------------
# ----- Function body -----
# ----- Function body -----
...
@@ -2054,9 +2052,9 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -2054,9 +2052,9 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
if
profile
or
linetrace
:
code
.
funcstate
.
can_trace
=
False
code
.
funcstate
.
can_trace
=
False
if
self
.
return_type
.
is_pyobject
:
if
self
.
return_type
.
is_pyobject
:
code
.
put_trace_return
(
Naming
.
retval_cname
)
code
.
put_trace_return
(
Naming
.
retval_cname
,
nogil
=
not
code
.
funcstate
.
gil_owned
)
else
:
else
:
code
.
put_trace_return
(
"Py_None"
)
code
.
put_trace_return
(
"Py_None"
,
nogil
=
not
code
.
funcstate
.
gil_owned
)
if
not
lenv
.
nogil
:
if
not
lenv
.
nogil
:
# GIL holding function
# GIL holding function
...
@@ -2065,6 +2063,7 @@ class FuncDefNode(StatNode, BlockNode):
...
@@ -2065,6 +2063,7 @@ class FuncDefNode(StatNode, BlockNode):
if
acquire_gil
or
(
lenv
.
nogil
and
lenv
.
has_with_gil_block
):
if
acquire_gil
or
(
lenv
.
nogil
and
lenv
.
has_with_gil_block
):
# release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
# release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
code
.
put_release_ensured_gil
()
code
.
put_release_ensured_gil
()
code
.
funcstate
.
gil_owned
=
False
if
not
self
.
return_type
.
is_void
:
if
not
self
.
return_type
.
is_void
:
code
.
putln
(
"return %s;"
%
Naming
.
retval_cname
)
code
.
putln
(
"return %s;"
%
Naming
.
retval_cname
)
...
@@ -7073,21 +7072,20 @@ class GILStatNode(NogilTryFinallyStatNode):
...
@@ -7073,21 +7072,20 @@ class GILStatNode(NogilTryFinallyStatNode):
else
:
else
:
variable
=
None
variable
=
None
old_
trace_config
=
code
.
funcstate
.
can_trace
old_
gil_config
=
code
.
funcstate
.
gil_owned
if
self
.
state
==
'gil'
:
if
self
.
state
==
'gil'
:
code
.
put_ensure_gil
(
variable
=
variable
)
code
.
put_ensure_gil
(
variable
=
variable
)
# FIXME: not that easy, tracing may not be possible at all here
code
.
funcstate
.
gil_owned
=
True
#code.funcstate.can_trace = True
else
:
else
:
code
.
put_release_gil
(
variable
=
variable
)
code
.
put_release_gil
(
variable
=
variable
)
code
.
funcstate
.
can_trace
=
False
code
.
funcstate
.
gil_owned
=
False
TryFinallyStatNode
.
generate_execution_code
(
self
,
code
)
TryFinallyStatNode
.
generate_execution_code
(
self
,
code
)
if
self
.
state_temp
:
if
self
.
state_temp
:
self
.
state_temp
.
release
(
code
)
self
.
state_temp
.
release
(
code
)
code
.
funcstate
.
can_trace
=
old_trace
_config
code
.
funcstate
.
gil_owned
=
old_gil
_config
code
.
end_block
()
code
.
end_block
()
...
...
Cython/Utility/Profile.c
View file @
3b6ec99c
This diff is collapsed.
Click to expand it.
tests/run/coverage_nogil.srctree
View file @
3b6ec99c
...
@@ -23,7 +23,7 @@ plugins = Cython.Coverage
...
@@ -23,7 +23,7 @@ plugins = Cython.Coverage
######## coverage_test_nogil.pyx ########
######## coverage_test_nogil.pyx ########
# cython: linetrace=True
# cython: linetrace=True
# distutils: define_macros=CYTHON_TRACE=1
# distutils: define_macros=CYTHON_TRACE=1
CYTHON_TRACE_NOGIL=1
cdef int func1(int a, int b) nogil:
cdef int func1(int a, int b) nogil:
cdef int x # 5
cdef int x # 5
...
@@ -85,8 +85,8 @@ def run_coverage(module):
...
@@ -85,8 +85,8 @@ def run_coverage(module):
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
assert all(line in executed for line in [13, 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)
# c
urrently, we do not trace nogil code lines, but that should eventually be implemen
ted
# c
heck that everything that runs in nogil sections was execu
ted
# we also don't trace 'with gil' blocks in 'nogil' functions
assert all(line in executed for line in [6, 7, 8, 9]), '%s / %s' % (exec_lines, missing_lines)
if __name__ == '__main__':
if __name__ == '__main__':
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment