perftest_unittest.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. # Copyright (C) 2012 Google Inc. All rights reserved.
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions are
  5. # met:
  6. #
  7. # * Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # * Redistributions in binary form must reproduce the above
  10. # copyright notice, this list of conditions and the following disclaimer
  11. # in the documentation and/or other materials provided with the
  12. # distribution.
  13. # * Neither the name of Google Inc. nor the names of its
  14. # contributors may be used to endorse or promote products derived from
  15. # this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. import StringIO
  29. import json
  30. import math
  31. import unittest2 as unittest
  32. from webkitpy.common.host_mock import MockHost
  33. from webkitpy.common.system.outputcapture import OutputCapture
  34. from webkitpy.port.driver import DriverOutput
  35. from webkitpy.port.test import TestDriver
  36. from webkitpy.port.test import TestPort
  37. from webkitpy.performance_tests.perftest import PerfTest
  38. from webkitpy.performance_tests.perftest import PerfTestMetric
  39. from webkitpy.performance_tests.perftest import PerfTestFactory
  40. from webkitpy.performance_tests.perftest import ReplayPerfTest
  41. from webkitpy.performance_tests.perftest import SingleProcessPerfTest
  42. class MockPort(TestPort):
  43. def __init__(self, custom_run_test=None):
  44. super(MockPort, self).__init__(host=MockHost(), custom_run_test=custom_run_test)
  45. class TestPerfTestMetric(unittest.TestCase):
  46. def test_init_set_missing_unit(self):
  47. self.assertEqual(PerfTestMetric('Time', iterations=[1, 2, 3, 4, 5]).unit(), 'ms')
  48. self.assertEqual(PerfTestMetric('Malloc', iterations=[1, 2, 3, 4, 5]).unit(), 'bytes')
  49. self.assertEqual(PerfTestMetric('JSHeap', iterations=[1, 2, 3, 4, 5]).unit(), 'bytes')
  50. def test_init_set_time_metric(self):
  51. self.assertEqual(PerfTestMetric('Time', 'ms').name(), 'Time')
  52. self.assertEqual(PerfTestMetric('Time', 'fps').name(), 'FrameRate')
  53. self.assertEqual(PerfTestMetric('Time', 'runs/s').name(), 'Runs')
  54. def test_has_values(self):
  55. self.assertFalse(PerfTestMetric('Time').has_values())
  56. self.assertTrue(PerfTestMetric('Time', iterations=[1]).has_values())
  57. def test_append(self):
  58. metric = PerfTestMetric('Time')
  59. metric2 = PerfTestMetric('Time')
  60. self.assertFalse(metric.has_values())
  61. self.assertFalse(metric2.has_values())
  62. metric.append_group([1])
  63. self.assertTrue(metric.has_values())
  64. self.assertFalse(metric2.has_values())
  65. self.assertEqual(metric.grouped_iteration_values(), [[1]])
  66. self.assertEqual(metric.flattened_iteration_values(), [1])
  67. metric.append_group([2])
  68. self.assertEqual(metric.grouped_iteration_values(), [[1], [2]])
  69. self.assertEqual(metric.flattened_iteration_values(), [1, 2])
  70. metric2.append_group([3])
  71. self.assertTrue(metric2.has_values())
  72. self.assertEqual(metric.flattened_iteration_values(), [1, 2])
  73. self.assertEqual(metric2.flattened_iteration_values(), [3])
  74. metric.append_group([4, 5])
  75. self.assertEqual(metric.grouped_iteration_values(), [[1], [2], [4, 5]])
  76. self.assertEqual(metric.flattened_iteration_values(), [1, 2, 4, 5])
  77. class TestPerfTest(unittest.TestCase):
  78. def _assert_results_are_correct(self, test, output):
  79. test.run_single = lambda driver, path, time_out_ms: output
  80. self.assertTrue(test._run_with_driver(None, None))
  81. self.assertEqual(test._metrics.keys(), ['Time'])
  82. self.assertEqual(test._metrics['Time'].flattened_iteration_values(), [1080, 1120, 1095, 1101, 1104])
  83. def test_parse_output(self):
  84. output = DriverOutput("""
  85. Running 20 times
  86. Ignoring warm-up run (1115)
  87. Time:
  88. values 1080, 1120, 1095, 1101, 1104 ms
  89. avg 1100 ms
  90. median 1101 ms
  91. stdev 14.50862 ms
  92. min 1080 ms
  93. max 1120 ms
  94. """, image=None, image_hash=None, audio=None)
  95. output_capture = OutputCapture()
  96. output_capture.capture_output()
  97. try:
  98. test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  99. self._assert_results_are_correct(test, output)
  100. finally:
  101. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  102. self.assertEqual(actual_stdout, '')
  103. self.assertEqual(actual_stderr, '')
  104. self.assertEqual(actual_logs, '')
  105. def test_parse_output_with_failing_line(self):
  106. output = DriverOutput("""
  107. Running 20 times
  108. Ignoring warm-up run (1115)
  109. some-unrecognizable-line
  110. Time:
  111. values 1080, 1120, 1095, 1101, 1104 ms
  112. avg 1100 ms
  113. median 1101 ms
  114. stdev 14.50862 ms
  115. min 1080 ms
  116. max 1120 ms
  117. """, image=None, image_hash=None, audio=None)
  118. output_capture = OutputCapture()
  119. output_capture.capture_output()
  120. try:
  121. test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  122. test.run_single = lambda driver, path, time_out_ms: output
  123. self.assertFalse(test._run_with_driver(None, None))
  124. finally:
  125. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  126. self.assertEqual(actual_stdout, '')
  127. self.assertEqual(actual_stderr, '')
  128. self.assertEqual(actual_logs, 'ERROR: some-unrecognizable-line\n')
  129. def test_parse_output_with_description(self):
  130. output = DriverOutput("""
  131. Description: this is a test description.
  132. Running 20 times
  133. Ignoring warm-up run (1115)
  134. Time:
  135. values 1080, 1120, 1095, 1101, 1104 ms
  136. avg 1100 ms
  137. median 1101 ms
  138. stdev 14.50862 ms
  139. min 1080 ms
  140. max 1120 ms""", image=None, image_hash=None, audio=None)
  141. test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  142. self._assert_results_are_correct(test, output)
  143. self.assertEqual(test.description(), 'this is a test description.')
  144. def test_ignored_stderr_lines(self):
  145. test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  146. output_with_lines_to_ignore = DriverOutput('', image=None, image_hash=None, audio=None, error="""
  147. Unknown option: --foo-bar
  148. Should not be ignored
  149. [WARNING:proxy_service.cc] bad moon a-rising
  150. [WARNING:chrome.cc] Something went wrong
  151. [INFO:SkFontHost_android.cpp(1158)] Use Test Config File Main /data/local/tmp/drt/android_main_fonts.xml, Fallback /data/local/tmp/drt/android_fallback_fonts.xml, Font Dir /data/local/tmp/drt/fonts/
  152. [ERROR:main.cc] The sky has fallen""")
  153. test._filter_output(output_with_lines_to_ignore)
  154. self.assertEqual(output_with_lines_to_ignore.error,
  155. "Should not be ignored\n"
  156. "[WARNING:chrome.cc] Something went wrong\n"
  157. "[ERROR:main.cc] The sky has fallen")
  158. def test_parse_output_with_subtests(self):
  159. output = DriverOutput("""
  160. Running 20 times
  161. some test: [1, 2, 3, 4, 5]
  162. other test = else: [6, 7, 8, 9, 10]
  163. Ignoring warm-up run (1115)
  164. Time:
  165. values 1080, 1120, 1095, 1101, 1104 ms
  166. avg 1100 ms
  167. median 1101 ms
  168. stdev 14.50862 ms
  169. min 1080 ms
  170. max 1120 ms
  171. """, image=None, image_hash=None, audio=None)
  172. output_capture = OutputCapture()
  173. output_capture.capture_output()
  174. try:
  175. test = PerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  176. self._assert_results_are_correct(test, output)
  177. finally:
  178. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  179. self.assertEqual(actual_stdout, '')
  180. self.assertEqual(actual_stderr, '')
  181. self.assertEqual(actual_logs, '')
  182. class TestSingleProcessPerfTest(unittest.TestCase):
  183. def test_use_only_one_process(self):
  184. called = [0]
  185. def run_single(driver, path, time_out_ms):
  186. called[0] += 1
  187. return DriverOutput("""
  188. Running 20 times
  189. Ignoring warm-up run (1115)
  190. Time:
  191. values 1080, 1120, 1095, 1101, 1104 ms
  192. avg 1100 ms
  193. median 1101 ms
  194. stdev 14.50862 ms
  195. min 1080 ms
  196. max 1120 ms""", image=None, image_hash=None, audio=None)
  197. test = SingleProcessPerfTest(MockPort(), 'some-test', '/path/some-dir/some-test')
  198. test.run_single = run_single
  199. self.assertTrue(test.run(0))
  200. self.assertEqual(called[0], 1)
  201. class TestReplayPerfTest(unittest.TestCase):
  202. class ReplayTestPort(MockPort):
  203. def __init__(self, custom_run_test=None):
  204. class ReplayTestDriver(TestDriver):
  205. def run_test(self, text_input, stop_when_done):
  206. return custom_run_test(text_input, stop_when_done) if custom_run_test else None
  207. self._custom_driver_class = ReplayTestDriver
  208. super(self.__class__, self).__init__()
  209. def _driver_class(self):
  210. return self._custom_driver_class
  211. class MockReplayServer(object):
  212. def __init__(self, wait_until_ready=True):
  213. self.wait_until_ready = lambda: wait_until_ready
  214. def stop(self):
  215. pass
  216. def _add_file(self, port, dirname, filename, content=True):
  217. port.host.filesystem.maybe_make_directory(dirname)
  218. port.host.filesystem.write_binary_file(port.host.filesystem.join(dirname, filename), content)
  219. def _setup_test(self, run_test=None):
  220. test_port = self.ReplayTestPort(run_test)
  221. self._add_file(test_port, '/path/some-dir', 'some-test.replay', 'http://some-test/')
  222. test = ReplayPerfTest(test_port, 'some-test.replay', '/path/some-dir/some-test.replay')
  223. test._start_replay_server = lambda archive, record: self.__class__.MockReplayServer()
  224. return test, test_port
  225. def test_run_single(self):
  226. output_capture = OutputCapture()
  227. output_capture.capture_output()
  228. loaded_pages = []
  229. def run_test(test_input, stop_when_done):
  230. if test_input.test_name == test.force_gc_test:
  231. loaded_pages.append(test_input)
  232. return
  233. if test_input.test_name != "about:blank":
  234. self.assertEqual(test_input.test_name, 'http://some-test/')
  235. loaded_pages.append(test_input)
  236. self._add_file(port, '/path/some-dir', 'some-test.wpr', 'wpr content')
  237. return DriverOutput('actual text', 'actual image', 'actual checksum',
  238. audio=None, crash=False, timeout=False, error=False, test_time=12345)
  239. test, port = self._setup_test(run_test)
  240. test._archive_path = '/path/some-dir/some-test.wpr'
  241. test._url = 'http://some-test/'
  242. try:
  243. driver = port.create_driver(worker_number=1, no_timeout=True)
  244. output = test.run_single(driver, '/path/some-dir/some-test.replay', time_out_ms=100)
  245. self.assertTrue(output)
  246. finally:
  247. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  248. self.assertEqual(len(loaded_pages), 2)
  249. self.assertEqual(loaded_pages[0].test_name, test.force_gc_test)
  250. self.assertEqual(loaded_pages[1].test_name, 'http://some-test/')
  251. self.assertEqual(actual_stdout, '')
  252. self.assertEqual(actual_stderr, '')
  253. self.assertEqual(actual_logs, '')
  254. self.assertEqual(port.host.filesystem.read_binary_file('/path/some-dir/some-test-actual.png'), 'actual image')
  255. self.assertEqual(output.test_time, 12345)
  256. def test_run_single_fails_without_webpagereplay(self):
  257. output_capture = OutputCapture()
  258. output_capture.capture_output()
  259. test, port = self._setup_test()
  260. test._start_replay_server = lambda archive, record: None
  261. test._archive_path = '/path/some-dir.wpr'
  262. test._url = 'http://some-test/'
  263. try:
  264. driver = port.create_driver(worker_number=1, no_timeout=True)
  265. self.assertEqual(test.run_single(driver, '/path/some-dir/some-test.replay', time_out_ms=100), None)
  266. finally:
  267. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  268. self.assertEqual(actual_stdout, '')
  269. self.assertEqual(actual_stderr, '')
  270. self.assertEqual(actual_logs, "Web page replay didn't start.\n")
  271. def test_run_with_driver_accumulates_results(self):
  272. port = MockPort()
  273. test, port = self._setup_test()
  274. counter = [0]
  275. def mock_run_signle(drive, path, timeout):
  276. counter[0] += 1
  277. return DriverOutput('some output', image=None, image_hash=None, audio=None, test_time=counter[0], measurements={})
  278. test.run_single = mock_run_signle
  279. output_capture = OutputCapture()
  280. output_capture.capture_output()
  281. try:
  282. driver = port.create_driver(worker_number=1, no_timeout=True)
  283. self.assertTrue(test._run_with_driver(driver, None))
  284. finally:
  285. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  286. self.assertEqual(actual_stdout, '')
  287. self.assertEqual(actual_stderr, '')
  288. self.assertEqual(actual_logs, '')
  289. self.assertEqual(test._metrics.keys(), ['Time'])
  290. self.assertEqual(test._metrics['Time'].flattened_iteration_values(), [float(i * 1000) for i in range(2, 7)])
  291. def test_run_with_driver_accumulates_memory_results(self):
  292. port = MockPort()
  293. test, port = self._setup_test()
  294. counter = [0]
  295. def mock_run_signle(drive, path, timeout):
  296. counter[0] += 1
  297. return DriverOutput('some output', image=None, image_hash=None, audio=None, test_time=counter[0], measurements={'Malloc': 10, 'JSHeap': 5})
  298. test.run_single = mock_run_signle
  299. output_capture = OutputCapture()
  300. output_capture.capture_output()
  301. try:
  302. driver = port.create_driver(worker_number=1, no_timeout=True)
  303. self.assertTrue(test._run_with_driver(driver, None))
  304. finally:
  305. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  306. self.assertEqual(actual_stdout, '')
  307. self.assertEqual(actual_stderr, '')
  308. self.assertEqual(actual_logs, '')
  309. metrics = test._metrics
  310. self.assertEqual(sorted(metrics.keys()), ['JSHeap', 'Malloc', 'Time'])
  311. self.assertEqual(metrics['Time'].flattened_iteration_values(), [float(i * 1000) for i in range(2, 7)])
  312. self.assertEqual(metrics['Malloc'].flattened_iteration_values(), [float(10)] * 5)
  313. self.assertEqual(metrics['JSHeap'].flattened_iteration_values(), [float(5)] * 5)
  314. def test_prepare_fails_when_wait_until_ready_fails(self):
  315. output_capture = OutputCapture()
  316. output_capture.capture_output()
  317. test, port = self._setup_test()
  318. test._start_replay_server = lambda archive, record: self.__class__.MockReplayServer(wait_until_ready=False)
  319. test._archive_path = '/path/some-dir.wpr'
  320. test._url = 'http://some-test/'
  321. try:
  322. driver = port.create_driver(worker_number=1, no_timeout=True)
  323. self.assertEqual(test.run_single(driver, '/path/some-dir/some-test.replay', time_out_ms=100), None)
  324. finally:
  325. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  326. self.assertEqual(actual_stdout, '')
  327. self.assertEqual(actual_stderr, '')
  328. self.assertEqual(actual_logs, "Web page replay didn't start.\n")
  329. def test_run_single_fails_when_output_has_error(self):
  330. output_capture = OutputCapture()
  331. output_capture.capture_output()
  332. loaded_pages = []
  333. def run_test(test_input, stop_when_done):
  334. loaded_pages.append(test_input)
  335. self._add_file(port, '/path/some-dir', 'some-test.wpr', 'wpr content')
  336. return DriverOutput('actual text', 'actual image', 'actual checksum',
  337. audio=None, crash=False, timeout=False, error='some error')
  338. test, port = self._setup_test(run_test)
  339. test._archive_path = '/path/some-dir.wpr'
  340. test._url = 'http://some-test/'
  341. try:
  342. driver = port.create_driver(worker_number=1, no_timeout=True)
  343. self.assertEqual(test.run_single(driver, '/path/some-dir/some-test.replay', time_out_ms=100), None)
  344. finally:
  345. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  346. self.assertEqual(len(loaded_pages), 2)
  347. self.assertEqual(loaded_pages[0].test_name, test.force_gc_test)
  348. self.assertEqual(loaded_pages[1].test_name, 'http://some-test/')
  349. self.assertEqual(actual_stdout, '')
  350. self.assertEqual(actual_stderr, '')
  351. self.assertEqual(actual_logs, 'error: some-test.replay\nsome error\n')
  352. def test_prepare(self):
  353. output_capture = OutputCapture()
  354. output_capture.capture_output()
  355. def run_test(test_input, stop_when_done):
  356. self._add_file(port, '/path/some-dir', 'some-test.wpr', 'wpr content')
  357. return DriverOutput('actual text', 'actual image', 'actual checksum',
  358. audio=None, crash=False, timeout=False, error=False)
  359. test, port = self._setup_test(run_test)
  360. try:
  361. self.assertTrue(test.prepare(time_out_ms=100))
  362. finally:
  363. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  364. self.assertEqual(actual_stdout, '')
  365. self.assertEqual(actual_stderr, '')
  366. self.assertEqual(actual_logs, 'Preparing replay for some-test.replay\nPrepared replay for some-test.replay\n')
  367. self.assertEqual(port.host.filesystem.read_binary_file('/path/some-dir/some-test-expected.png'), 'actual image')
  368. def test_prepare_calls_run_single(self):
  369. output_capture = OutputCapture()
  370. output_capture.capture_output()
  371. called = [False]
  372. def run_single(driver, url, time_out_ms, record):
  373. self.assertTrue(record)
  374. self.assertEqual(url, '/path/some-dir/some-test.wpr')
  375. called[0] = True
  376. return False
  377. test, port = self._setup_test()
  378. test.run_single = run_single
  379. try:
  380. self.assertFalse(test.prepare(time_out_ms=100))
  381. finally:
  382. actual_stdout, actual_stderr, actual_logs = output_capture.restore_output()
  383. self.assertTrue(called[0])
  384. self.assertEqual(test._archive_path, '/path/some-dir/some-test.wpr')
  385. self.assertEqual(test._url, 'http://some-test/')
  386. self.assertEqual(actual_stdout, '')
  387. self.assertEqual(actual_stderr, '')
  388. self.assertEqual(actual_logs, "Preparing replay for some-test.replay\nFailed to prepare a replay for some-test.replay\n")
  389. class TestPerfTestFactory(unittest.TestCase):
  390. def test_regular_test(self):
  391. test = PerfTestFactory.create_perf_test(MockPort(), 'some-dir/some-test', '/path/some-dir/some-test')
  392. self.assertEqual(test.__class__, PerfTest)