Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 | |
| 13 DEEP_MEMORY_PROFILE_INTERVAL: The number of seconds to wait in-between each | |
| 14 sampling for the Deep Memory Profiler. | |
| 15 DEEP_MEMORY_PROFILE_SAVE: Don't clean-up profile dump files if it's set. | |
| 12 """ | 16 """ |
| 13 | 17 |
| 18 from datetime import datetime | |
| 19 import json | |
| 14 import logging | 20 import logging |
| 15 import os | 21 import os |
| 16 import re | 22 import re |
| 23 import subprocess | |
| 24 import tempfile | |
| 17 import time | 25 import time |
| 18 | 26 |
| 19 import perf | 27 import perf |
| 20 import pyauto_functional # Must be imported before pyauto. | 28 import pyauto_functional # Must be imported before pyauto. |
| 21 import pyauto | 29 import pyauto |
| 30 import pyauto_utils | |
| 22 import remote_inspector_client | 31 import remote_inspector_client |
| 23 import selenium.common.exceptions | 32 import selenium.common.exceptions |
| 24 from selenium.webdriver.support.ui import WebDriverWait | 33 from selenium.webdriver.support.ui import WebDriverWait |
| 25 | 34 |
| 26 | |
| 27 class ChromeEndureBaseTest(perf.BasePerfTest): | 35 class ChromeEndureBaseTest(perf.BasePerfTest): |
| 28 """Implements common functionality for all Chrome Endure tests. | 36 """Implements common functionality for all Chrome Endure tests. |
| 29 | 37 |
| 30 All Chrome Endure test classes should inherit from this class. | 38 All Chrome Endure test classes should inherit from this class. |
| 31 """ | 39 """ |
| 32 | 40 |
| 33 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. | 41 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. |
| 34 _GET_PERF_STATS_INTERVAL = 60 * 10 # Measure perf stats every 10 minutes. | 42 _GET_PERF_STATS_INTERVAL = 60 * 10 # Measure perf stats every 10 minutes. |
| 35 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. | 43 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. |
| 44 _DEEP_MEMORY_PROFILE_INTERVAL = 0 | |
| 45 _DEEP_MEMORY_PROFILE_SAVE = False | |
| 46 | |
| 47 _DMPROF_DIR_PATH = os.path.join( | |
| 48 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, | |
| 49 'tools', 'deep_memory_profiler') | |
| 50 | |
| 51 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof') | |
| 52 | |
| 53 # TODO(dmikurube): Need to find an actual running chrome. | |
| 54 _CHROME_BIN_PATH = os.path.join( | |
| 55 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, | |
| 56 'out', 'Debug', 'chrome') | |
| 36 | 57 |
| 37 def setUp(self): | 58 def setUp(self): |
| 59 # These environment variables for the Deep Memory Profiler must be set | |
| 60 # before perf.BasePerfTest.setUp() to inherit them to Chrome. | |
| 61 self._deep_memory_profile_interval = 0 | |
| 62 if self.IsLinux(): | |
| 63 self._deep_memory_profile_interval = int( | |
| 64 os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL', | |
| 65 self._DEEP_MEMORY_PROFILE_INTERVAL)) | |
| 66 | |
| 67 if self._deep_memory_profile_interval > 0: | |
| 68 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S') | |
| 69 self._deep_tempdir = tempfile.mkdtemp(prefix=dir_prefix) | |
| 70 os.environ['HEAPPROFILE'] = os.path.join(self._deep_tempdir, 'endure') | |
| 71 os.environ['HEAP_PROFILE_MMAP'] = 'True' | |
| 72 os.environ['DEEP_HEAP_PROFILE'] = 'True' | |
| 73 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL when PyAuto | |
| 74 # supports to dump renderer heap profile. | |
| 75 os.environ['HEAP_PROFILE_TIME_INTERVAL'] = ( | |
| 76 '%d' % self._deep_memory_profile_interval) | |
| 77 | |
| 38 perf.BasePerfTest.setUp(self) | 78 perf.BasePerfTest.setUp(self) |
| 39 | 79 |
| 40 self._test_length_sec = int( | 80 self._test_length_sec = int( |
| 41 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) | 81 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) |
| 42 self._get_perf_stats_interval = int( | 82 self._get_perf_stats_interval = int( |
| 43 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) | 83 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) |
| 44 | 84 |
| 85 self._deep_memory_profile_save = False | |
| 86 if self.IsLinux(): | |
| 87 self._deep_memory_profile_save = bool( | |
| 88 os.environ.get('DEEP_MEMORY_PROFILE_SAVE', | |
| 89 self._DEEP_MEMORY_PROFILE_SAVE)) | |
| 90 self._deep_memory_profile_last_json_filename = '' | |
| 91 | |
| 45 logging.info('Running test for %d seconds.', self._test_length_sec) | 92 logging.info('Running test for %d seconds.', self._test_length_sec) |
| 46 logging.info('Gathering perf stats every %d seconds.', | 93 logging.info('Gathering perf stats every %d seconds.', |
| 47 self._get_perf_stats_interval) | 94 self._get_perf_stats_interval) |
| 95 if self._deep_memory_profile_interval > 0: | |
| 96 logging.info('Running with the Deep Memory Profiler every %d seconds.', | |
| 97 self._deep_memory_profile_interval) | |
| 98 if self._deep_memory_profile_save: | |
| 99 logging.info('Dump files by the Deep Memory Profiler are not cleaned.') | |
| 48 | 100 |
| 49 # Set up a remote inspector client associated with tab 0. | 101 # Set up a remote inspector client associated with tab 0. |
| 50 logging.info('Setting up connection to remote inspector...') | 102 logging.info('Setting up connection to remote inspector...') |
| 51 self._remote_inspector_client = ( | 103 self._remote_inspector_client = ( |
| 52 remote_inspector_client.RemoteInspectorClient()) | 104 remote_inspector_client.RemoteInspectorClient()) |
| 53 logging.info('Connection to remote inspector set up successfully.') | 105 logging.info('Connection to remote inspector set up successfully.') |
| 54 | 106 |
| 55 self._dom_node_count_results = [] | 107 self._dom_node_count_results = [] |
| 56 self._event_listener_count_results = [] | 108 self._event_listener_count_results = [] |
| 57 self._browser_process_private_mem_results = [] | 109 self._browser_process_private_mem_results = [] |
| 58 self._tab_process_private_mem_results = [] | 110 self._tab_process_private_mem_results = [] |
| 59 self._v8_mem_used_results = [] | 111 self._v8_mem_used_results = [] |
| 60 self._test_start_time = 0 | 112 self._test_start_time = 0 |
| 61 self._num_errors = 0 | 113 self._num_errors = 0 |
| 62 self._iteration_num = 0 | 114 self._iteration_num = 0 |
| 115 self._deep_memory_profile_json_f = None | |
|
dennis_jeffrey
2012/04/17 22:36:14
I recommend using "file" instead of just "f", just
Dai Mikurube (NOT FULLTIME)
2012/04/18 04:59:51
Done.
| |
| 116 self._deep_memory_profile_proc = None | |
| 63 | 117 |
| 64 def tearDown(self): | 118 def tearDown(self): |
| 65 logging.info('Terminating connection to remote inspector...') | 119 logging.info('Terminating connection to remote inspector...') |
| 66 self._remote_inspector_client.Stop() | 120 self._remote_inspector_client.Stop() |
| 67 logging.info('Connection to remote inspector terminated.') | 121 logging.info('Connection to remote inspector terminated.') |
| 122 if self._deep_memory_profile_interval > 0: | |
| 123 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL in setUp when | |
| 124 # PyAuto supports to dump renderer heap profile. | |
| 125 del os.environ['HEAP_PROFILE_TIME_INTERVAL'] | |
| 126 del os.environ['DEEP_HEAP_PROFILE'] | |
| 127 del os.environ['HEAP_PROFILE_MMAP'] | |
| 128 del os.environ['HEAPPROFILE'] | |
| 68 perf.BasePerfTest.tearDown(self) # Must be done at end of this function. | 129 perf.BasePerfTest.tearDown(self) # Must be done at end of this function. |
|
dennis_jeffrey
2012/04/17 22:36:14
Maybe we should move this line to the bottom of th
Dai Mikurube (NOT FULLTIME)
2012/04/18 04:59:51
We have to remove the temporary directory after Ch
| |
| 130 if (self._deep_memory_profile_interval > 0 and | |
| 131 not self._deep_memory_profile_save and | |
| 132 self._deep_tempdir): | |
| 133 pyauto_utils.RemovePath(self._deep_tempdir) | |
| 69 | 134 |
| 70 def ExtraChromeFlags(self): | 135 def ExtraChromeFlags(self): |
| 71 """Ensures Chrome is launched with custom flags. | 136 """Ensures Chrome is launched with custom flags. |
| 72 | 137 |
| 73 Returns: | 138 Returns: |
| 74 A list of extra flags to pass to Chrome when it is launched. | 139 A list of extra flags to pass to Chrome when it is launched. |
| 75 """ | 140 """ |
| 141 # The same with setUp, but need to fetch the environment variable since | |
| 142 # ExtraChromeFlags is called before setUp. | |
| 143 deep_memory_profile_interval = 0 | |
| 144 if self.IsLinux(): | |
| 145 deep_memory_profile_interval = int( | |
| 146 os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL', | |
| 147 self._DEEP_MEMORY_PROFILE_INTERVAL)) | |
| 148 | |
| 76 # Ensure Chrome enables remote debugging on port 9222. This is required to | 149 # Ensure Chrome enables remote debugging on port 9222. This is required to |
| 77 # interact with Chrome's remote inspector. | 150 # interact with Chrome's remote inspector. |
| 78 return (perf.BasePerfTest.ExtraChromeFlags(self) + | 151 extra_flags = ['--remote-debugging-port=9222'] |
| 79 ['--remote-debugging-port=9222']) | 152 if deep_memory_profile_interval > 0: |
| 153 extra_flags.append('--no-sandbox') | |
| 154 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags) | |
| 80 | 155 |
| 81 def _RunEndureTest(self, webapp_name, tab_title_substring, test_description, | 156 def _RunEndureTest(self, webapp_name, tab_title_substring, test_description, |
| 82 do_scenario): | 157 do_scenario): |
| 83 """The main test harness function to run a general Chrome Endure test. | 158 """The main test harness function to run a general Chrome Endure test. |
| 84 | 159 |
| 85 After a test has performed any setup work and has navigated to the proper | 160 After a test has performed any setup work and has navigated to the proper |
| 86 starting webpage, this function should be invoked to run the endurance test. | 161 starting webpage, this function should be invoked to run the endurance test. |
| 87 | 162 |
| 88 Args: | 163 Args: |
| 89 webapp_name: A string name for the webapp being tested. Should not | 164 webapp_name: A string name for the webapp being tested. Should not |
| 90 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. | 165 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. |
| 91 tab_title_substring: A unique substring contained within the title of | 166 tab_title_substring: A unique substring contained within the title of |
| 92 the tab to use, for identifying the appropriate tab. | 167 the tab to use, for identifying the appropriate tab. |
| 93 test_description: A string description of what the test does, used for | 168 test_description: A string description of what the test does, used for |
| 94 outputting results to be graphed. Should not contain spaces. For | 169 outputting results to be graphed. Should not contain spaces. For |
| 95 example, 'ComposeDiscard' for Gmail. | 170 example, 'ComposeDiscard' for Gmail. |
| 96 do_scenario: A callable to be invoked that implements the scenario to be | 171 do_scenario: A callable to be invoked that implements the scenario to be |
| 97 performed by this test. The callable is invoked iteratively for the | 172 performed by this test. The callable is invoked iteratively for the |
| 98 duration of the test. | 173 duration of the test. |
| 99 """ | 174 """ |
| 100 self._num_errors = 0 | 175 self._num_errors = 0 |
| 101 self._test_start_time = time.time() | 176 self._test_start_time = time.time() |
| 102 last_perf_stats_time = time.time() | 177 last_perf_stats_time = time.time() |
| 178 # Note: this variable will be removed when committing. | |
| 179 last_deep_memory_profile_time = time.time() | |
| 103 self._GetPerformanceStats( | 180 self._GetPerformanceStats( |
| 104 webapp_name, test_description, tab_title_substring) | 181 webapp_name, test_description, tab_title_substring) |
| 105 self._iteration_num = 0 | 182 self._iteration_num = 0 |
| 106 while time.time() - self._test_start_time < self._test_length_sec: | 183 while time.time() - self._test_start_time < self._test_length_sec: |
| 107 self._iteration_num += 1 | 184 self._iteration_num += 1 |
| 108 | 185 |
| 109 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: | 186 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: |
| 110 logging.error('Error count threshold (%d) reached. Terminating test ' | 187 logging.error('Error count threshold (%d) reached. Terminating test ' |
| 111 'early.' % self._ERROR_COUNT_THRESHOLD) | 188 'early.' % self._ERROR_COUNT_THRESHOLD) |
| 112 break | 189 break |
| 113 | 190 |
| 191 # Note: this block will be removed when committing. | |
| 192 # TODO(dmikurube): Need pid of the target process. | |
| 193 if (self._deep_memory_profile_interval > 0 and | |
| 194 time.time() - last_deep_memory_profile_time >= | |
| 195 self._deep_memory_profile_interval): | |
| 196 last_deep_memory_profile_time = time.time() | |
| 197 logging.info('HeapProfilerDump would be called here.') | |
| 198 | |
| 114 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: | 199 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: |
| 115 last_perf_stats_time = time.time() | 200 last_perf_stats_time = time.time() |
| 116 self._GetPerformanceStats( | 201 self._GetPerformanceStats( |
| 117 webapp_name, test_description, tab_title_substring) | 202 webapp_name, test_description, tab_title_substring) |
| 118 | 203 |
| 119 if self._iteration_num % 10 == 0: | 204 if self._iteration_num % 10 == 0: |
| 120 remaining_time = self._test_length_sec - (time.time() - | 205 remaining_time = self._test_length_sec - (time.time() - |
| 121 self._test_start_time) | 206 self._test_start_time) |
| 122 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % | 207 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % |
| 123 (self._iteration_num, remaining_time)) | 208 (self._iteration_num, remaining_time)) |
| 124 | 209 |
| 125 do_scenario() | 210 do_scenario() |
| 126 | 211 |
| 212 # Note: this block will be removed when committing. | |
| 213 if self._deep_memory_profile_interval > 0: | |
| 214 logging.info('HeapProfilerDump would be called here.') | |
| 215 | |
| 127 self._GetPerformanceStats( | 216 self._GetPerformanceStats( |
| 128 webapp_name, test_description, tab_title_substring) | 217 webapp_name, test_description, tab_title_substring, is_last=True) |
| 129 | 218 |
| 130 def _GetProcessInfo(self, tab_title_substring): | 219 def _GetProcessInfo(self, tab_title_substring): |
| 131 """Gets process info associated with an open browser/tab. | 220 """Gets process info associated with an open browser/tab. |
| 132 | 221 |
| 133 Args: | 222 Args: |
| 134 tab_title_substring: A unique substring contained within the title of | 223 tab_title_substring: A unique substring contained within the title of |
| 135 the tab to use; needed for locating the tab info. | 224 the tab to use; needed for locating the tab info. |
| 136 | 225 |
| 137 Returns: | 226 Returns: |
| 138 A dictionary containing information about the browser and specified tab | 227 A dictionary containing information about the browser and specified tab |
| 139 process: | 228 process: |
| 140 { | 229 { |
| 141 'browser_private_mem': integer, # Private memory associated with the | 230 'browser_private_mem': integer, # Private memory associated with the |
| 142 # browser process, in KB. | 231 # browser process, in KB. |
| 143 'tab_private_mem': integer, # Private memory associated with the tab | 232 'tab_private_mem': integer, # Private memory associated with the tab |
| 144 # process, in KB. | 233 # process, in KB. |
| 234 'tab_pid': integer, # Process ID of the tab process. | |
| 145 } | 235 } |
| 146 """ | 236 """ |
| 147 browser_process_name = ( | 237 browser_process_name = ( |
| 148 self.GetBrowserInfo()['properties']['BrowserProcessExecutableName']) | 238 self.GetBrowserInfo()['properties']['BrowserProcessExecutableName']) |
| 149 info = self.GetProcessInfo() | 239 info = self.GetProcessInfo() |
| 150 | 240 |
| 151 # Get the information associated with the browser process. | 241 # Get the information associated with the browser process. |
| 152 browser_proc_info = [] | 242 browser_proc_info = [] |
| 153 for browser_info in info['browsers']: | 243 for browser_info in info['browsers']: |
| 154 if browser_info['process_name'] == browser_process_name: | 244 if browser_info['process_name'] == browser_process_name: |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 171 msg='Expected to find 1 %s tab process, but found %d ' | 261 msg='Expected to find 1 %s tab process, but found %d ' |
| 172 'instead.\nCurrent process info:\n%s.' % ( | 262 'instead.\nCurrent process info:\n%s.' % ( |
| 173 tab_title_substring, len(tab_proc_info), | 263 tab_title_substring, len(tab_proc_info), |
| 174 self.pformat(info))) | 264 self.pformat(info))) |
| 175 | 265 |
| 176 browser_proc_info = browser_proc_info[0] | 266 browser_proc_info = browser_proc_info[0] |
| 177 tab_proc_info = tab_proc_info[0] | 267 tab_proc_info = tab_proc_info[0] |
| 178 return { | 268 return { |
| 179 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], | 269 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], |
| 180 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], | 270 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], |
| 271 'tab_pid': tab_proc_info['pid'], | |
| 181 } | 272 } |
| 182 | 273 |
| 183 def _GetPerformanceStats(self, webapp_name, test_description, | 274 def _GetPerformanceStats(self, webapp_name, test_description, |
| 184 tab_title_substring): | 275 tab_title_substring, is_last=False): |
| 185 """Gets performance statistics and outputs the results. | 276 """Gets performance statistics and outputs the results. |
| 186 | 277 |
| 187 Args: | 278 Args: |
| 188 webapp_name: A string name for the webapp being tested. Should not | 279 webapp_name: A string name for the webapp being tested. Should not |
| 189 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. | 280 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. |
| 190 test_description: A string description of what the test does, used for | 281 test_description: A string description of what the test does, used for |
| 191 outputting results to be graphed. Should not contain spaces. For | 282 outputting results to be graphed. Should not contain spaces. For |
| 192 example, 'ComposeDiscard' for Gmail. | 283 example, 'ComposeDiscard' for Gmail. |
| 193 tab_title_substring: A unique substring contained within the title of | 284 tab_title_substring: A unique substring contained within the title of |
| 194 the tab to use, for identifying the appropriate tab. | 285 the tab to use, for identifying the appropriate tab. |
| 286 is_last: A boolean value which should be True if it's the last call of | |
| 287 _GetPerformanceStats. The default is False. | |
| 195 """ | 288 """ |
| 196 logging.info('Gathering performance stats...') | 289 logging.info('Gathering performance stats...') |
| 197 elapsed_time = time.time() - self._test_start_time | 290 elapsed_time = time.time() - self._test_start_time |
| 198 elapsed_time = int(round(elapsed_time)) | 291 elapsed_time = int(round(elapsed_time)) |
| 199 | 292 |
| 200 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() | 293 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() |
| 201 | 294 |
| 202 dom_node_count = memory_counts['DOMNodeCount'] | 295 dom_node_count = memory_counts['DOMNodeCount'] |
| 203 logging.info(' Total DOM node count: %d nodes' % dom_node_count) | 296 logging.info(' Total DOM node count: %d nodes' % dom_node_count) |
| 204 self._dom_node_count_results.append((elapsed_time, dom_node_count)) | 297 self._dom_node_count_results.append((elapsed_time, dom_node_count)) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 216 logging.info(' Tab process private memory: %d KB' % | 309 logging.info(' Tab process private memory: %d KB' % |
| 217 proc_info['tab_private_mem']) | 310 proc_info['tab_private_mem']) |
| 218 self._tab_process_private_mem_results.append( | 311 self._tab_process_private_mem_results.append( |
| 219 (elapsed_time, proc_info['tab_private_mem'])) | 312 (elapsed_time, proc_info['tab_private_mem'])) |
| 220 | 313 |
| 221 v8_info = self.GetV8HeapStats() # First window, first tab. | 314 v8_info = self.GetV8HeapStats() # First window, first tab. |
| 222 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. | 315 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. |
| 223 logging.info(' V8 memory used: %f KB' % v8_mem_used) | 316 logging.info(' V8 memory used: %f KB' % v8_mem_used) |
| 224 self._v8_mem_used_results.append((elapsed_time, v8_mem_used)) | 317 self._v8_mem_used_results.append((elapsed_time, v8_mem_used)) |
| 225 | 318 |
| 319 # TODO(dmikurube): A part of this block should be carved out as a function. | |
| 320 if self._deep_memory_profile_interval > 0: | |
| 321 logging.info('Profiling with the Deep Memory Profiler...') | |
| 322 | |
| 323 # Wait for a running dmprof process for last _GetPerformanceStat call to | |
| 324 # cover last dump files. | |
| 325 if is_last and self._deep_memory_profile_proc: | |
| 326 logging.info(' Waiting for the last dmprof.') | |
| 327 self._deep_memory_profile_proc.wait() | |
| 328 self._deep_memory_profile_proc = None | |
| 329 if self._deep_memory_profile_json_f: | |
| 330 self._deep_memory_profile_last_json_filename = ( | |
| 331 self._deep_memory_profile_json_f.name) | |
| 332 self._deep_memory_profile_json_f.close() | |
| 333 self._deep_memory_profile_json_f = None | |
| 334 | |
| 335 if (self._deep_memory_profile_proc and | |
| 336 self._deep_memory_profile_proc.poll() is None): | |
| 337 logging.info(' Last dmprof is still running.') | |
| 338 else: | |
| 339 if self._deep_memory_profile_json_f: | |
| 340 self._deep_memory_profile_last_json_filename = ( | |
| 341 self._deep_memory_profile_json_f.name) | |
| 342 self._deep_memory_profile_json_f.close() | |
| 343 self._deep_memory_profile_json_f = None | |
| 344 first_dump = '' | |
| 345 last_dump = '' | |
| 346 for filename in sorted(os.listdir(self._deep_tempdir)): | |
| 347 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'], | |
| 348 filename): | |
| 349 logging.info(' Profiled dump file: %s' % filename) | |
| 350 last_dump = filename | |
| 351 if not first_dump: | |
| 352 first_dump = filename | |
| 353 if first_dump: | |
| 354 logging.info(' First dump file: %s' % first_dump) | |
| 355 matched= re.match('^endure.\d+.(\d+).heap$', last_dump) | |
| 356 last_sequence_id = matched.group(1) | |
| 357 self._deep_memory_profile_json_f = open( | |
| 358 os.path.join(self._deep_tempdir, | |
| 359 'endure.%05d.%s.json' % (proc_info['tab_pid'], | |
| 360 last_sequence_id)), 'w+') | |
| 361 self._deep_memory_profile_proc = subprocess.Popen( | |
| 362 '%s --json %s %s %s' % (self._DMPROF_SCRIPT_PATH, | |
| 363 self._CHROME_BIN_PATH, | |
| 364 os.path.join(self._DMPROF_DIR_PATH, | |
| 365 'policy.l2.txt'), | |
| 366 os.path.join(self._deep_tempdir, | |
| 367 first_dump)), | |
| 368 shell=True, stdout=self._deep_memory_profile_json_f) | |
| 369 # Don't wait for the new process since dmprof may take long time. | |
| 370 | |
| 371 if is_last: | |
| 372 self._deep_memory_profile_proc.wait() | |
| 373 self._deep_memory_profile_last_json_filename = ( | |
| 374 self._deep_memory_profile_json_f.name) | |
| 375 self._deep_memory_profile_json_f.close() | |
| 376 | |
| 377 else: | |
| 378 logging.info(' No dump files.') | |
| 379 | |
| 226 # Output the results seen so far, to be graphed. | 380 # Output the results seen so far, to be graphed. |
| 227 self._OutputPerfGraphValue( | 381 self._OutputPerfGraphValue( |
| 228 'TotalDOMNodeCount', self._dom_node_count_results, 'nodes', | 382 'TotalDOMNodeCount', self._dom_node_count_results, 'nodes', |
| 229 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), | 383 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), |
| 230 units_x='seconds') | 384 units_x='seconds') |
| 231 self._OutputPerfGraphValue( | 385 self._OutputPerfGraphValue( |
| 232 'EventListenerCount', self._event_listener_count_results, 'listeners', | 386 'EventListenerCount', self._event_listener_count_results, 'listeners', |
| 233 graph_name='%s%s-EventListeners' % (webapp_name, test_description), | 387 graph_name='%s%s-EventListeners' % (webapp_name, test_description), |
| 234 units_x='seconds') | 388 units_x='seconds') |
| 235 self._OutputPerfGraphValue( | 389 self._OutputPerfGraphValue( |
| 236 'BrowserPrivateMemory', self._browser_process_private_mem_results, 'KB', | 390 'BrowserPrivateMemory', self._browser_process_private_mem_results, 'KB', |
| 237 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), | 391 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), |
| 238 units_x='seconds') | 392 units_x='seconds') |
| 239 self._OutputPerfGraphValue( | 393 self._OutputPerfGraphValue( |
| 240 'TabPrivateMemory', self._tab_process_private_mem_results, 'KB', | 394 'TabPrivateMemory', self._tab_process_private_mem_results, 'KB', |
| 241 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), | 395 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), |
| 242 units_x='seconds') | 396 units_x='seconds') |
| 243 self._OutputPerfGraphValue( | 397 self._OutputPerfGraphValue( |
| 244 'V8MemoryUsed', self._v8_mem_used_results, 'KB', | 398 'V8MemoryUsed', self._v8_mem_used_results, 'KB', |
| 245 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), | 399 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), |
| 246 units_x='seconds') | 400 units_x='seconds') |
| 401 if self._deep_memory_profile_interval > 0: | |
| 402 deep_memory_profile_results = {} | |
| 403 if self._deep_memory_profile_last_json_filename: | |
| 404 json_data = {} | |
| 405 with open(self._deep_memory_profile_last_json_filename) as json_f: | |
| 406 json_data = json.load(json_f) | |
| 407 if json_data['version'] == 'JSON_DEEP_1': | |
| 408 for component in json_data['legends']: | |
| 409 deep_memory_profile_results[component] = [] | |
| 410 for snapshot in json_data['snapshots']: | |
| 411 deep_memory_profile_results[component].append(snapshot[component]) | |
| 412 # TODO(dmikurube): Output graph values (for multi-lined graphs), here. | |
| 413 # 'deep_memory_profile_results' is the value to be output. | |
| 247 | 414 |
| 248 def _GetElement(self, find_by, value): | 415 def _GetElement(self, find_by, value): |
| 249 """Gets a WebDriver element object from the webpage DOM. | 416 """Gets a WebDriver element object from the webpage DOM. |
| 250 | 417 |
| 251 Args: | 418 Args: |
| 252 find_by: A callable that queries WebDriver for an element from the DOM. | 419 find_by: A callable that queries WebDriver for an element from the DOM. |
| 253 value: A string value that can be passed to the |find_by| callable. | 420 value: A string value that can be passed to the |find_by| callable. |
| 254 | 421 |
| 255 Returns: | 422 Returns: |
| 256 The identified WebDriver element object, if found in the DOM, or | 423 The identified WebDriver element object, if found in the DOM, or |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 self._driver, self._wait, 'id("state")[text()="offline"]'): | 1005 self._driver, self._wait, 'id("state")[text()="offline"]'): |
| 839 self._num_errors += 1 | 1006 self._num_errors += 1 |
| 840 time.sleep(1) | 1007 time.sleep(1) |
| 841 | 1008 |
| 842 self._RunEndureTest(self._webapp_name, self._tab_title_substring, | 1009 self._RunEndureTest(self._webapp_name, self._tab_title_substring, |
| 843 test_description, scenario) | 1010 test_description, scenario) |
| 844 | 1011 |
| 845 | 1012 |
| 846 if __name__ == '__main__': | 1013 if __name__ == '__main__': |
| 847 pyauto_functional.Main() | 1014 pyauto_functional.Main() |
| OLD | NEW |