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: Enable the Deep Memory Profiler if it's set to 'True'. | |
| 14 DEEP_MEMORY_PROFILE_INTERVAL: The number of seconds to wait in-between each | |
| 15 sampling for the Deep Memory Profiler. | |
| 16 DEEP_MEMORY_PROFILE_SAVE: Don't clean up dump files if it's set to 'True'. | |
| 12 """ | 17 """ |
| 13 | 18 |
| 19 from datetime import datetime | |
| 20 import json | |
| 14 import logging | 21 import logging |
| 15 import os | 22 import os |
| 16 import re | 23 import re |
| 24 import subprocess | |
| 25 import tempfile | |
| 17 import time | 26 import time |
| 18 | 27 |
| 19 import perf | 28 import perf |
| 20 import pyauto_functional # Must be imported before pyauto. | 29 import pyauto_functional # Must be imported before pyauto. |
| 21 import pyauto | 30 import pyauto |
| 31 import pyauto_utils | |
| 22 import remote_inspector_client | 32 import remote_inspector_client |
| 23 import selenium.common.exceptions | 33 import selenium.common.exceptions |
| 24 from selenium.webdriver.support.ui import WebDriverWait | 34 from selenium.webdriver.support.ui import WebDriverWait |
| 25 | 35 |
|
dennis_jeffrey
2012/05/09 04:31:47
add 1 more blank line here
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 26 | |
| 27 class ChromeEndureBaseTest(perf.BasePerfTest): | 36 class ChromeEndureBaseTest(perf.BasePerfTest): |
| 28 """Implements common functionality for all Chrome Endure tests. | 37 """Implements common functionality for all Chrome Endure tests. |
| 29 | 38 |
| 30 All Chrome Endure test classes should inherit from this class. | 39 All Chrome Endure test classes should inherit from this class. |
| 31 """ | 40 """ |
| 32 | 41 |
| 33 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. | 42 _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. | 43 _GET_PERF_STATS_INTERVAL = 60 * 10 # Measure perf stats every 10 minutes. |
| 35 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. | 44 _ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate. |
| 45 _DEEP_MEMORY_PROFILE = False | |
| 46 _DEEP_MEMORY_PROFILE_INTERVAL = _GET_PERF_STATS_INTERVAL | |
| 47 _DEEP_MEMORY_PROFILE_SAVE = False | |
| 48 | |
| 49 _DMPROF_DIR_PATH = os.path.join( | |
| 50 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, | |
| 51 'tools', 'deep_memory_profiler') | |
| 52 | |
| 53 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof') | |
| 54 | |
| 55 _CHROME_BIN_PATH = os.path.join(perf.BasePerfTest.BrowserPath(), 'chrome') | |
|
dennis_jeffrey
2012/05/09 04:31:47
I think we can just say "self.BrowserPath()" here
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Since it's not in "def something(self)", we can't
dennis_jeffrey
2012/05/09 23:03:55
Ah, you're right!
| |
| 36 | 56 |
| 37 def setUp(self): | 57 def setUp(self): |
| 58 # The environment variables for the Deep Memory Profiler must be set | |
| 59 # before perf.BasePerfTest.setUp() to inherit them to Chrome. | |
| 60 self._deep_memory_profile = self.GetDeepMemoryProfileEnv( | |
| 61 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE, False) | |
| 62 print self._deep_memory_profile | |
|
dennis_jeffrey
2012/05/09 04:31:47
i recommend using logging.debug or logging.info, o
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Thanks. Removed this line.
| |
| 63 | |
| 64 self._deep_memory_profile_interval = self.GetDeepMemoryProfileEnv( | |
| 65 'DEEP_MEMORY_PROFILE_INTERVAL', int, | |
| 66 self._DEEP_MEMORY_PROFILE_INTERVAL, 0) | |
| 67 | |
| 68 if self._deep_memory_profile: | |
| 69 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S') | |
| 70 self._deep_tempdir = tempfile.mkdtemp(prefix=dir_prefix) | |
| 71 os.environ['HEAPPROFILE'] = os.path.join(self._deep_tempdir, 'endure') | |
| 72 os.environ['HEAP_PROFILE_MMAP'] = 'True' | |
| 73 os.environ['DEEP_HEAP_PROFILE'] = 'True' | |
| 74 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL when PyAuto | |
| 75 # supports to dump renderer heap profile. | |
| 76 os.environ['HEAP_PROFILE_TIME_INTERVAL'] = ( | |
| 77 '%d' % self._deep_memory_profile_interval) | |
|
dennis_jeffrey
2012/05/09 04:31:47
os.environ['HEAP_PROFILE_TIME_INTERVAL'] = (
s
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 78 | |
| 38 perf.BasePerfTest.setUp(self) | 79 perf.BasePerfTest.setUp(self) |
| 39 | 80 |
| 40 self._test_length_sec = int( | 81 self._test_length_sec = int( |
| 41 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) | 82 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) |
| 42 self._get_perf_stats_interval = int( | 83 self._get_perf_stats_interval = int( |
| 43 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) | 84 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) |
| 44 | 85 |
| 86 self._deep_memory_profile_save = self.GetDeepMemoryProfileEnv( | |
| 87 'DEEP_MEMORY_PROFILE_SAVE', bool, self._DEEP_MEMORY_PROFILE_SAVE, False) | |
| 88 | |
| 45 logging.info('Running test for %d seconds.', self._test_length_sec) | 89 logging.info('Running test for %d seconds.', self._test_length_sec) |
| 46 logging.info('Gathering perf stats every %d seconds.', | 90 logging.info('Gathering perf stats every %d seconds.', |
| 47 self._get_perf_stats_interval) | 91 self._get_perf_stats_interval) |
| 92 if self._deep_memory_profile: | |
| 93 logging.info('Running with the Deep Memory Profiler every %d seconds.', | |
| 94 self._deep_memory_profile_interval) | |
| 95 if self._deep_memory_profile_save: | |
| 96 logging.info(' Dumped files won\'t be cleaned.') | |
| 97 else: | |
| 98 logging.info(' Dumped files will be cleaned up after every test.') | |
| 48 | 99 |
| 49 # Set up a remote inspector client associated with tab 0. | 100 # Set up a remote inspector client associated with tab 0. |
| 50 logging.info('Setting up connection to remote inspector...') | 101 logging.info('Setting up connection to remote inspector...') |
| 51 self._remote_inspector_client = ( | 102 self._remote_inspector_client = ( |
| 52 remote_inspector_client.RemoteInspectorClient()) | 103 remote_inspector_client.RemoteInspectorClient()) |
| 53 logging.info('Connection to remote inspector set up successfully.') | 104 logging.info('Connection to remote inspector set up successfully.') |
| 54 | 105 |
| 55 self._test_start_time = 0 | 106 self._test_start_time = 0 |
| 56 self._num_errors = 0 | 107 self._num_errors = 0 |
| 57 self._events_to_output = [] | 108 self._events_to_output = [] |
| 109 self._iteration_num = 0 | |
|
dennis_jeffrey
2012/05/09 04:31:47
i think this line is unnecessary
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Thanks. It may be mixed when I rebased.
| |
| 110 self._deep_memory_profile_json_file = None | |
| 111 self._deep_memory_profile_last_json_filename = '' | |
| 112 self._deep_memory_profile_proc = None | |
| 113 self._deep_memory_profile_records = [] | |
| 114 self._deep_memory_profile_last_index = 0 | |
| 58 | 115 |
| 59 def tearDown(self): | 116 def tearDown(self): |
| 60 logging.info('Terminating connection to remote inspector...') | 117 logging.info('Terminating connection to remote inspector...') |
| 61 self._remote_inspector_client.Stop() | 118 self._remote_inspector_client.Stop() |
| 62 logging.info('Connection to remote inspector terminated.') | 119 logging.info('Connection to remote inspector terminated.') |
| 63 perf.BasePerfTest.tearDown(self) # Must be done at end of this function. | 120 if self._deep_memory_profile: |
| 121 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL in setUp when | |
| 122 # PyAuto supports to dump renderer heap profile. | |
| 123 del os.environ['HEAP_PROFILE_TIME_INTERVAL'] | |
| 124 del os.environ['DEEP_HEAP_PROFILE'] | |
| 125 del os.environ['HEAP_PROFILE_MMAP'] | |
| 126 del os.environ['HEAPPROFILE'] | |
| 127 | |
| 128 # Must be done at end of this function except for post-cleaning after | |
| 129 # Chrome finishes. | |
| 130 perf.BasePerfTest.tearDown(self) | |
| 131 | |
| 132 # Remove the temporary directory after Chrome finishes in tearDown. | |
| 133 if (self._deep_memory_profile and | |
| 134 not self._deep_memory_profile_save and | |
| 135 self._deep_tempdir): | |
| 136 pyauto_utils.RemovePath(self._deep_tempdir) | |
| 137 | |
| 138 def GetDeepMemoryProfileEnv( | |
|
dennis_jeffrey
2012/05/09 04:31:47
prefix the function name with an underscore if it'
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 139 self, env_name, converter, default, not_supported): | |
| 140 """Returns a converted environment variable for the Deep Memory Profiler. | |
| 141 | |
| 142 Args: | |
| 143 env_name: A string name of an environment variable. | |
| 144 converter: A function taking a string to convert an environment variable. | |
| 145 default: A value used if the environment variable is not specified. | |
| 146 not_supported: A value used if the Deep Memory Profiler is not supported. | |
| 147 | |
| 148 Returns: | |
| 149 A value converted from the environment variable with 'converter'. | |
| 150 """ | |
| 151 result = not_supported | |
|
dennis_jeffrey
2012/05/09 04:31:47
rather than having a "not_supported" value, should
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done. Introduced a new RuntimeError: NotSupported
| |
| 152 if self.IsLinux(): | |
| 153 result = converter(os.environ.get(env_name, default)) | |
| 154 return result | |
| 155 | |
| 156 def WaitForDeepMemoryProfiler(self): | |
|
dennis_jeffrey
2012/05/09 04:31:47
prefix the function name with an underscore if it'
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 157 """Waits for the Deep Memory Profiler finished if running. | |
|
dennis_jeffrey
2012/05/09 04:31:47
'finished' --> 'to finish'
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 158 """ | |
|
dennis_jeffrey
2012/05/09 04:31:47
move this to the previous line if it fits there
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done.
| |
| 159 if self._deep_memory_profile and self._deep_memory_profile_proc: | |
| 160 self._deep_memory_profile_proc.wait() | |
| 161 self._deep_memory_profile_proc = None | |
| 162 if self._deep_memory_profile_json_file: | |
| 163 self._deep_memory_profile_last_json_filename = ( | |
| 164 self._deep_memory_profile_json_file.name) | |
| 165 self._deep_memory_profile_json_file.close() | |
| 166 self._deep_memory_profile_json_file = None | |
| 64 | 167 |
| 65 def ExtraChromeFlags(self): | 168 def ExtraChromeFlags(self): |
| 66 """Ensures Chrome is launched with custom flags. | 169 """Ensures Chrome is launched with custom flags. |
| 67 | 170 |
| 68 Returns: | 171 Returns: |
| 69 A list of extra flags to pass to Chrome when it is launched. | 172 A list of extra flags to pass to Chrome when it is launched. |
| 70 """ | 173 """ |
| 174 # The same with setUp, but need to fetch the environment variable since | |
| 175 # ExtraChromeFlags is called before setUp. | |
| 176 deep_memory_profile = self.GetDeepMemoryProfileEnv( | |
| 177 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE, False) | |
| 178 | |
| 71 # Ensure Chrome enables remote debugging on port 9222. This is required to | 179 # Ensure Chrome enables remote debugging on port 9222. This is required to |
| 72 # interact with Chrome's remote inspector. | 180 # interact with Chrome's remote inspector. |
| 73 return (perf.BasePerfTest.ExtraChromeFlags(self) + | 181 extra_flags = ['--remote-debugging-port=9222'] |
| 74 ['--remote-debugging-port=9222']) | 182 if deep_memory_profile: |
| 183 extra_flags.append('--no-sandbox') | |
| 184 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags) | |
| 75 | 185 |
| 76 def _OnTimelineEvent(self, event_info): | 186 def _OnTimelineEvent(self, event_info): |
| 77 """Invoked by the Remote Inspector Client when a timeline event occurs. | 187 """Invoked by the Remote Inspector Client when a timeline event occurs. |
| 78 | 188 |
| 79 Args: | 189 Args: |
| 80 event_info: A dictionary containing raw information associated with a | 190 event_info: A dictionary containing raw information associated with a |
| 81 timeline event received from Chrome's remote inspector. Refer to | 191 timeline event received from Chrome's remote inspector. Refer to |
| 82 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json | 192 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json |
| 83 for the format of this dictionary. | 193 for the format of this dictionary. |
| 84 """ | 194 """ |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 self._OnTimelineEvent) | 232 self._OnTimelineEvent) |
| 123 | 233 |
| 124 while time.time() - self._test_start_time < self._test_length_sec: | 234 while time.time() - self._test_start_time < self._test_length_sec: |
| 125 self._iteration_num += 1 | 235 self._iteration_num += 1 |
| 126 | 236 |
| 127 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: | 237 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: |
| 128 logging.error('Error count threshold (%d) reached. Terminating test ' | 238 logging.error('Error count threshold (%d) reached. Terminating test ' |
| 129 'early.' % self._ERROR_COUNT_THRESHOLD) | 239 'early.' % self._ERROR_COUNT_THRESHOLD) |
| 130 break | 240 break |
| 131 | 241 |
| 242 # TODO(dmikurube): Call HeapProfilerDump when PyAuto supports dumping for | |
| 243 # renderer processes. | |
| 244 # TODO(dmikurube): Need pid of the target process. | |
| 245 | |
| 132 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: | 246 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: |
| 133 last_perf_stats_time = time.time() | 247 last_perf_stats_time = time.time() |
| 134 self._GetPerformanceStats( | 248 self._GetPerformanceStats( |
| 135 webapp_name, test_description, tab_title_substring) | 249 webapp_name, test_description, tab_title_substring) |
| 136 | 250 |
| 137 if self._iteration_num % 10 == 0: | 251 if self._iteration_num % 10 == 0: |
| 138 remaining_time = self._test_length_sec - (time.time() - | 252 remaining_time = self._test_length_sec - (time.time() - |
| 139 self._test_start_time) | 253 self._test_start_time) |
| 140 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % | 254 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % |
| 141 (self._iteration_num, remaining_time)) | 255 (self._iteration_num, remaining_time)) |
| 142 | 256 |
| 143 do_scenario() | 257 do_scenario() |
| 144 | 258 |
| 145 self._remote_inspector_client.StopTimelineEventMonitoring() | 259 self._remote_inspector_client.StopTimelineEventMonitoring() |
| 260 # TODO(dmikurube): Call HeapProfilerDump when PyAuto supports dumping for | |
| 261 # renderer processes. | |
| 262 | |
| 146 self._GetPerformanceStats( | 263 self._GetPerformanceStats( |
| 147 webapp_name, test_description, tab_title_substring) | 264 webapp_name, test_description, tab_title_substring, is_last=True) |
| 148 | 265 |
| 149 def _GetProcessInfo(self, tab_title_substring): | 266 def _GetProcessInfo(self, tab_title_substring): |
| 150 """Gets process info associated with an open browser/tab. | 267 """Gets process info associated with an open browser/tab. |
| 151 | 268 |
| 152 Args: | 269 Args: |
| 153 tab_title_substring: A unique substring contained within the title of | 270 tab_title_substring: A unique substring contained within the title of |
| 154 the tab to use; needed for locating the tab info. | 271 the tab to use; needed for locating the tab info. |
| 155 | 272 |
| 156 Returns: | 273 Returns: |
| 157 A dictionary containing information about the browser and specified tab | 274 A dictionary containing information about the browser and specified tab |
| 158 process: | 275 process: |
| 159 { | 276 { |
| 160 'browser_private_mem': integer, # Private memory associated with the | 277 'browser_private_mem': integer, # Private memory associated with the |
| 161 # browser process, in KB. | 278 # browser process, in KB. |
| 162 'tab_private_mem': integer, # Private memory associated with the tab | 279 'tab_private_mem': integer, # Private memory associated with the tab |
| 163 # process, in KB. | 280 # process, in KB. |
| 281 'tab_pid': integer, # Process ID of the tab process. | |
| 164 } | 282 } |
| 165 """ | 283 """ |
| 166 browser_process_name = ( | 284 browser_process_name = ( |
| 167 self.GetBrowserInfo()['properties']['BrowserProcessExecutableName']) | 285 self.GetBrowserInfo()['properties']['BrowserProcessExecutableName']) |
| 168 info = self.GetProcessInfo() | 286 info = self.GetProcessInfo() |
| 169 | 287 |
| 170 # Get the information associated with the browser process. | 288 # Get the information associated with the browser process. |
| 171 browser_proc_info = [] | 289 browser_proc_info = [] |
| 172 for browser_info in info['browsers']: | 290 for browser_info in info['browsers']: |
| 173 if browser_info['process_name'] == browser_process_name: | 291 if browser_info['process_name'] == browser_process_name: |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 190 msg='Expected to find 1 %s tab process, but found %d ' | 308 msg='Expected to find 1 %s tab process, but found %d ' |
| 191 'instead.\nCurrent process info:\n%s.' % ( | 309 'instead.\nCurrent process info:\n%s.' % ( |
| 192 tab_title_substring, len(tab_proc_info), | 310 tab_title_substring, len(tab_proc_info), |
| 193 self.pformat(info))) | 311 self.pformat(info))) |
| 194 | 312 |
| 195 browser_proc_info = browser_proc_info[0] | 313 browser_proc_info = browser_proc_info[0] |
| 196 tab_proc_info = tab_proc_info[0] | 314 tab_proc_info = tab_proc_info[0] |
| 197 return { | 315 return { |
| 198 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], | 316 'browser_private_mem': browser_proc_info['working_set_mem']['priv'], |
| 199 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], | 317 'tab_private_mem': tab_proc_info['working_set_mem']['priv'], |
| 318 'tab_pid': tab_proc_info['pid'], | |
| 200 } | 319 } |
| 201 | 320 |
| 202 def _GetPerformanceStats(self, webapp_name, test_description, | 321 def _GetPerformanceStats(self, webapp_name, test_description, |
| 203 tab_title_substring): | 322 tab_title_substring, is_last=False): |
| 204 """Gets performance statistics and outputs the results. | 323 """Gets performance statistics and outputs the results. |
| 205 | 324 |
| 206 Args: | 325 Args: |
| 207 webapp_name: A string name for the webapp being tested. Should not | 326 webapp_name: A string name for the webapp being tested. Should not |
| 208 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. | 327 include spaces. For example, 'Gmail', 'Docs', or 'Plus'. |
| 209 test_description: A string description of what the test does, used for | 328 test_description: A string description of what the test does, used for |
| 210 outputting results to be graphed. Should not contain spaces. For | 329 outputting results to be graphed. Should not contain spaces. For |
| 211 example, 'ComposeDiscard' for Gmail. | 330 example, 'ComposeDiscard' for Gmail. |
| 212 tab_title_substring: A unique substring contained within the title of | 331 tab_title_substring: A unique substring contained within the title of |
| 213 the tab to use, for identifying the appropriate tab. | 332 the tab to use, for identifying the appropriate tab. |
| 333 is_last: A boolean value which should be True if it's the last call of | |
| 334 _GetPerformanceStats. The default is False. | |
| 214 """ | 335 """ |
| 215 logging.info('Gathering performance stats...') | 336 logging.info('Gathering performance stats...') |
| 216 elapsed_time = int(round(time.time() - self._test_start_time)) | 337 elapsed_time = int(round(time.time() - self._test_start_time)) |
| 217 | 338 |
| 218 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() | 339 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() |
| 340 proc_info = self._GetProcessInfo(tab_title_substring) | |
| 341 | |
| 342 # Run Deep Memory Profiler in background. | |
| 343 if self._deep_memory_profile: | |
| 344 logging.info(' Profiling with the Deep Memory Profiler...') | |
| 345 | |
| 346 # Wait for a running dmprof process for last _GetPerformanceStat call to | |
| 347 # cover last dump files. | |
| 348 if is_last: | |
| 349 logging.info(' Waiting for the last dmprof.') | |
| 350 self.WaitForDeepMemoryProfiler() | |
| 351 | |
| 352 if (self._deep_memory_profile_proc and | |
| 353 self._deep_memory_profile_proc.poll() is None): | |
| 354 logging.info(' Last dmprof is still running.') | |
| 355 else: | |
| 356 if self._deep_memory_profile_json_file: | |
| 357 self._deep_memory_profile_last_json_filename = ( | |
| 358 self._deep_memory_profile_json_file.name) | |
| 359 self._deep_memory_profile_json_file.close() | |
| 360 self._deep_memory_profile_json_file = None | |
| 361 first_dump = '' | |
| 362 last_dump = '' | |
| 363 for filename in sorted(os.listdir(self._deep_tempdir)): | |
| 364 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'], | |
| 365 filename): | |
| 366 logging.info(' Profiled dump file: %s' % filename) | |
| 367 last_dump = filename | |
| 368 if not first_dump: | |
| 369 first_dump = filename | |
| 370 if first_dump: | |
| 371 logging.info(' First dump file: %s' % first_dump) | |
| 372 matched= re.match('^endure.\d+.(\d+).heap$', last_dump) | |
| 373 last_sequence_id = matched.group(1) | |
| 374 self._deep_memory_profile_json_file = open( | |
| 375 os.path.join(self._deep_tempdir, | |
| 376 'endure.%05d.%s.json' % (proc_info['tab_pid'], | |
| 377 last_sequence_id)), 'w+') | |
| 378 self._deep_memory_profile_proc = subprocess.Popen( | |
| 379 '%s --json %s %s %s' % (self._DMPROF_SCRIPT_PATH, | |
| 380 self._CHROME_BIN_PATH, | |
| 381 os.path.join(self._DMPROF_DIR_PATH, | |
| 382 'policy.l0.txt'), | |
| 383 os.path.join(self._deep_tempdir, | |
| 384 first_dump)), | |
| 385 shell=True, stdout=self._deep_memory_profile_json_file) | |
| 386 # Don't wait for the new process since dmprof may take long time. | |
| 387 | |
| 388 if is_last: | |
| 389 self.WaitForDeepMemoryProfiler() | |
| 390 | |
| 391 else: | |
| 392 logging.info(' No dump files.') | |
| 219 | 393 |
| 220 # DOM node count. | 394 # DOM node count. |
| 221 dom_node_count = memory_counts['DOMNodeCount'] | 395 dom_node_count = memory_counts['DOMNodeCount'] |
| 222 self._OutputPerfGraphValue( | 396 self._OutputPerfGraphValue( |
| 223 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes', | 397 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes', |
| 224 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), | 398 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), |
| 225 units_x='seconds') | 399 units_x='seconds') |
| 226 | 400 |
| 227 # Event listener count. | 401 # Event listener count. |
| 228 event_listener_count = memory_counts['EventListenerCount'] | 402 event_listener_count = memory_counts['EventListenerCount'] |
| 229 self._OutputPerfGraphValue( | 403 self._OutputPerfGraphValue( |
| 230 'EventListenerCount', [(elapsed_time, event_listener_count)], | 404 'EventListenerCount', [(elapsed_time, event_listener_count)], |
| 231 'listeners', | 405 'listeners', |
| 232 graph_name='%s%s-EventListeners' % (webapp_name, test_description), | 406 graph_name='%s%s-EventListeners' % (webapp_name, test_description), |
| 233 units_x='seconds') | 407 units_x='seconds') |
| 234 | 408 |
| 235 # Browser process private memory. | 409 # Browser process private memory. |
| 236 proc_info = self._GetProcessInfo(tab_title_substring) | |
| 237 self._OutputPerfGraphValue( | 410 self._OutputPerfGraphValue( |
| 238 'BrowserPrivateMemory', | 411 'BrowserPrivateMemory', |
| 239 [(elapsed_time, proc_info['browser_private_mem'])], 'KB', | 412 [(elapsed_time, proc_info['browser_private_mem'])], 'KB', |
| 240 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), | 413 graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description), |
| 241 units_x='seconds') | 414 units_x='seconds') |
| 242 | 415 |
| 243 # Tab process private memory. | 416 # Tab process private memory. |
| 244 self._OutputPerfGraphValue( | 417 self._OutputPerfGraphValue( |
| 245 'TabPrivateMemory', | 418 'TabPrivateMemory', |
| 246 [(elapsed_time, proc_info['tab_private_mem'])], 'KB', | 419 [(elapsed_time, proc_info['tab_private_mem'])], 'KB', |
| 247 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), | 420 graph_name='%s%s-TabMem-Private' % (webapp_name, test_description), |
| 248 units_x='seconds') | 421 units_x='seconds') |
| 249 | 422 |
| 250 # V8 memory used. | 423 # V8 memory used. |
| 251 v8_info = self.GetV8HeapStats() # First window, first tab. | 424 v8_info = self.GetV8HeapStats() # First window, first tab. |
| 252 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. | 425 v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB. |
| 253 self._OutputPerfGraphValue( | 426 self._OutputPerfGraphValue( |
| 254 'V8MemoryUsed', [(elapsed_time, v8_mem_used)], 'KB', | 427 'V8MemoryUsed', [(elapsed_time, v8_mem_used)], 'KB', |
| 255 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), | 428 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), |
| 256 units_x='seconds') | 429 units_x='seconds') |
| 257 | 430 |
| 431 # Deep Memory Profiler result. | |
| 432 if self._deep_memory_profile: | |
| 433 deep_memory_profile_results = {} | |
| 434 if self._deep_memory_profile_last_json_filename: | |
| 435 json_data = {} | |
| 436 with open(self._deep_memory_profile_last_json_filename) as json_f: | |
| 437 json_data = json.load(json_f) | |
| 438 if json_data['version'] == 'JSON_DEEP_1': | |
| 439 for component in json_data['legends']: | |
| 440 deep_memory_profile_results[component] = [] | |
| 441 for snapshot in json_data['snapshots']: | |
| 442 deep_memory_profile_results[component].append(snapshot[component]) | |
| 443 if deep_memory_profile_results: | |
| 444 for index in range(self._deep_memory_profile_last_index, | |
|
dennis_jeffrey
2012/05/09 04:31:47
rather than looping through each index and separat
Dai Mikurube (NOT FULLTIME)
2012/05/09 07:44:34
Done. Now it prints like following repeatedly:
R
| |
| 445 len(deep_memory_profile_results['second'])): | |
| 446 self._OutputPerfGraphValue( | |
| 447 'DMP-TCMallocUsed', | |
| 448 [(deep_memory_profile_results['second'][index], | |
| 449 deep_memory_profile_results['tc-used-all'][index] / 1024.0)], | |
| 450 'KB', | |
| 451 graph_name='%s%s-DMP-TCUsed' % (webapp_name, test_description), | |
| 452 units_x='seconds') | |
| 453 self._deep_memory_profile_last_index = ( | |
| 454 len(deep_memory_profile_results['second'])) | |
| 455 # TODO(dmikurube): Output graph values (for multi-lined graphs), here. | |
| 456 # 'deep_memory_profile_results' is the value to be output. | |
| 457 | |
| 258 logging.info(' Total DOM node count: %d nodes' % dom_node_count) | 458 logging.info(' Total DOM node count: %d nodes' % dom_node_count) |
| 259 logging.info(' Event listener count: %d listeners' % event_listener_count) | 459 logging.info(' Event listener count: %d listeners' % event_listener_count) |
| 260 logging.info(' Browser process private memory: %d KB' % | 460 logging.info(' Browser process private memory: %d KB' % |
| 261 proc_info['browser_private_mem']) | 461 proc_info['browser_private_mem']) |
| 262 logging.info(' Tab process private memory: %d KB' % | 462 logging.info(' Tab process private memory: %d KB' % |
| 263 proc_info['tab_private_mem']) | 463 proc_info['tab_private_mem']) |
| 264 logging.info(' V8 memory used: %f KB' % v8_mem_used) | 464 logging.info(' V8 memory used: %f KB' % v8_mem_used) |
| 265 | 465 |
| 266 # Output any new timeline events that have occurred. | 466 # Output any new timeline events that have occurred. |
| 267 if self._events_to_output: | 467 if self._events_to_output: |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 877 self._driver, self._wait, 'id("state")[text()="offline"]'): | 1077 self._driver, self._wait, 'id("state")[text()="offline"]'): |
| 878 self._num_errors += 1 | 1078 self._num_errors += 1 |
| 879 time.sleep(1) | 1079 time.sleep(1) |
| 880 | 1080 |
| 881 self._RunEndureTest(self._webapp_name, self._tab_title_substring, | 1081 self._RunEndureTest(self._webapp_name, self._tab_title_substring, |
| 882 test_description, scenario) | 1082 test_description, scenario) |
| 883 | 1083 |
| 884 | 1084 |
| 885 if __name__ == '__main__': | 1085 if __name__ == '__main__': |
| 886 pyauto_functional.Main() | 1086 pyauto_functional.Main() |
| OLD | NEW |