1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
|
class AppTestCProfile(object):
spaceconfig = {
"usemodules": ['_lsprof', 'time'],
}
def setup_class(cls):
cls.w_expected_output = cls.space.wrap(expected_output)
cls.w_file = cls.space.wrap(__file__)
def test_repr(self):
import _lsprof
assert repr(_lsprof.Profiler) == "<class '_lsprof.Profiler'>"
def test_builtins(self):
import _lsprof
prof = _lsprof.Profiler()
lst = []
prof.enable()
lst.append(len(lst))
prof.disable()
stats = prof.getstats()
expected = (
"<built-in function len>",
"<method 'append' of 'list' objects>",
"<method 'disable' of '_lsprof.Profiler' objects>",
)
for entry in stats:
assert entry.code in expected
def test_builtins_callers(self):
import _lsprof
prof = _lsprof.Profiler(subcalls=True)
lst = []
def f1():
lst.append(len(lst))
prof.enable(subcalls=True)
f1()
prof.disable()
stats = prof.getstats()
expected = (
"<built-in function len>",
"<method 'append' of 'list' objects>",
)
by_id = set()
for entry in stats:
if entry.code == f1.__code__:
assert len(entry.calls) == 2
for subentry in entry.calls:
assert subentry.code in expected
by_id.add(id(subentry.code))
elif entry.code in expected:
by_id.add(id(entry.code))
# :-( cProfile.py relies on the id() of the strings...
assert len(by_id) == len(expected)
def test_direct(self):
import _lsprof
def getticks():
return len(ticks)
prof = _lsprof.Profiler(getticks, 0.25, True, False)
ticks = []
def bar(m):
ticks.append(1)
if m == 1:
foo(42)
ticks.append(1)
def spam(m):
bar(m)
def foo(n):
bar(n)
ticks.append(1)
bar(n+1)
ticks.append(1)
spam(n+2)
prof.enable()
foo(0)
prof.disable()
assert len(ticks) == 16
stats = prof.getstats()
entries = {}
for entry in stats:
assert hasattr(entry.code, 'co_name')
entries[entry.code.co_name] = entry
efoo = entries['foo']
assert efoo.callcount == 2
assert efoo.reccallcount == 1
assert efoo.inlinetime == 1.0
assert efoo.totaltime == 4.0
assert len(efoo.calls) == 2
ebar = entries['bar']
assert ebar.callcount == 6
assert ebar.reccallcount == 3
assert ebar.inlinetime == 3.0
assert ebar.totaltime == 3.5
assert len(ebar.calls) == 1
espam = entries['spam']
assert espam.callcount == 2
assert espam.reccallcount == 0
assert espam.inlinetime == 0.0
assert espam.totaltime == 1.0
assert len(espam.calls) == 1
foo2spam, foo2bar = efoo.calls
if foo2bar.code.co_name == 'spam':
foo2bar, foo2spam = foo2spam, foo2bar
assert foo2bar.code.co_name == 'bar'
assert foo2bar.callcount == 4
assert foo2bar.reccallcount == 2
assert foo2bar.inlinetime == 2.0
assert foo2bar.totaltime == 3.0
assert foo2spam.code.co_name == 'spam'
assert foo2spam.callcount == 2
assert foo2spam.reccallcount == 0
assert foo2spam.inlinetime == 0.0
assert foo2spam.totaltime == 1.0
bar2foo, = ebar.calls
assert bar2foo.code.co_name == 'foo'
assert bar2foo.callcount == 1
assert bar2foo.reccallcount == 0
assert bar2foo.inlinetime == 0.5
assert bar2foo.totaltime == 2.0
spam2bar, = espam.calls
assert spam2bar.code.co_name == 'bar'
assert spam2bar.callcount == 2
assert spam2bar.reccallcount == 0
assert spam2bar.inlinetime == 1.0
assert spam2bar.totaltime == 1.0
def test_scale_of_result(self):
import _lsprof, time
prof = _lsprof.Profiler()
def foo(n):
t = time.time()
while abs(t - time.time()) < 1.0:
pass # busy-wait for 1 second
def bar(n):
foo(n)
prof.enable()
bar(0)
prof.disable()
stats = prof.getstats()
entries = {}
for entry in stats:
entries[entry.code] = entry
efoo = entries[foo.__code__]
ebar = entries[bar.__code__]
assert 0.9 < efoo.totaltime < 2.9
# --- cannot test .inlinetime, because it does not include
# --- the time spent doing the call to time.time()
#assert 0.9 < efoo.inlinetime < 2.9
for subentry in ebar.calls:
assert 0.9 < subentry.totaltime < 2.9
#assert 0.9 < subentry.inlinetime < 2.9
def test_builtin_exception(self):
import math
import _lsprof
prof = _lsprof.Profiler()
prof.enable()
try:
math.sqrt("a")
except TypeError:
pass
prof.disable()
stats = prof.getstats()
assert len(stats) == 2
def test_use_cprofile(self):
import sys, os
# XXX this is evil trickery to walk around the fact that we don't
# have __file__ at app-level here
sys.path.insert(0, os.path.dirname(self.file))
try:
import re
from cProfile import Profile
from profilee import testfunc, timer
methodnames = ['print_stats', 'print_callers', 'print_callees']
def do_profiling(cls):
results = []
prof = cls(timer, 0.001)
start_timer = timer()
prof.runctx("testfunc()", {'testfunc':testfunc}, locals())
results.append(timer() - start_timer)
for methodname in methodnames:
import pstats
from io import StringIO
s = StringIO()
stats = pstats.Stats(prof, stream=s)
stats.strip_dirs().sort_stats("stdname")
getattr(stats, methodname)()
results.append(s.getvalue())
return results, prof
res, prof = do_profiling(Profile)
assert res[0] == 1000
for i, method in enumerate(methodnames):
got = res[i + 1]
expected = self.expected_output[method]
patterns = expected.splitlines()
lines = set(got.splitlines())
lines.remove('') # ignore blank lines
for pattern in patterns:
if not pattern:
continue # ignore blank lines
pattern = pattern.replace('(', '\\(')
pattern = pattern.replace(')', '\\)')
pattern = pattern.replace('?', '\\?')
pattern = pattern.replace(r'\\?', '?')
pattern = pattern.replace(r'\\(', '(')
pattern = pattern.replace(r'\\)', ')')
repattern = re.compile('^' + pattern + '$')
for line in lines:
if repattern.match(line):
lines.remove(line)
break
else:
print('NOT FOUND: %s' % pattern.rstrip('\n'))
print('--- GOT ---')
print(got)
print('')
print('--- EXPECTED ---')
print(expected)
assert False
assert not lines
finally:
sys.path.pop(0)
expected_output = {}
expected_output['print_stats'] = """\
119 function calls (99 primitive calls) in 1.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.000 1.000 <string>:1(<module>)
28 0.028 0.001 0.028 0.001 profilee.py:110(__getattr__)
1 0.270 0.270 1.000 1.000 profilee.py:25(testfunc)
23/3 0.150 0.007 0.170 0.057 profilee.py:35(factorial)
20 0.020 0.001 0.020 0.001 profilee.py:48(mul)
2 0.040 0.020 0.600 0.300 profilee.py:55(helper)
4 0.116 0.029 0.120 0.030 profilee.py:73(helper1)
2 0.000 0.000 0.140 0.070 profilee.py:84(helper2_indirect)
8 0.312 0.039 0.400 0.050 profilee.py:88(helper2)
8 0.064 0.008 0.080 0.010 profilee.py:98(subhelper)
1 0.000 0.000 1.000 1.000 {built-in function exec}
12 0.000 0.000 0.012 0.001 {built-in function hasattr}
4 0.000 0.000 0.000 0.000 {built-in function sys.exc_info}
4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
"""
expected_output['print_callers'] = """\
Ordered by: standard name
Function was called by...
ncalls tottime cumtime
<string>:1(<module>) <- 1 0.000 1.000 {built-in function exec}
profilee.py:110(__getattr__) <- 16 0.016 0.016 profilee.py:98(subhelper)
12 0.012 0.012 {built-in function hasattr}
profilee.py:25(testfunc) <- 1 0.270 1.000 <string>:1(<module>)
profilee.py:35(factorial) <- 1 0.014 0.130 profilee.py:25(testfunc)
20/3 0.130 0.147 profilee.py:35(factorial)
2 0.006 0.040 profilee.py:84(helper2_indirect)
profilee.py:48(mul) <- 20 0.020 0.020 profilee.py:35(factorial)
profilee.py:55(helper) <- 2 0.040 0.600 profilee.py:25(testfunc)
profilee.py:73(helper1) <- 4 0.116 0.120 profilee.py:55(helper)
profilee.py:84(helper2_indirect) <- 2 0.000 0.140 profilee.py:55(helper)
profilee.py:88(helper2) <- 6 0.234 0.300 profilee.py:55(helper)
2 0.078 0.100 profilee.py:84(helper2_indirect)
profilee.py:98(subhelper) <- 8 0.064 0.080 profilee.py:88(helper2)
{built-in function exec} <-
{built-in function hasattr} <- 4 0.000 0.004 profilee.py:73(helper1)
8 0.000 0.008 profilee.py:88(helper2)
{method 'append' of 'list' objects} <- 4 0.000 0.000 profilee.py:73(helper1)
{method 'disable' of '_lsprof.Profiler' objects} <-
{built-in function sys.exc_info} <- 4 0.000 0.000 profilee.py:73(helper1)
"""
expected_output['print_callees'] = """\
Ordered by: standard name
Function called...
ncalls tottime cumtime
<string>:1(<module>) -> 1 0.270 1.000 profilee.py:25(testfunc)
profilee.py:110(__getattr__) ->
profilee.py:25(testfunc) -> 1 0.014 0.130 profilee.py:35(factorial)
2 0.040 0.600 profilee.py:55(helper)
profilee.py:35(factorial) -> 20/3 0.130 0.147 profilee.py:35(factorial)
20 0.020 0.020 profilee.py:48(mul)
profilee.py:48(mul) ->
profilee.py:55(helper) -> 4 0.116 0.120 profilee.py:73(helper1)
2 0.000 0.140 profilee.py:84(helper2_indirect)
6 0.234 0.300 profilee.py:88(helper2)
profilee.py:73(helper1) -> 4 0.000 0.004 {built-in function hasattr}
4 0.000 0.000 {method 'append' of 'list' objects}
4 0.000 0.000 {built-in function sys.exc_info}
profilee.py:84(helper2_indirect) -> 2 0.006 0.040 profilee.py:35(factorial)
2 0.078 0.100 profilee.py:88(helper2)
profilee.py:88(helper2) -> 8 0.064 0.080 profilee.py:98(subhelper)
8 0.000 0.008 {built-in function hasattr}
profilee.py:98(subhelper) -> 16 0.016 0.016 profilee.py:110(__getattr__)
{built-in function exec} -> 1 0.000 1.000 <string>:1(<module>)
{built-in function hasattr} -> 12 0.012 0.012 profilee.py:110(__getattr__)
{method 'append' of 'list' objects} ->
{method 'disable' of '_lsprof.Profiler' objects} ->
{built-in function sys.exc_info} ->
"""
|