PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/_lsprof/test/test_cprofile.py

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