PageRenderTime 40ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

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

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