PageRenderTime 24ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/test/test_profile.py

https://gitlab.com/unofficial-mirrors/cpython
Python | 187 lines | 158 code | 21 blank | 8 comment | 17 complexity | 3eb99b1412e7cd5c501b9566756b886c MD5 | raw file
  1. """Test suite for the profile module."""
  2. import sys
  3. import pstats
  4. import unittest
  5. import os
  6. from difflib import unified_diff
  7. from io import StringIO
  8. from test.support import TESTFN, run_unittest, unlink
  9. from contextlib import contextmanager
  10. import profile
  11. from test.profilee import testfunc, timer
  12. class ProfileTest(unittest.TestCase):
  13. profilerclass = profile.Profile
  14. profilermodule = profile
  15. methodnames = ['print_stats', 'print_callers', 'print_callees']
  16. expected_max_output = ':0(max)'
  17. def tearDown(self):
  18. unlink(TESTFN)
  19. def get_expected_output(self):
  20. return _ProfileOutput
  21. @classmethod
  22. def do_profiling(cls):
  23. results = []
  24. prof = cls.profilerclass(timer, 0.001)
  25. start_timer = timer()
  26. prof.runctx("testfunc()", globals(), locals())
  27. results.append(timer() - start_timer)
  28. for methodname in cls.methodnames:
  29. s = StringIO()
  30. stats = pstats.Stats(prof, stream=s)
  31. stats.strip_dirs().sort_stats("stdname")
  32. getattr(stats, methodname)()
  33. output = s.getvalue().splitlines()
  34. mod_name = testfunc.__module__.rsplit('.', 1)[1]
  35. # Only compare against stats originating from the test file.
  36. # Prevents outside code (e.g., the io module) from causing
  37. # unexpected output.
  38. output = [line.rstrip() for line in output if mod_name in line]
  39. results.append('\n'.join(output))
  40. return results
  41. def test_cprofile(self):
  42. results = self.do_profiling()
  43. expected = self.get_expected_output()
  44. self.assertEqual(results[0], 1000)
  45. for i, method in enumerate(self.methodnames):
  46. if results[i+1] != expected[method]:
  47. print("Stats.%s output for %s doesn't fit expectation!" %
  48. (method, self.profilerclass.__name__))
  49. print('\n'.join(unified_diff(
  50. results[i+1].split('\n'),
  51. expected[method].split('\n'))))
  52. def test_calling_conventions(self):
  53. # Issue #5330: profile and cProfile wouldn't report C functions called
  54. # with keyword arguments. We test all calling conventions.
  55. stmts = [
  56. "max([0])",
  57. "max([0], key=int)",
  58. "max([0], **dict(key=int))",
  59. "max(*([0],))",
  60. "max(*([0],), key=int)",
  61. "max(*([0],), **dict(key=int))",
  62. ]
  63. for stmt in stmts:
  64. s = StringIO()
  65. prof = self.profilerclass(timer, 0.001)
  66. prof.runctx(stmt, globals(), locals())
  67. stats = pstats.Stats(prof, stream=s)
  68. stats.print_stats()
  69. res = s.getvalue()
  70. self.assertIn(self.expected_max_output, res,
  71. "Profiling {0!r} didn't report max:\n{1}".format(stmt, res))
  72. def test_run(self):
  73. with silent():
  74. self.profilermodule.run("int('1')")
  75. self.profilermodule.run("int('1')", filename=TESTFN)
  76. self.assertTrue(os.path.exists(TESTFN))
  77. def test_runctx(self):
  78. with silent():
  79. self.profilermodule.runctx("testfunc()", globals(), locals())
  80. self.profilermodule.runctx("testfunc()", globals(), locals(),
  81. filename=TESTFN)
  82. self.assertTrue(os.path.exists(TESTFN))
  83. def regenerate_expected_output(filename, cls):
  84. filename = filename.rstrip('co')
  85. print('Regenerating %s...' % filename)
  86. results = cls.do_profiling()
  87. newfile = []
  88. with open(filename, 'r') as f:
  89. for line in f:
  90. newfile.append(line)
  91. if line.startswith('#--cut'):
  92. break
  93. with open(filename, 'w') as f:
  94. f.writelines(newfile)
  95. f.write("_ProfileOutput = {}\n")
  96. for i, method in enumerate(cls.methodnames):
  97. f.write('_ProfileOutput[%r] = """\\\n%s"""\n' % (
  98. method, results[i+1]))
  99. f.write('\nif __name__ == "__main__":\n main()\n')
  100. @contextmanager
  101. def silent():
  102. stdout = sys.stdout
  103. try:
  104. sys.stdout = StringIO()
  105. yield
  106. finally:
  107. sys.stdout = stdout
  108. def test_main():
  109. run_unittest(ProfileTest)
  110. def main():
  111. if '-r' not in sys.argv:
  112. test_main()
  113. else:
  114. regenerate_expected_output(__file__, ProfileTest)
  115. # Don't remove this comment. Everything below it is auto-generated.
  116. #--cut--------------------------------------------------------------------------
  117. _ProfileOutput = {}
  118. _ProfileOutput['print_stats'] = """\
  119. 28 27.972 0.999 27.972 0.999 profilee.py:110(__getattr__)
  120. 1 269.996 269.996 999.769 999.769 profilee.py:25(testfunc)
  121. 23/3 149.937 6.519 169.917 56.639 profilee.py:35(factorial)
  122. 20 19.980 0.999 19.980 0.999 profilee.py:48(mul)
  123. 2 39.986 19.993 599.830 299.915 profilee.py:55(helper)
  124. 4 115.984 28.996 119.964 29.991 profilee.py:73(helper1)
  125. 2 -0.006 -0.003 139.946 69.973 profilee.py:84(helper2_indirect)
  126. 8 311.976 38.997 399.912 49.989 profilee.py:88(helper2)
  127. 8 63.976 7.997 79.960 9.995 profilee.py:98(subhelper)"""
  128. _ProfileOutput['print_callers'] = """\
  129. :0(append) <- profilee.py:73(helper1)(4) 119.964
  130. :0(exc_info) <- profilee.py:73(helper1)(4) 119.964
  131. :0(hasattr) <- profilee.py:73(helper1)(4) 119.964
  132. profilee.py:88(helper2)(8) 399.912
  133. profilee.py:110(__getattr__) <- :0(hasattr)(12) 11.964
  134. profilee.py:98(subhelper)(16) 79.960
  135. profilee.py:25(testfunc) <- <string>:1(<module>)(1) 999.767
  136. profilee.py:35(factorial) <- profilee.py:25(testfunc)(1) 999.769
  137. profilee.py:35(factorial)(20) 169.917
  138. profilee.py:84(helper2_indirect)(2) 139.946
  139. profilee.py:48(mul) <- profilee.py:35(factorial)(20) 169.917
  140. profilee.py:55(helper) <- profilee.py:25(testfunc)(2) 999.769
  141. profilee.py:73(helper1) <- profilee.py:55(helper)(4) 599.830
  142. profilee.py:84(helper2_indirect) <- profilee.py:55(helper)(2) 599.830
  143. profilee.py:88(helper2) <- profilee.py:55(helper)(6) 599.830
  144. profilee.py:84(helper2_indirect)(2) 139.946
  145. profilee.py:98(subhelper) <- profilee.py:88(helper2)(8) 399.912"""
  146. _ProfileOutput['print_callees'] = """\
  147. :0(hasattr) -> profilee.py:110(__getattr__)(12) 27.972
  148. <string>:1(<module>) -> profilee.py:25(testfunc)(1) 999.769
  149. profilee.py:110(__getattr__) ->
  150. profilee.py:25(testfunc) -> profilee.py:35(factorial)(1) 169.917
  151. profilee.py:55(helper)(2) 599.830
  152. profilee.py:35(factorial) -> profilee.py:35(factorial)(20) 169.917
  153. profilee.py:48(mul)(20) 19.980
  154. profilee.py:48(mul) ->
  155. profilee.py:55(helper) -> profilee.py:73(helper1)(4) 119.964
  156. profilee.py:84(helper2_indirect)(2) 139.946
  157. profilee.py:88(helper2)(6) 399.912
  158. profilee.py:73(helper1) -> :0(append)(4) -0.004
  159. profilee.py:84(helper2_indirect) -> profilee.py:35(factorial)(2) 169.917
  160. profilee.py:88(helper2)(2) 399.912
  161. profilee.py:88(helper2) -> :0(hasattr)(8) 11.964
  162. profilee.py:98(subhelper)(8) 79.960
  163. profilee.py:98(subhelper) -> profilee.py:110(__getattr__)(16) 27.972"""
  164. if __name__ == "__main__":
  165. main()