3
# cython: profile = True
4
# distutils: define_macros = CYTHON_TRACE_NOGIL=1
7
>>> import os, tempfile, cProfile as profile, pstats
8
>>> statsfile = tempfile.mkstemp()[1]
9
>>> profile.runctx("test_profile(100)", locals(), globals(), statsfile)
10
>>> s = pstats.Stats(statsfile)
11
>>> short_stats = dict([(k[2], v[1]) for k,v in s.stats.items()])
12
>>> short_stats['f_def']
14
>>> short_stats['f_cdef']
16
>>> short_stats['f_cpdef']
18
>>> short_stats['f_inline']
20
>>> short_stats['f_inline_prof']
23
... assert short_stats['f_noprof']
27
... assert not COMPILED
29
>>> short_stats['f_raise']
32
>>> short_stats['withgil_prof']
35
... assert short_stats['withgil_noprof']
39
... assert not COMPILED
41
>>> short_stats['nogil_prof']
45
... assert short_stats['nogil_noprof']
49
... assert not COMPILED
51
>>> short_stats['m_def']
53
>>> short_stats['m_cdef']
56
>>> short_stats['m_cpdef']
60
... os.unlink(statsfile)
64
>>> sorted(list(callees(s, 'test_profile')) + (
65
... ['f_noprof', 'nogil_noprof', 'withgil_noprof'] if COMPILED else [])) #doctest: +NORMALIZE_WHITESPACE
66
['f_cdef', 'f_cpdef', 'f_def',
67
'f_inline', 'f_inline_prof',
70
'm_cdef', 'm_cpdef', 'm_def',
71
'nogil_noprof', 'nogil_prof',
72
'withgil_noprof', 'withgil_prof']
74
>>> profile.runctx("test_generators()", locals(), globals(), statsfile)
75
>>> s = pstats.Stats(statsfile)
76
>>> short_stats = dict([(k[2], v[1]) for k,v in s.stats.items()])
77
>>> short_stats['generator']
80
>>> short_stats['generator_exception']
83
>>> sorted(callees(s, 'test_generators'))
84
['call_generator', 'call_generator_exception']
86
>>> list(callees(s, 'call_generator'))
89
>>> list(callees(s, 'generator'))
92
>>> list(callees(s, 'generator_exception'))
95
>>> def python_generator():
98
>>> def call_python_generator():
99
... list(python_generator())
101
>>> profile.runctx("call_python_generator()", locals(), globals(), statsfile)
102
>>> python_stats = pstats.Stats(statsfile)
103
>>> python_stats_dict = dict([(k[2], v[1]) for k,v in python_stats.stats.items()])
105
>>> profile.runctx("call_generator()", locals(), globals(), statsfile)
106
>>> cython_stats = pstats.Stats(statsfile)
107
>>> cython_stats_dict = dict([(k[2], v[1]) for k,v in cython_stats.stats.items()])
109
>>> python_stats_dict['python_generator'] == cython_stats_dict['generator'] \
110
or (python_stats_dict['python_generator'], cython_stats_dict['generator'])
114
... os.unlink(statsfile)
121
COMPILED = cython.compiled
125
# python3 -c 'import pstats_profile_test_py as pp; pp.print_event_traces()' > pytrace.log
126
# Then compile the module and run:
127
# python3 -c 'import pstats_profile_test_py as pp; pp.print_event_traces()' > cytrace.log
128
# Compare the two logs.
130
@cython.profile(False)
131
@cython.linetrace(False)
132
def print_event_traces():
133
trace_events(test_profile)
134
trace_events(test_generators)
137
def trace_events(func=None):
141
last_code_obj = [None]
143
@cython.profile(False)
144
@cython.linetrace(False)
145
def trace_function(frame, event, arg):
147
code_obj = frame.f_code
148
if last_code_obj[0] is not code_obj:
149
last_code_obj[0] = code_obj
151
print(f"{event:20}, {code_obj.co_name}:{code_obj.co_firstlineno}, {frame.f_lineno}, {arg}")
152
except Exception as exc:
155
traceback.print_stack()
157
return trace_function
161
sys.settrace(trace_function)
162
sys.setprofile(trace_function)
171
def callees(pstats, target_caller):
172
pstats.calc_callees()
173
for (_, _, caller), callees in pstats.all_callees.items():
174
if caller == target_caller:
175
for (file, line, callee) in callees.keys():
176
if 'pstats_profile_test' in file:
180
def test_profile(N: cython.long):
188
n += cython.cast(object, f_cpdef)(i)
190
n += f_inline_prof(i)
194
n += withgil_noprof(i)
197
n += cython.cast(object, a).m_def(i)
199
n += cython.cast(object, a).m_cpdef(i)
207
def f_def(a: cython.long):
211
def f_cdef(a: cython.long) -> cython.long:
215
def f_cpdef(a: cython.long) -> cython.long:
220
def f_inline(a: cython.long) -> cython.long:
226
def f_inline_prof(a: cython.long) -> cython.long:
229
@cython.profile(False)
232
def f_noprof(a: cython.long) -> cython.long:
238
def f_raise(a: cython.long) -> cython.long:
241
@cython.profile(False)
244
def withgil_noprof(a: cython.long) -> cython.long:
250
def withgil_prof(a: cython.long) -> cython.long:
253
@cython.profile(False)
256
def nogil_noprof(a: cython.long) -> cython.long:
262
def nogil_prof(a: cython.long) -> cython.long:
268
def m_def(self, a: cython.long):
271
def m_cpdef(self, a: cython.long):
274
def m_cdef(self, a: cython.long):
278
def test_generators(_=None):
280
call_generator_exception()
289
def call_generator_exception():
291
list(generator_exception())
295
def generator_exception():
299
# Generator expressions are inlined in Python 3.12 and no longer show uo in profiles.
300
#def generator_expr():
301
# e = (x for x in range(10))