Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(694)

Side by Side Diff: chrome/test/functional/perf_endure.py

Issue 10803002: Run Chrome Endure tests with network simulation via Web Page Replay. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge with master Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/test/data/chrome_endure/webpagereplay/wpr_deterministic.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Performance tests for Chrome Endure (long-running perf tests on Chrome). 6 """Performance tests for Chrome Endure (long-running perf tests on Chrome).
7 7
8 This module accepts the following environment variable inputs: 8 This module accepts the following environment variable inputs:
9 TEST_LENGTH: The number of seconds in which to run each test. 9 TEST_LENGTH: The number of seconds in which to run each test.
10 PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling 10 PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling
11 of performance/memory statistics. 11 of performance/memory statistics.
12 12
13 DEEP_MEMORY_PROFILE: Enable the Deep Memory Profiler if it's set to 'True'. 13 DEEP_MEMORY_PROFILE: Enable the Deep Memory Profiler if it's set to 'True'.
14 DEEP_MEMORY_PROFILE_SAVE: Don't clean up dump files if it's set to 'True'. 14 DEEP_MEMORY_PROFILE_SAVE: Don't clean up dump files if it's set to 'True'.
15
16 ENDURE_NO_WPR: Run tests without Web Page Replay if it's set.
17 WPR_RECORD: Run tests in record mode. If you want to make a fresh
18 archive, make sure to delete the old one, otherwise
19 it will append to the old one.
20 WPR_ARCHIVE_PATH: an alternative archive file to use.
15 """ 21 """
16 22
17 from datetime import datetime 23 from datetime import datetime
18 import json 24 import json
19 import logging 25 import logging
20 import os 26 import os
21 import re 27 import re
22 import subprocess 28 import subprocess
23 import tempfile 29 import tempfile
24 import time 30 import time
25 31
26 import perf 32 import perf
27 import pyauto_functional # Must be imported before pyauto. 33 import pyauto_functional # Must be imported before pyauto.
28 import pyauto 34 import pyauto
29 import pyauto_errors 35 import pyauto_errors
30 import pyauto_utils 36 import pyauto_utils
31 import remote_inspector_client 37 import remote_inspector_client
32 import selenium.common.exceptions 38 import selenium.common.exceptions
33 from selenium.webdriver.support.ui import WebDriverWait 39 from selenium.webdriver.support.ui import WebDriverWait
40 import webpagereplay
34 41
35 42
36 class NotSupportedEnvironmentError(RuntimeError): 43 class NotSupportedEnvironmentError(RuntimeError):
37 """Represent an error raised since the environment (OS) is not supported.""" 44 """Represent an error raised since the environment (OS) is not supported."""
38 pass 45 pass
39 46
47
40 class ChromeEndureBaseTest(perf.BasePerfTest): 48 class ChromeEndureBaseTest(perf.BasePerfTest):
41 """Implements common functionality for all Chrome Endure tests. 49 """Implements common functionality for all Chrome Endure tests.
42 50
43 All Chrome Endure test classes should inherit from this class. 51 All Chrome Endure test classes should inherit from this class.
44 """ 52 """
45 53
46 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. 54 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
47 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes. 55 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
48 # TODO(dennisjeffrey): Do we still need to tolerate errors? 56 # TODO(dennisjeffrey): Do we still need to tolerate errors?
49 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate. 57 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate.
50 _DEEP_MEMORY_PROFILE = False 58 _DEEP_MEMORY_PROFILE = False
51 _DEEP_MEMORY_PROFILE_SAVE = False 59 _DEEP_MEMORY_PROFILE_SAVE = False
52 60
53 _DMPROF_DIR_PATH = os.path.join( 61 _DMPROF_DIR_PATH = os.path.join(
54 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 62 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
55 'tools', 'deep_memory_profiler') 63 'tools', 'deep_memory_profiler')
56 64
57 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof') 65 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
58 66
59 def setUp(self): 67 def setUp(self):
68 # The Web Page Replay environment variables must be parsed before
69 # perf.BasePerfTest.setUp()
70 self._ParseReplayEnv()
60 # The environment variables for the Deep Memory Profiler must be set 71 # The environment variables for the Deep Memory Profiler must be set
61 # before perf.BasePerfTest.setUp() to inherit them to Chrome. 72 # before perf.BasePerfTest.setUp() to inherit them to Chrome.
62 self._deep_memory_profile = self._GetDeepMemoryProfileEnv( 73 self._deep_memory_profile = self._GetDeepMemoryProfileEnv(
63 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 74 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
64 75
65 if self._deep_memory_profile: 76 if self._deep_memory_profile:
66 if not self.IsLinux(): 77 if not self.IsLinux():
67 raise NotSupportedEnvironmentError( 78 raise NotSupportedEnvironmentError(
68 'Deep Memory Profiler is not supported in this environment (OS).') 79 'Deep Memory Profiler is not supported in this environment (OS).')
69 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S') 80 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
(...skipping 27 matching lines...) Expand all
97 self._remote_inspector_client = ( 108 self._remote_inspector_client = (
98 remote_inspector_client.RemoteInspectorClient()) 109 remote_inspector_client.RemoteInspectorClient())
99 logging.info('Connection to remote inspector set up successfully.') 110 logging.info('Connection to remote inspector set up successfully.')
100 111
101 self._test_start_time = 0 112 self._test_start_time = 0
102 self._num_errors = 0 113 self._num_errors = 0
103 self._events_to_output = [] 114 self._events_to_output = []
104 self._deep_memory_profile_json_file = None 115 self._deep_memory_profile_json_file = None
105 self._deep_memory_profile_last_json_filename = '' 116 self._deep_memory_profile_last_json_filename = ''
106 self._deep_memory_profile_proc = None 117 self._deep_memory_profile_proc = None
118 self._StartReplayServerIfNecessary()
107 119
108 def tearDown(self): 120 def tearDown(self):
109 logging.info('Terminating connection to remote inspector...') 121 logging.info('Terminating connection to remote inspector...')
110 self._remote_inspector_client.Stop() 122 self._remote_inspector_client.Stop()
111 logging.info('Connection to remote inspector terminated.') 123 logging.info('Connection to remote inspector terminated.')
112 if self._deep_memory_profile: 124 if self._deep_memory_profile:
113 del os.environ['DEEP_HEAP_PROFILE'] 125 del os.environ['DEEP_HEAP_PROFILE']
114 del os.environ['HEAP_PROFILE_MMAP'] 126 del os.environ['HEAP_PROFILE_MMAP']
115 del os.environ['HEAPPROFILE'] 127 del os.environ['HEAPPROFILE']
116 128
117 # Must be done at end of this function except for post-cleaning after 129 # Must be done at end of this function except for post-cleaning after
118 # Chrome finishes. 130 # Chrome finishes.
119 perf.BasePerfTest.tearDown(self) 131 perf.BasePerfTest.tearDown(self)
120 132
121 # Remove the temporary directory after Chrome finishes in tearDown. 133 # Remove the temporary directory after Chrome finishes in tearDown.
122 if (self._deep_memory_profile and 134 if (self._deep_memory_profile and
123 not self._deep_memory_profile_save and 135 not self._deep_memory_profile_save and
124 self._deep_tempdir): 136 self._deep_tempdir):
125 pyauto_utils.RemovePath(self._deep_tempdir) 137 pyauto_utils.RemovePath(self._deep_tempdir)
138 # Must be done after perf.BasePerfTest.tearDown()
139 self._StopReplayServerIfNecessary()
140
141 def _GetArchiveName(self):
142 """Return the Web Page Replay archive name that corresponds to a test.
143
144 Override this function to return the name of an archive that
145 corresponds to the test, e.g "ChromeEndureGmailTest.wpr".
146
147 Returns:
148 None, by default no archive name is provided.
149 """
150 return None
151
152 def _ParseReplayEnv(self):
153 """Parse Web Page Replay related envrionment variables."""
154 if 'ENDURE_NO_WPR' in os.environ:
155 self._use_wpr = False
156 logging.info('Skipping Web Page Replay since ENDURE_NO_WPR is set.')
157 else:
158 self._archive_path = None
159 if 'WPR_ARCHIVE_PATH' in os.environ:
160 self._archive_path = os.environ.get('WPR_ARCHIVE_PATH')
161 else:
162 if self._GetArchiveName():
163 self._archive_path = ChromeEndureReplay.Path(
164 'archive', archive_name=self._GetArchiveName())
165 self._is_record_mode = 'WPR_RECORD' in os.environ
166 if self._is_record_mode:
167 if self._archive_path:
168 self._use_wpr = True
169 else:
170 self._use_wpr = False
171 logging.info('Fail to record since a valid archive path can not ' +
172 'be generated. Did you implement ' +
173 '_GetArchiveName() in your test?')
174 else:
175 if self._archive_path and os.path.exists(self._archive_path):
176 self._use_wpr = True
177 else:
178 self._use_wpr = False
179 logging.info(
180 'Skipping Web Page Replay since archive file %sdoes not exist.',
181 self._archive_path + ' ' if self._archive_path else '')
126 182
127 def _GetDeepMemoryProfileEnv(self, env_name, converter, default): 183 def _GetDeepMemoryProfileEnv(self, env_name, converter, default):
128 """Returns a converted environment variable for the Deep Memory Profiler. 184 """Returns a converted environment variable for the Deep Memory Profiler.
129 185
130 Args: 186 Args:
131 env_name: A string name of an environment variable. 187 env_name: A string name of an environment variable.
132 converter: A function taking a string to convert an environment variable. 188 converter: A function taking a string to convert an environment variable.
133 default: A value used if the environment variable is not specified. 189 default: A value used if the environment variable is not specified.
134 190
135 Returns: 191 Returns:
(...skipping 21 matching lines...) Expand all
157 # The same with setUp, but need to fetch the environment variable since 213 # The same with setUp, but need to fetch the environment variable since
158 # ExtraChromeFlags is called before setUp. 214 # ExtraChromeFlags is called before setUp.
159 deep_memory_profile = self._GetDeepMemoryProfileEnv( 215 deep_memory_profile = self._GetDeepMemoryProfileEnv(
160 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 216 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
161 217
162 # Ensure Chrome enables remote debugging on port 9222. This is required to 218 # Ensure Chrome enables remote debugging on port 9222. This is required to
163 # interact with Chrome's remote inspector. 219 # interact with Chrome's remote inspector.
164 extra_flags = ['--remote-debugging-port=9222'] 220 extra_flags = ['--remote-debugging-port=9222']
165 if deep_memory_profile: 221 if deep_memory_profile:
166 extra_flags.append('--no-sandbox') 222 extra_flags.append('--no-sandbox')
167 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags) 223 if self._use_wpr:
224 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS)
225 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags
168 226
169 def _OnTimelineEvent(self, event_info): 227 def _OnTimelineEvent(self, event_info):
170 """Invoked by the Remote Inspector Client when a timeline event occurs. 228 """Invoked by the Remote Inspector Client when a timeline event occurs.
171 229
172 Args: 230 Args:
173 event_info: A dictionary containing raw information associated with a 231 event_info: A dictionary containing raw information associated with a
174 timeline event received from Chrome's remote inspector. Refer to 232 timeline event received from Chrome's remote inspector. Refer to
175 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json 233 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json
176 for the format of this dictionary. 234 for the format of this dictionary.
177 """ 235 """
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 try: 573 try:
516 element = self._GetElement(driver.find_element_by_xpath, xpath) 574 element = self._GetElement(driver.find_element_by_xpath, xpath)
517 element.click() 575 element.click()
518 except (selenium.common.exceptions.StaleElementReferenceException, 576 except (selenium.common.exceptions.StaleElementReferenceException,
519 selenium.common.exceptions.TimeoutException) as e: 577 selenium.common.exceptions.TimeoutException) as e:
520 logging.exception('WebDriver exception: %s' % e) 578 logging.exception('WebDriver exception: %s' % e)
521 return False 579 return False
522 580
523 return True 581 return True
524 582
583 def _StartReplayServerIfNecessary(self):
584 """Start replay server if necessary."""
585 if self._use_wpr:
586 mode = 'record' if self._is_record_mode else 'replay'
587 self._wpr_server = ChromeEndureReplay.ReplayServer(self._archive_path)
588 self._wpr_server.StartServer()
589 logging.info('Web Page Replay server has started in %s mode.', mode)
590
591 def _StopReplayServerIfNecessary(self):
592 """Stop the Web Page Replay server if necessary.
593
594 This method has to be called AFTER all network connections which go
595 through Web Page Replay server have shut down. Otherwise the
596 Web Page Replay server will hang to wait for them. A good
597 place is to call it at the end of the teardown process.
598 """
599 if self._use_wpr:
600 self._wpr_server.StopServer()
601 logging.info('The Web Page Replay server stopped.')
602
525 603
526 class ChromeEndureControlTest(ChromeEndureBaseTest): 604 class ChromeEndureControlTest(ChromeEndureBaseTest):
527 """Control tests for Chrome Endure.""" 605 """Control tests for Chrome Endure."""
528 606
529 _WEBAPP_NAME = 'Control' 607 _WEBAPP_NAME = 'Control'
530 _TAB_TITLE_SUBSTRING = 'Chrome Endure Control Test' 608 _TAB_TITLE_SUBSTRING = 'Chrome Endure Control Test'
531 609
532 def testControlAttachDetachDOMTree(self): 610 def testControlAttachDetachDOMTree(self):
533 """Continually attach and detach a DOM tree from a basic document.""" 611 """Continually attach and detach a DOM tree from a basic document."""
534 test_description = 'AttachDetachDOMTree' 612 test_description = 'AttachDetachDOMTree'
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 687
610 # Test whether latency dom element is available. 688 # Test whether latency dom element is available.
611 try: 689 try:
612 self._GetLatencyDomElement(5000) 690 self._GetLatencyDomElement(5000)
613 self._has_latency = True 691 self._has_latency = True
614 except pyauto_errors.JSONInterfaceError: 692 except pyauto_errors.JSONInterfaceError:
615 logging.info('Skip recording latency as latency ' + 693 logging.info('Skip recording latency as latency ' +
616 'dom element is not available.') 694 'dom element is not available.')
617 self._has_latency = False 695 self._has_latency = False
618 696
697 def _GetArchiveName(self):
698 """Return Web Page Replay archive name."""
699 return 'ChromeEndureGmailTest.wpr'
700
619 def _SwitchToCanvasFrame(self, driver): 701 def _SwitchToCanvasFrame(self, driver):
620 """Switch the WebDriver to Gmail's 'canvas_frame', if it's available. 702 """Switch the WebDriver to Gmail's 'canvas_frame', if it's available.
621 703
622 Args: 704 Args:
623 driver: A selenium.webdriver.remote.webdriver.WebDriver object. 705 driver: A selenium.webdriver.remote.webdriver.WebDriver object.
624 706
625 Returns: 707 Returns:
626 True, if the switch to Gmail's 'canvas_frame' is successful, or 708 True, if the switch to Gmail's 'canvas_frame' is successful, or
627 False if not. 709 False if not.
628 """ 710 """
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 self.NavigateToURL(self._GetConfig().get('docs_url')) 1030 self.NavigateToURL(self._GetConfig().get('docs_url'))
949 self.assertTrue( 1031 self.assertTrue(
950 self.WaitUntil(lambda: self._TAB_TITLE_SUBSTRING in 1032 self.WaitUntil(lambda: self._TAB_TITLE_SUBSTRING in
951 self.GetActiveTabTitle(), 1033 self.GetActiveTabTitle(),
952 timeout=60, expect_retval=True, retry_sleep=1), 1034 timeout=60, expect_retval=True, retry_sleep=1),
953 msg='Timed out waiting for Docs to load. Tab title is: %s' % 1035 msg='Timed out waiting for Docs to load. Tab title is: %s' %
954 self.GetActiveTabTitle()) 1036 self.GetActiveTabTitle())
955 1037
956 self._driver = self.NewWebDriver() 1038 self._driver = self.NewWebDriver()
957 1039
1040 def _GetArchiveName(self):
1041 """Return Web Page Replay archive name."""
1042 return 'ChromeEndureDocsTest.wpr'
1043
958 def testDocsAlternatelyClickLists(self): 1044 def testDocsAlternatelyClickLists(self):
959 """Alternates between two different document lists. 1045 """Alternates between two different document lists.
960 1046
961 This test alternately clicks the "Shared with me" and "My Drive" buttons in 1047 This test alternately clicks the "Shared with me" and "My Drive" buttons in
962 Google Docs, and periodically gathers performance stats that may reveal 1048 Google Docs, and periodically gathers performance stats that may reveal
963 memory bloat. 1049 memory bloat.
964 """ 1050 """
965 test_description = 'AlternateLists' 1051 test_description = 'AlternateLists'
966 1052
967 def sort_menu_setup(): 1053 def sort_menu_setup():
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 # Log into a test Google account and open up Google Plus. 1104 # Log into a test Google account and open up Google Plus.
1019 self._LoginToGoogleAccount() 1105 self._LoginToGoogleAccount()
1020 self.NavigateToURL(self._GetConfig().get('plus_url')) 1106 self.NavigateToURL(self._GetConfig().get('plus_url'))
1021 loaded_tab_title = self.GetActiveTabTitle() 1107 loaded_tab_title = self.GetActiveTabTitle()
1022 self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title, 1108 self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title,
1023 msg='Loaded tab title does not contain "%s": "%s"' % 1109 msg='Loaded tab title does not contain "%s": "%s"' %
1024 (self._TAB_TITLE_SUBSTRING, loaded_tab_title)) 1110 (self._TAB_TITLE_SUBSTRING, loaded_tab_title))
1025 1111
1026 self._driver = self.NewWebDriver() 1112 self._driver = self.NewWebDriver()
1027 1113
1114 def _GetArchiveName(self):
1115 """Return Web Page Replay archive name."""
1116 return 'ChromeEndurePlusTest.wpr'
1117
1028 def testPlusAlternatelyClickStreams(self): 1118 def testPlusAlternatelyClickStreams(self):
1029 """Alternates between two different streams. 1119 """Alternates between two different streams.
1030 1120
1031 This test alternately clicks the "Friends" and "Family" buttons using 1121 This test alternately clicks the "Friends" and "Family" buttons using
1032 Google Plus, and periodically gathers performance stats that may reveal 1122 Google Plus, and periodically gathers performance stats that may reveal
1033 memory bloat. 1123 memory bloat.
1034 """ 1124 """
1035 test_description = 'AlternateStreams' 1125 test_description = 'AlternateStreams'
1036 1126
1037 def scenario(): 1127 def scenario():
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1121 except (pyauto_errors.JSONInterfaceError, 1211 except (pyauto_errors.JSONInterfaceError,
1122 pyauto_errors.JavascriptRuntimeError): 1212 pyauto_errors.JavascriptRuntimeError):
1123 self._num_errors += 1 1213 self._num_errors += 1
1124 1214
1125 time.sleep(1) 1215 time.sleep(1)
1126 1216
1127 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING, 1217 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
1128 test_description, scenario) 1218 test_description, scenario)
1129 1219
1130 1220
1221 class ChromeEndureReplay(object):
1222 """Run Chrome Endure tests with network simulation via Web Page Replay."""
1223
1224 _PATHS = {
1225 'archive':
1226 'src/chrome/test/data/pyauto_private/webpagereplay/{archive_name}',
1227 'scripts':
1228 'src/chrome/test/data/chrome_endure/webpagereplay/wpr_deterministic.js',
1229 }
1230 CHROME_FLAGS = webpagereplay.CHROME_FLAGS
1231
1232 @classmethod
1233 def Path(cls, key, **kwargs):
1234 return perf.FormatChromePath(cls._PATHS[key], **kwargs)
1235
1236 @classmethod
1237 def ReplayServer(cls, archive_path):
1238 """Create a replay server."""
1239 # Inject customized scripts for Google webapps.
1240 # See the javascript file for details.
1241 scripts = cls.Path('scripts')
1242 if not os.path.exists(scripts):
1243 raise IOError('Injected scripts %s not found.' % scripts)
1244 replay_options = ['--inject_scripts', scripts]
1245 if 'WPR_RECORD' in os.environ:
1246 replay_options.append('--append')
1247 return webpagereplay.ReplayServer(archive_path, replay_options)
1248
1249
1131 if __name__ == '__main__': 1250 if __name__ == '__main__':
1132 pyauto_functional.Main() 1251 pyauto_functional.Main()
OLDNEW
« no previous file with comments | « chrome/test/data/chrome_endure/webpagereplay/wpr_deterministic.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698