cython

Форк
0
/
pstats_profile_test_py.py 
302 строки · 7.1 Кб
1
# mode: run
2
# tag: pstats, pure3.6
3
# cython: profile = True
4
# distutils: define_macros = CYTHON_TRACE_NOGIL=1
5

6
u"""
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']
13
    100
14
    >>> short_stats['f_cdef']
15
    100
16
    >>> short_stats['f_cpdef']
17
    200
18
    >>> short_stats['f_inline']
19
    100
20
    >>> short_stats['f_inline_prof']
21
    100
22
    >>> try:
23
    ...     assert short_stats['f_noprof']
24
    ... except KeyError:
25
    ...     assert COMPILED
26
    ... else:
27
    ...     assert not COMPILED
28

29
    >>> short_stats['f_raise']
30
    100
31

32
    >>> short_stats['withgil_prof']
33
    100
34
    >>> try:
35
    ...     assert short_stats['withgil_noprof']
36
    ... except KeyError:
37
    ...     assert COMPILED
38
    ... else:
39
    ...     assert not COMPILED
40

41
    >>> short_stats['nogil_prof']
42
    100
43

44
    >>> try:
45
    ...     assert short_stats['nogil_noprof']
46
    ... except KeyError:
47
    ...     assert COMPILED
48
    ... else:
49
    ...     assert not COMPILED
50

51
    >>> short_stats['m_def']
52
    200
53
    >>> short_stats['m_cdef']
54
    100
55

56
    >>> short_stats['m_cpdef']
57
    200
58

59
    >>> try:
60
    ...    os.unlink(statsfile)
61
    ... except:
62
    ...    pass
63

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',
68
     'f_noprof',
69
     'f_raise',
70
     'm_cdef', 'm_cpdef', 'm_def',
71
     'nogil_noprof', 'nogil_prof',
72
     'withgil_noprof', 'withgil_prof']
73

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']
78
    3
79

80
    >>> short_stats['generator_exception']
81
    2
82

83
    >>> sorted(callees(s, 'test_generators'))
84
    ['call_generator', 'call_generator_exception']
85

86
    >>> list(callees(s, 'call_generator'))
87
    ['generator']
88

89
    >>> list(callees(s, 'generator'))
90
    []
91

92
    >>> list(callees(s, 'generator_exception'))
93
    []
94

95
    >>> def python_generator():
96
    ...   yield 1
97
    ...   yield 2
98
    >>> def call_python_generator():
99
    ...   list(python_generator())
100

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()])
104

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()])
108

109
    >>> python_stats_dict['python_generator'] == cython_stats_dict['generator']  \
110
             or  (python_stats_dict['python_generator'], cython_stats_dict['generator'])
111
    True
112

113
    >>> try:
114
    ...    os.unlink(statsfile)
115
    ... except:
116
    ...    pass
117
"""
118

119
import cython
120

121
COMPILED = cython.compiled
122

123
####### Debug helper
124
# Use like:
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.
129

130
@cython.profile(False)
131
@cython.linetrace(False)
132
def print_event_traces():
133
    trace_events(test_profile)
134
    trace_events(test_generators)
135

136

137
def trace_events(func=None):
138
    if func is None:
139
        func = test_profile
140

141
    last_code_obj = [None]
142

143
    @cython.profile(False)
144
    @cython.linetrace(False)
145
    def trace_function(frame, event, arg):
146
        try:
147
            code_obj = frame.f_code
148
            if last_code_obj[0] is not code_obj:
149
                last_code_obj[0] = code_obj
150
                print('')
151
            print(f"{event:20}, {code_obj.co_name}:{code_obj.co_firstlineno}, {frame.f_lineno}, {arg}")
152
        except Exception as exc:
153
            print("EXC:", exc)
154
            import traceback
155
            traceback.print_stack()
156

157
        return trace_function
158

159
    import sys
160
    try:
161
        sys.settrace(trace_function)
162
        sys.setprofile(trace_function)
163
        func(1)
164
    finally:
165
        sys.setprofile(None)
166
        sys.settrace(None)
167

168

169
####### Test code
170

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:
177
                    yield callee
178

179

180
def test_profile(N: cython.long):
181
    i: cython.long
182
    n: cython.long = 0
183
    a: A = A()
184
    for i in range(N):
185
        n += f_def(i)
186
        n += f_cdef(i)
187
        n += f_cpdef(i)
188
        n += cython.cast(object, f_cpdef)(i)
189
        n += f_inline(i)
190
        n += f_inline_prof(i)
191
        n += f_noprof(i)
192
        n += nogil_noprof(i)
193
        n += nogil_prof(i)
194
        n += withgil_noprof(i)
195
        n += withgil_prof(i)
196
        n += a.m_def(i)
197
        n += cython.cast(object, a).m_def(i)
198
        n += a.m_cpdef(i)
199
        n += cython.cast(object, a).m_cpdef(i)
200
        n += a.m_cdef(i)
201
        try:
202
            n += f_raise(i+2)
203
        except RuntimeError:
204
            pass
205
    return n
206

207
def f_def(a: cython.long):
208
    return a
209

210
@cython.cfunc
211
def f_cdef(a: cython.long) -> cython.long:
212
    return a
213

214
@cython.ccall
215
def f_cpdef(a: cython.long) -> cython.long:
216
    return a
217

218
@cython.inline
219
@cython.cfunc
220
def f_inline(a: cython.long) -> cython.long:
221
    return a
222

223
@cython.profile(True)
224
@cython.inline
225
@cython.cfunc
226
def f_inline_prof(a: cython.long) -> cython.long:
227
    return a
228

229
@cython.profile(False)
230
@cython.inline
231
@cython.cfunc
232
def f_noprof(a: cython.long) -> cython.long:
233
    return a
234

235
@cython.inline
236
@cython.exceptval(-2)
237
@cython.cfunc
238
def f_raise(a: cython.long) -> cython.long:
239
    raise RuntimeError
240

241
@cython.profile(False)
242
@cython.with_gil
243
@cython.cfunc
244
def withgil_noprof(a: cython.long) -> cython.long:
245
    return (a)
246

247
@cython.profile(True)
248
@cython.with_gil
249
@cython.cfunc
250
def withgil_prof(a: cython.long) -> cython.long:
251
    return (a)
252

253
@cython.profile(False)
254
@cython.nogil
255
@cython.cfunc
256
def nogil_noprof(a: cython.long) -> cython.long:
257
    return a
258

259
@cython.profile(True)
260
@cython.nogil
261
@cython.cfunc
262
def nogil_prof(a: cython.long) -> cython.long:
263
    return a
264

265

266
@cython.cclass
267
class A(object):
268
    def m_def(self, a: cython.long):
269
        return a
270
    @cython.ccall
271
    def m_cpdef(self, a: cython.long):
272
        return a
273
    @cython.cfunc
274
    def m_cdef(self, a: cython.long):
275
        return a
276

277

278
def test_generators(_=None):
279
    call_generator()
280
    call_generator_exception()
281

282
def call_generator():
283
    list(generator())
284

285
def generator():
286
    yield 1
287
    yield 2
288

289
def call_generator_exception():
290
    try:
291
        list(generator_exception())
292
    except ValueError:
293
        pass
294

295
def generator_exception():
296
    yield 1
297
    raise ValueError(2)
298

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))
302
#    return sum(e)
303

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.