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 DEEP_MEMORY_PROFILE_INTERVAL: The number of seconds to wait in-between each | |
|
dennis_jeffrey
2012/04/17 01:20:27
nit: add a blank line above this to separate the D
dennis_jeffrey
2012/04/17 01:20:27
Right now, this variable seems to control whether
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
I thought about such a flag to turn on/off, but I
dennis_jeffrey
2012/04/17 22:36:14
I thought about setting the default to 0, but then
Dai Mikurube (NOT FULLTIME)
2012/04/18 04:59:51
Basically agreed. Added an env "DEEP_MEMORY_PROFI
| |
| 13 sampling for the Deep Memory Profiler. | |
| 14 DEEP_MEMORY_PROFILE_SAVE: Don't clean-up profile dump files if it's set. | |
| 12 """ | 15 """ |
| 13 | 16 |
| 17 from datetime import datetime | |
| 14 import logging | 18 import logging |
| 15 import os | 19 import os |
| 16 import re | 20 import re |
| 21 import shutil | |
| 22 import subprocess | |
| 23 import tempfile | |
| 17 import time | 24 import time |
| 18 | 25 |
| 19 import perf | 26 import perf |
| 20 import pyauto_functional # Must be imported before pyauto. | 27 import pyauto_functional # Must be imported before pyauto. |
| 21 import pyauto | 28 import pyauto |
| 22 import remote_inspector_client | 29 import remote_inspector_client |
| 23 import selenium.common.exceptions | 30 import selenium.common.exceptions |
| 24 from selenium.webdriver.support.ui import WebDriverWait | 31 from selenium.webdriver.support.ui import WebDriverWait |
| 25 | 32 |
| 26 | |
| 27 class ChromeEndureBaseTest(perf.BasePerfTest): | 33 class ChromeEndureBaseTest(perf.BasePerfTest): |
| 28 """Implements common functionality for all Chrome Endure tests. | 34 """Implements common functionality for all Chrome Endure tests. |
| 29 | 35 |
| 30 All Chrome Endure test classes should inherit from this class. | 36 All Chrome Endure test classes should inherit from this class. |
| 31 """ | 37 """ |
| 32 | 38 |
| 33 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. | 39 _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. | 40 _GET_PERF_STATS_INTERVAL = 60 * 10 # Measure perf stats every 10 minutes. |
| 35 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. | 41 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. |
| 42 _DEEP_MEMORY_PROFILE_INTERVAL = _GET_PERF_STATS_INTERVAL | |
| 43 _DEEP_MEMORY_PROFILE_SAVE = False | |
| 44 | |
| 45 _DMPROF_DIR_PATH = os.path.join(os.path.dirname(__file__), | |
| 46 os.pardir, | |
| 47 os.pardir, | |
| 48 os.pardir, | |
| 49 'tools', | |
| 50 'deep_memory_profiler') | |
|
dennis_jeffrey
2012/04/17 01:20:27
I recommend fitting as many parameters as you can
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 51 | |
| 52 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, | |
| 53 'dmprof') | |
|
dennis_jeffrey
2012/04/17 01:20:27
this can probably fit on the previous line
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 54 | |
| 55 # TODO(dmikurube): Need to find an actual running chrome. | |
| 56 _CHROME_BIN_PATH = os.path.join(os.path.dirname(__file__), | |
| 57 os.pardir, | |
| 58 os.pardir, | |
| 59 os.pardir, | |
| 60 'out', | |
| 61 'Debug', | |
| 62 'chrome') | |
|
dennis_jeffrey
2012/04/17 01:20:27
same comment as line 50 above
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 36 | 63 |
| 37 def setUp(self): | 64 def setUp(self): |
| 65 # These environment variables for the Deep Memory Profiler must be set | |
| 66 # before perf.BasePerfTest.setUp() to inherit them to Chrome. | |
| 67 self._deep_memory_profile_interval = 0 | |
| 68 if self.IsLinux(): | |
| 69 self._deep_memory_profile_interval = int( | |
| 70 os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL', | |
| 71 self._DEEP_MEMORY_PROFILE_INTERVAL)) | |
| 72 | |
| 73 if self._deep_memory_profile_interval > 0: | |
| 74 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S') | |
| 75 self._deep_tempdir = tempfile.mkdtemp(prefix=dir_prefix) | |
| 76 os.environ['HEAPPROFILE'] = os.path.join(self._deep_tempdir, 'endure') | |
| 77 os.environ['HEAP_PROFILE_MMAP'] = 'True' | |
| 78 os.environ['DEEP_HEAP_PROFILE'] = 'True' | |
| 79 # TODO(dmikurube): Remove it when renderer dump is supported in PyAuto | |
|
dennis_jeffrey
2012/04/17 01:20:27
remove what - the following environment variable d
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Changed it to:
Stop to set HEAP_PROFILE_TIME_INTER
| |
| 80 os.environ['HEAP_PROFILE_TIME_INTERVAL'] = ( | |
| 81 '%d' % self._deep_memory_profile_interval) | |
| 82 | |
| 38 perf.BasePerfTest.setUp(self) | 83 perf.BasePerfTest.setUp(self) |
| 39 | 84 |
| 40 self._test_length_sec = int( | 85 self._test_length_sec = int( |
| 41 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) | 86 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) |
| 42 self._get_perf_stats_interval = int( | 87 self._get_perf_stats_interval = int( |
| 43 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) | 88 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) |
| 44 | 89 |
| 90 self._deep_memory_profile_save = False | |
| 91 if self.IsLinux(): | |
| 92 self._deep_memory_profile_save = bool( | |
| 93 os.environ.get('DEEP_MEMORY_PROFILE_SAVE', | |
| 94 self._DEEP_MEMORY_PROFILE_SAVE)) | |
| 95 | |
| 45 logging.info('Running test for %d seconds.', self._test_length_sec) | 96 logging.info('Running test for %d seconds.', self._test_length_sec) |
| 46 logging.info('Gathering perf stats every %d seconds.', | 97 logging.info('Gathering perf stats every %d seconds.', |
| 47 self._get_perf_stats_interval) | 98 self._get_perf_stats_interval) |
| 99 if self._deep_memory_profile_interval > 0: | |
| 100 logging.info('Running with the Deep Memory Profiler every %d seconds.', | |
| 101 self._deep_memory_profile_interval) | |
| 102 if self._deep_memory_profile_save: | |
| 103 logging.info('Dump files by the Deep Memory Profiler are not cleaned.') | |
| 48 | 104 |
| 49 # Set up a remote inspector client associated with tab 0. | 105 # Set up a remote inspector client associated with tab 0. |
| 50 logging.info('Setting up connection to remote inspector...') | 106 logging.info('Setting up connection to remote inspector...') |
| 51 self._remote_inspector_client = ( | 107 self._remote_inspector_client = ( |
| 52 remote_inspector_client.RemoteInspectorClient()) | 108 remote_inspector_client.RemoteInspectorClient()) |
| 53 logging.info('Connection to remote inspector set up successfully.') | 109 logging.info('Connection to remote inspector set up successfully.') |
| 54 | 110 |
| 55 self._dom_node_count_results = [] | 111 self._dom_node_count_results = [] |
| 56 self._event_listener_count_results = [] | 112 self._event_listener_count_results = [] |
| 57 self._browser_process_private_mem_results = [] | 113 self._browser_process_private_mem_results = [] |
| 58 self._tab_process_private_mem_results = [] | 114 self._tab_process_private_mem_results = [] |
| 59 self._v8_mem_used_results = [] | 115 self._v8_mem_used_results = [] |
| 60 self._test_start_time = 0 | 116 self._test_start_time = 0 |
| 61 self._num_errors = 0 | 117 self._num_errors = 0 |
| 62 self._iteration_num = 0 | 118 self._iteration_num = 0 |
| 119 self._deep_memory_profile_json = None | |
|
dennis_jeffrey
2012/04/17 01:20:27
The variable name here suggests that it will store
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Added '_f'.
| |
| 120 self._deep_memory_profile_proc = None | |
| 63 | 121 |
| 64 def tearDown(self): | 122 def tearDown(self): |
| 65 logging.info('Terminating connection to remote inspector...') | 123 logging.info('Terminating connection to remote inspector...') |
| 66 self._remote_inspector_client.Stop() | 124 self._remote_inspector_client.Stop() |
| 67 logging.info('Connection to remote inspector terminated.') | 125 logging.info('Connection to remote inspector terminated.') |
| 126 if self._deep_memory_profile_interval > 0: | |
| 127 # TODO(dmikurube): Remove it when renderer dump is supported in PyAuto | |
|
dennis_jeffrey
2012/04/17 01:20:27
remove what? the next line? the next 4 lines?
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Changed in the same way above.
| |
| 128 del os.environ['HEAP_PROFILE_TIME_INTERVAL'] | |
| 129 del os.environ['DEEP_HEAP_PROFILE'] | |
| 130 del os.environ['HEAP_PROFILE_MMAP'] | |
| 131 del os.environ['HEAPPROFILE'] | |
| 68 perf.BasePerfTest.tearDown(self) # Must be done at end of this function. | 132 perf.BasePerfTest.tearDown(self) # Must be done at end of this function. |
| 133 if not self._deep_memory_profile_save: | |
| 134 shutil.rmtree(self._deep_tempdir) | |
|
dennis_jeffrey
2012/04/17 01:20:27
we can invoke pyauto_utils.RemovePath() here inste
dennis_jeffrey
2012/04/17 01:20:27
be careful, I don't think we can assume that self.
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Added conditions.
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done... but top of the file?
| |
| 69 | 135 |
| 70 def ExtraChromeFlags(self): | 136 def ExtraChromeFlags(self): |
| 71 """Ensures Chrome is launched with custom flags. | 137 """Ensures Chrome is launched with custom flags. |
| 72 | 138 |
| 73 Returns: | 139 Returns: |
| 74 A list of extra flags to pass to Chrome when it is launched. | 140 A list of extra flags to pass to Chrome when it is launched. |
| 75 """ | 141 """ |
| 142 deep_memory_profile_interval = 0 | |
| 143 if self.IsLinux(): | |
| 144 deep_memory_profile_interval = int( | |
| 145 os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL', | |
| 146 self._DEEP_MEMORY_PROFILE_INTERVAL)) | |
|
dennis_jeffrey
2012/04/17 01:20:27
isn't this work already done in setUp() above?
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
ExtraChromeFlags looks like called before setUp().
dennis_jeffrey
2012/04/17 22:36:14
Ok - then maybe it's best to write a little helper
Dai Mikurube (NOT FULLTIME)
2012/04/18 04:59:51
Since I'm not sure that ExtraChromeFlags is always
| |
| 147 | |
| 76 # Ensure Chrome enables remote debugging on port 9222. This is required to | 148 # Ensure Chrome enables remote debugging on port 9222. This is required to |
| 77 # interact with Chrome's remote inspector. | 149 # interact with Chrome's remote inspector. |
| 78 return (perf.BasePerfTest.ExtraChromeFlags(self) + | 150 if deep_memory_profile_interval > 0: |
| 79 ['--remote-debugging-port=9222']) | 151 return (perf.BasePerfTest.ExtraChromeFlags(self) + |
| 152 ['--remote-debugging-port=9222', '--no-sandbox']) | |
| 153 else: | |
| 154 return (perf.BasePerfTest.ExtraChromeFlags(self) + | |
| 155 ['--remote-debugging-port=9222']) | |
|
dennis_jeffrey
2012/04/17 01:20:27
extra_flags = ['--remote-debugging-port=9222']
if
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 80 | 156 |
| 81 def _RunEndureTest(self, webapp_name, tab_title_substring, test_description, | 157 def _RunEndureTest(self, webapp_name, tab_title_substring, test_description, |
| 82 do_scenario): | 158 do_scenario): |
| 83 """The main test harness function to run a general Chrome Endure test. | 159 """The main test harness function to run a general Chrome Endure test. |
| 84 | 160 |
| 85 After a test has performed any setup work and has navigated to the proper | 161 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. | 162 starting webpage, this function should be invoked to run the endurance test. |
| 87 | 163 |
| 88 Args: | 164 Args: |
| 89 webapp_name: A string name for the webapp being tested. Should not | 165 webapp_name: A string name for the webapp being tested. Should not |
| 90 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. | 166 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. |
| 91 tab_title_substring: A unique substring contained within the title of | 167 tab_title_substring: A unique substring contained within the title of |
| 92 the tab to use, for identifying the appropriate tab. | 168 the tab to use, for identifying the appropriate tab. |
| 93 test_description: A string description of what the test does, used for | 169 test_description: A string description of what the test does, used for |
| 94 outputting results to be graphed. Should not contain spaces. For | 170 outputting results to be graphed. Should not contain spaces. For |
| 95 example, 'ComposeDiscard' for Gmail. | 171 example, 'ComposeDiscard' for Gmail. |
| 96 do_scenario: A callable to be invoked that implements the scenario to be | 172 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 | 173 performed by this test. The callable is invoked iteratively for the |
| 98 duration of the test. | 174 duration of the test. |
| 99 """ | 175 """ |
| 100 self._num_errors = 0 | 176 self._num_errors = 0 |
| 101 self._test_start_time = time.time() | 177 self._test_start_time = time.time() |
| 102 last_perf_stats_time = time.time() | 178 last_perf_stats_time = time.time() |
| 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. | |
|
dennis_jeffrey
2012/04/17 01:20:27
if this block will get removed before committing,
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Ok, added a commment.
| |
| 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('HeapProfileDump 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('HeapProfileDump 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, True) |
|
dennis_jeffrey
2012/04/17 01:20:27
is_last=True
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 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 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 171 msg='Expected to find 1 %s tab process, but found %d ' | 260 msg='Expected to find 1 %s tab process, but found %d ' |
| 172 'instead.\nCurrent process info:\n%s.' % ( | 261 'instead.\nCurrent process info:\n%s.' % ( |
| 173 tab_title_substring, len(tab_proc_info), | 262 tab_title_substring, len(tab_proc_info), |
| 174 self.pformat(info))) | 263 self.pformat(info))) |
| 175 | 264 |
| 176 browser_proc_info = browser_proc_info[0] | 265 browser_proc_info = browser_proc_info[0] |
| 177 tab_proc_info = tab_proc_info[0] | 266 tab_proc_info = tab_proc_info[0] |
| 178 return { | 267 return { |
| 179 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], | 268 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], |
| 180 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], | 269 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], |
| 270 'tab_pid': tab_proc_info['pid'], | |
| 181 } | 271 } |
| 182 | 272 |
| 183 def _GetPerformanceStats(self, webapp_name, test_description, | 273 def _GetPerformanceStats(self, webapp_name, test_description, |
| 184 tab_title_substring): | 274 tab_title_substring, is_last=False): |
| 185 """Gets performance statistics and outputs the results. | 275 """Gets performance statistics and outputs the results. |
| 186 | 276 |
| 187 Args: | 277 Args: |
| 188 webapp_name: A string name for the webapp being tested. Should not | 278 webapp_name: A string name for the webapp being tested. Should not |
| 189 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. | 279 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. |
| 190 test_description: A string description of what the test does, used for | 280 test_description: A string description of what the test does, used for |
| 191 outputting results to be graphed. Should not contain spaces. For | 281 outputting results to be graphed. Should not contain spaces. For |
| 192 example, 'ComposeDiscard' for Gmail. | 282 example, 'ComposeDiscard' for Gmail. |
| 193 tab_title_substring: A unique substring contained within the title of | 283 tab_title_substring: A unique substring contained within the title of |
| 194 the tab to use, for identifying the appropriate tab. | 284 the tab to use, for identifying the appropriate tab. |
|
dennis_jeffrey
2012/04/17 01:20:27
describe the new is_last argument
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Done.
| |
| 195 """ | 285 """ |
| 196 logging.info('Gathering performance stats...') | 286 logging.info('Gathering performance stats...') |
| 197 elapsed_time = time.time() - self._test_start_time | 287 elapsed_time = time.time() - self._test_start_time |
| 198 elapsed_time = int(round(elapsed_time)) | 288 elapsed_time = int(round(elapsed_time)) |
| 199 | 289 |
| 200 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() | 290 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() |
| 201 | 291 |
| 202 dom_node_count = memory_counts['DOMNodeCount'] | 292 dom_node_count = memory_counts['DOMNodeCount'] |
| 203 logging.info(' Total DOM node count: %d nodes' % dom_node_count) | 293 logging.info(' Total DOM node count: %d nodes' % dom_node_count) |
| 204 self._dom_node_count_results.append((elapsed_time, dom_node_count)) | 294 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' % | 306 logging.info(' Tab process private memory: %d KB' % |
| 217 proc_info['tab_private_mem']) | 307 proc_info['tab_private_mem']) |
| 218 self._tab_process_private_mem_results.append( | 308 self._tab_process_private_mem_results.append( |
| 219 (elapsed_time, proc_info['tab_private_mem'])) | 309 (elapsed_time, proc_info['tab_private_mem'])) |
| 220 | 310 |
| 221 v8_info = self.GetV8HeapStats() # First window, first tab. | 311 v8_info = self.GetV8HeapStats() # First window, first tab. |
| 222 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. | 312 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. |
| 223 logging.info(' V8 memory used: %f KB' % v8_mem_used) | 313 logging.info(' V8 memory used: %f KB' % v8_mem_used) |
| 224 self._v8_mem_used_results.append((elapsed_time, v8_mem_used)) | 314 self._v8_mem_used_results.append((elapsed_time, v8_mem_used)) |
| 225 | 315 |
| 316 if is_last and self._deep_memory_profile_proc: | |
|
dennis_jeffrey
2012/04/17 01:20:27
should this check go inside the condition at line
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Exactly. Moved this block into :
"if self._deep_m
| |
| 317 self._deep_memory_profile_proc.wait() | |
| 318 self._deep_memory_profile_proc = None | |
| 319 if self._deep_memory_profile_json: | |
| 320 self._deep_memory_profile_json.close() | |
| 321 self._deep_memory_profile_json = None | |
| 322 | |
| 323 # TODO(dmikurube): Add --single in dmprof.py? | |
| 324 # TODO(dmikurube): Avoid broken (or ongoing) profile dumps in dmprof. | |
| 325 if self._deep_memory_profile_interval > 0: | |
| 326 logging.info('Profiling with the Deep Memory Profiler...') | |
| 327 if (self._deep_memory_profile_proc and | |
| 328 self._deep_memory_profile_proc.poll() is None): | |
| 329 logging.info(' Last dmprof is still running.') | |
|
dennis_jeffrey
2012/04/17 01:20:27
Is it ok to just skip the dump analysis on this in
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Actually, a single dmprof run for 'first_dump' wil
dennis_jeffrey
2012/04/17 22:36:14
Ok. This shouldn't have any impact on the memory
Dai Mikurube (NOT FULLTIME)
2012/04/18 04:59:51
No impact. Profile data have already been dumped
| |
| 330 else: | |
| 331 if self._deep_memory_profile_json: | |
| 332 self._deep_memory_profile_json.close() | |
| 333 self._deep_memory_profile_json = None | |
| 334 first_dump = '' | |
| 335 last_dump = '' | |
| 336 for filename in sorted(os.listdir(self._deep_tempdir)): | |
| 337 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'], | |
| 338 filename): | |
| 339 logging.info(' Profiled dump file: %s' % filename) | |
| 340 last_dump = filename | |
| 341 if not first_dump: | |
| 342 first_dump = filename | |
| 343 if first_dump: | |
| 344 logging.info(' First dump file: %s' % first_dump) | |
| 345 matched= re.match('^endure.\d+.(\d+).heap$', last_dump) | |
| 346 last_sequence_id = matched.group(1) | |
| 347 self._deep_memory_profile_json = open( | |
| 348 os.path.join(self._deep_tempdir, | |
| 349 'endure.%05d.%s.json' % (proc_info['tab_pid'], | |
| 350 last_sequence_id)), 'w+') | |
| 351 self._deep_memory_profile_proc = subprocess.Popen( | |
| 352 '%s --json %s %s %s' % (self._DMPROF_SCRIPT_PATH, | |
| 353 self._CHROME_BIN_PATH, | |
| 354 os.path.join(self._DMPROF_DIR_PATH, | |
| 355 'policy.l2.txt'), | |
| 356 os.path.join(self._deep_tempdir, | |
| 357 first_dump)), | |
| 358 shell=True, stdout=self._deep_memory_profile_json) | |
| 359 # Don't wait since dmprof may take long time. | |
| 360 | |
| 361 if is_last: | |
| 362 self._deep_memory_profile_proc.wait() | |
| 363 self._deep_memory_profile_json.close() | |
| 364 | |
| 365 else: | |
| 366 logging.info(' No dump files.') | |
| 367 | |
| 368 # 2) Parse .json (including only the latest snapshot) file here. | |
|
dennis_jeffrey
2012/04/17 01:20:27
shouldn't this parsing work be inside the "if" at
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Exactly. Moved the comment.
| |
| 369 | |
| 226 # Output the results seen so far, to be graphed. | 370 # Output the results seen so far, to be graphed. |
| 227 self._OutputPerfGraphValue( | 371 self._OutputPerfGraphValue( |
| 228 'TotalDOMNodeCount', self._dom_node_count_results, 'nodes', | 372 'TotalDOMNodeCount', self._dom_node_count_results, 'nodes', |
| 229 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), | 373 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), |
| 230 units_x='seconds') | 374 units_x='seconds') |
| 231 self._OutputPerfGraphValue( | 375 self._OutputPerfGraphValue( |
| 232 'EventListenerCount', self._event_listener_count_results, 'listeners', | 376 'EventListenerCount', self._event_listener_count_results, 'listeners', |
| 233 graph_name='%s%s-EventListeners' % (webapp_name, test_description), | 377 graph_name='%s%s-EventListeners' % (webapp_name, test_description), |
| 234 units_x='seconds') | 378 units_x='seconds') |
| 235 self._OutputPerfGraphValue( | 379 self._OutputPerfGraphValue( |
| 236 'BrowserPrivateMemory', self._browser_process_private_mem_results, 'KB', | 380 'BrowserPrivateMemory', self._browser_process_private_mem_results, 'KB', |
| 237 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), | 381 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), |
| 238 units_x='seconds') | 382 units_x='seconds') |
| 239 self._OutputPerfGraphValue( | 383 self._OutputPerfGraphValue( |
| 240 'TabPrivateMemory', self._tab_process_private_mem_results, 'KB', | 384 'TabPrivateMemory', self._tab_process_private_mem_results, 'KB', |
| 241 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), | 385 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), |
| 242 units_x='seconds') | 386 units_x='seconds') |
| 243 self._OutputPerfGraphValue( | 387 self._OutputPerfGraphValue( |
| 244 'V8MemoryUsed', self._v8_mem_used_results, 'KB', | 388 'V8MemoryUsed', self._v8_mem_used_results, 'KB', |
| 245 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), | 389 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), |
| 246 units_x='seconds') | 390 units_x='seconds') |
| 391 # 3) Do self._OutputPerfGraphValue for multiple lines, here. | |
|
dennis_jeffrey
2012/04/17 01:20:27
What multiple lines need to be outputted here? Sh
Dai Mikurube (NOT FULLTIME)
2012/04/17 06:33:11
Maybe a TODO. I'd like to output data such as:
{
| |
| 247 | 392 |
| 248 def _GetElement(self, find_by, value): | 393 def _GetElement(self, find_by, value): |
| 249 """Gets a WebDriver element object from the webpage DOM. | 394 """Gets a WebDriver element object from the webpage DOM. |
| 250 | 395 |
| 251 Args: | 396 Args: |
| 252 find_by: A callable that queries WebDriver for an element from the DOM. | 397 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. | 398 value: A string value that can be passed to the |find_by| callable. |
| 254 | 399 |
| 255 Returns: | 400 Returns: |
| 256 The identified WebDriver element object, if found in the DOM, or | 401 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"]'): | 983 self._driver, self._wait, 'id("state")[text()="offline"]'): |
| 839 self._num_errors += 1 | 984 self._num_errors += 1 |
| 840 time.sleep(1) | 985 time.sleep(1) |
| 841 | 986 |
| 842 self._RunEndureTest(self._webapp_name, self._tab_title_substring, | 987 self._RunEndureTest(self._webapp_name, self._tab_title_substring, |
| 843 test_description, scenario) | 988 test_description, scenario) |
| 844 | 989 |
| 845 | 990 |
| 846 if __name__ == '__main__': | 991 if __name__ == '__main__': |
| 847 pyauto_functional.Main() | 992 pyauto_functional.Main() |
| OLD | NEW |