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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
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
* Support for coverage.py 4.0+ can be enabled by adding the plugin
"Cython.Coverage" to the ".coveragerc" config file.
* Tracing is supported in ``nogil`` functions/sections.
Bugs fixed
----------
...
...
Cython/Compiler/Code.pxd
View file @
3b6ec99c
...
...
@@ -31,9 +31,10 @@ cdef class FunctionState:
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
bint
in_try_finally
cdef
public
bint
can_trace
cdef
public
bint
gil_owned
cdef
public
list
temps_allocated
cdef
public
dict
temps_free
...
...
Cython/Compiler/Code.py
View file @
3b6ec99c
...
...
@@ -518,6 +518,7 @@ class FunctionState(object):
self.in_try_finally = 0
self.exc_vars = None
self.can_trace = False
self.gil_owned = True
self.temps_allocated = [] # of (name, type, manage_ref, static)
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
...
...
@@ -1572,7 +1573,8 @@ class CCodeWriter(object):
if
(
self
.
funcstate
and
self
.
funcstate
.
can_trace
and
self
.
globalstate
.
directives
[
'linetrace'
]):
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
.
marker
=
None
...
...
@@ -2093,17 +2095,18 @@ class CCodeWriter(object):
self
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"WriteUnraisableException"
,
"Exceptions.c"
))
def
put_trace_declarations
(
self
,
codeobj
=
None
):
self
.
putln
(
'__Pyx_TraceDeclarations(%s
)'
%
(
codeobj
or
'NULL'
))
def
put_trace_declarations
(
self
,
codeobj
=
None
,
nogil
=
False
):
self
.
putln
(
'__Pyx_TraceDeclarations(%s
, %d)'
%
(
codeobj
or
'NULL'
,
nogil
))
def
put_trace_call
(
self
,
name
,
pos
):
self
.
putln
(
'__Pyx_TraceCall("%s", %s[%s], %s);'
%
(
name
,
Naming
.
filetable_cname
,
self
.
lookup_filename
(
pos
[
0
]),
pos
[
1
]))
def
put_trace_call
(
self
,
name
,
pos
,
nogil
=
False
):
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
):
self
.
putln
(
"__Pyx_TraceException();"
)
def
put_trace_return
(
self
,
retvalue_cname
):
self
.
putln
(
"__Pyx_TraceReturn(%s
);"
%
retvalue_cname
)
def
put_trace_return
(
self
,
retvalue_cname
,
nogil
=
False
):
self
.
putln
(
"__Pyx_TraceReturn(%s
, %d);"
%
(
retvalue_cname
,
nogil
)
)
def
putln_openmp
(
self
,
string
):
self
.
putln
(
"#ifdef _OPENMP"
)
...
...
Cython/Compiler/Nodes.py
View file @
3b6ec99c
...
...
@@ -1698,9 +1698,6 @@ class FuncDefNode(StatNode, BlockNode):
profile
=
code
.
globalstate
.
directives
[
'profile'
]
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
:
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"Profile"
,
"Profile.c"
))
...
...
@@ -1708,6 +1705,7 @@ class FuncDefNode(StatNode, BlockNode):
# Generate C code for header and body of function
code
.
enter_cfunc_scope
()
code
.
return_from_error_cleanup_label
=
code
.
new_label
()
code
.
funcstate
.
gil_owned
=
not
lenv
.
nogil
# ----- Top-level constants used by this function
code
.
mark_pos
(
self
.
pos
)
...
...
@@ -1764,7 +1762,7 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
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
lenv
.
generate_library_function_declarations
(
code
)
...
...
@@ -1775,10 +1773,9 @@ class FuncDefNode(StatNode, BlockNode):
# See if we need to acquire the GIL for variable declarations, or for
# refnanny only
# Profiling or closures are not currently possible for cdef nogil
# functions, but check them anyway
have_object_args
=
(
self
.
needs_closure
or
self
.
needs_outer_scope
or
profile
or
linetrace
)
# Closures are not currently possible for cdef nogil functions,
# but check them anyway
have_object_args
=
self
.
needs_closure
or
self
.
needs_outer_scope
for
arg
in
lenv
.
arg_entries
:
if
arg
.
type
.
is_pyobject
:
have_object_args
=
True
...
...
@@ -1796,6 +1793,7 @@ class FuncDefNode(StatNode, BlockNode):
if
acquire_gil
or
acquire_gil_for_var_decls_only
:
code
.
put_ensure_gil
()
code
.
funcstate
.
gil_owned
=
True
elif
lenv
.
nogil
and
lenv
.
has_with_gil_block
:
code
.
declare_gilstate
()
...
...
@@ -1855,7 +1853,7 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
# 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
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
# ----- Fetch arguments
self
.
generate_argument_parsing_code
(
env
,
code
)
...
...
@@ -1874,8 +1872,7 @@ class FuncDefNode(StatNode, BlockNode):
# incref our arguments
elif
(
is_cdef
and
entry
.
type
.
is_memoryviewslice
and
len
(
entry
.
cf_assignments
)
>
1
):
code
.
put_incref_memoryviewslice
(
entry
.
cname
,
have_gil
=
not
lenv
.
nogil
)
code
.
put_incref_memoryviewslice
(
entry
.
cname
,
have_gil
=
code
.
funcstate
.
gil_owned
)
for
entry
in
lenv
.
var_entries
:
if
entry
.
is_arg
and
len
(
entry
.
cf_assignments
)
>
1
:
code
.
put_var_incref
(
entry
)
...
...
@@ -1894,6 +1891,7 @@ class FuncDefNode(StatNode, BlockNode):
if
acquire_gil_for_var_decls_only
:
code
.
put_release_ensured_gil
()
code
.
funcstate
.
gil_owned
=
False
# -------------------------
# ----- Function body -----
...
...
@@ -2054,9 +2052,9 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
code
.
funcstate
.
can_trace
=
False
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
:
code
.
put_trace_return
(
"Py_None"
)
code
.
put_trace_return
(
"Py_None"
,
nogil
=
not
code
.
funcstate
.
gil_owned
)
if
not
lenv
.
nogil
:
# GIL holding function
...
...
@@ -2065,6 +2063,7 @@ class FuncDefNode(StatNode, BlockNode):
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)
code
.
put_release_ensured_gil
()
code
.
funcstate
.
gil_owned
=
False
if
not
self
.
return_type
.
is_void
:
code
.
putln
(
"return %s;"
%
Naming
.
retval_cname
)
...
...
@@ -7073,21 +7072,20 @@ class GILStatNode(NogilTryFinallyStatNode):
else
:
variable
=
None
old_
trace_config
=
code
.
funcstate
.
can_trace
old_
gil_config
=
code
.
funcstate
.
gil_owned
if
self
.
state
==
'gil'
:
code
.
put_ensure_gil
(
variable
=
variable
)
# FIXME: not that easy, tracing may not be possible at all here
#code.funcstate.can_trace = True
code
.
funcstate
.
gil_owned
=
True
else
:
code
.
put_release_gil
(
variable
=
variable
)
code
.
funcstate
.
can_trace
=
False
code
.
funcstate
.
gil_owned
=
False
TryFinallyStatNode
.
generate_execution_code
(
self
,
code
)
if
self
.
state_temp
:
self
.
state_temp
.
release
(
code
)
code
.
funcstate
.
can_trace
=
old_trace
_config
code
.
funcstate
.
gil_owned
=
old_gil
_config
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
######## coverage_test_nogil.pyx ########
# 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 x # 5
...
...
@@ -85,8 +85,8 @@ def run_coverage(module):
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 [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
# we also don't trace 'with gil' blocks in 'nogil' functions
# c
heck that everything that runs in nogil sections was execu
ted
assert all(line in executed for line in [6, 7, 8, 9]), '%s / %s' % (exec_lines, missing_lines)
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