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

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

Issue 10871038: Dump data for stacked graphs in Chrome Endure. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed for Dennis's comment. 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/functional/perf.py ('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
(...skipping 27 matching lines...) Expand all
38 import selenium.common.exceptions 38 import selenium.common.exceptions
39 from selenium.webdriver.support.ui import WebDriverWait 39 from selenium.webdriver.support.ui import WebDriverWait
40 import webpagereplay 40 import webpagereplay
41 41
42 42
43 class NotSupportedEnvironmentError(RuntimeError): 43 class NotSupportedEnvironmentError(RuntimeError):
44 """Represent an error raised since the environment (OS) is not supported.""" 44 """Represent an error raised since the environment (OS) is not supported."""
45 pass 45 pass
46 46
47 47
48 class DeepMemoryProfiler(object):
49 """Controls Deep Memory Profiler (dmprof) for endurance tests."""
50 DEEP_MEMORY_PROFILE = False
51 DEEP_MEMORY_PROFILE_SAVE = False
52
53 _DMPROF_DIR_PATH = os.path.join(
54 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
55 'tools', 'deep_memory_profiler')
56 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
57
58 def __init__(self):
59 self._enabled = self.GetEnvironmentVariable(
60 'DEEP_MEMORY_PROFILE', bool, self.DEEP_MEMORY_PROFILE)
61 self._save = self.GetEnvironmentVariable(
62 'DEEP_MEMORY_PROFILE_SAVE', bool, self.DEEP_MEMORY_PROFILE_SAVE)
63 self._json_file = None
64 self._last_json_filename = ''
65 self._proc = None
66 self._last_time = -1.0
67
68 def __nonzero__(self):
69 return self._enabled
70
71 @staticmethod
72 def GetEnvironmentVariable(env_name, converter, default):
73 """Returns a converted environment variable for Deep Memory Profiler.
74
75 Args:
76 env_name: A string name of an environment variable.
77 converter: A function taking a string to convert an environment variable.
78 default: A value used if the environment variable is not specified.
79
80 Returns:
81 A value converted from the environment variable with 'converter'.
82 """
83 return converter(os.environ.get(env_name, default))
84
85 def SetUp(self, is_linux):
86 """Sets up Deep Memory Profiler settings for a Chrome process.
87
88 It sets environment variables and makes a working directory.
89 """
90 if not self._enabled:
91 return
92
93 if not is_linux:
94 raise NotSupportedEnvironmentError(
95 'Deep Memory Profiler is not supported in this environment (OS).')
96 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
97 self._tempdir = tempfile.mkdtemp(prefix=dir_prefix)
98 os.environ['HEAPPROFILE'] = os.path.join(self._tempdir, 'endure')
99 os.environ['HEAP_PROFILE_MMAP'] = '1'
100 os.environ['DEEP_HEAP_PROFILE'] = '1'
101
102 def TearDown(self):
103 """Tear down Deep Memory Profiler settings for the Chrome process.
104
105 It removes the environment variables and the temporary directory.
106 Call it after Chrome finishes. Chrome may dump last files at the end.
107 """
108 if not self._enabled:
109 return
110
111 del os.environ['DEEP_HEAP_PROFILE']
112 del os.environ['HEAP_PROFILE_MMAP']
113 del os.environ['HEAPPROFILE']
114 if not self._save and self._tempdir:
115 pyauto_utils.RemovePath(self._tempdir)
116
117 def LogFirstMessage(self):
118 """Logs first messages."""
119 if not self._enabled:
120 return
121
122 logging.info('Running with the Deep Memory Profiler.')
123 if self._save:
124 logging.info(' Dumped files won\'t be cleaned.')
125 else:
126 logging.info(' Dumped files will be cleaned up after every test.')
127
128 def StartProfiler(self, proc_info, is_last):
129 """Starts Deep Memory Profiler in background."""
130 if not self._enabled:
131 return
132
133 logging.info(' Profiling with the Deep Memory Profiler...')
134
135 # Wait for a running dmprof process for last _GetPerformanceStat call to
136 # cover last dump files.
137 if is_last:
138 logging.info(' Waiting for the last dmprof.')
139 self._WaitForDeepMemoryProfiler()
140
141 if self._proc and self._proc.poll() is None:
142 logging.info(' Last dmprof is still running.')
143 else:
144 if self._json_file:
145 self._last_json_filename = self._json_file.name
146 self._json_file.close()
147 self._json_file = None
148 first_dump = ''
149 last_dump = ''
150 for filename in sorted(os.listdir(self._tempdir)):
151 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
152 filename):
153 logging.info(' Profiled dump file: %s' % filename)
154 last_dump = filename
155 if not first_dump:
156 first_dump = filename
157 if first_dump:
158 logging.info(' First dump file: %s' % first_dump)
159 matched = re.match('^endure.\d+.(\d+).heap$', last_dump)
160 last_sequence_id = matched.group(1)
161 self._json_file = open(
162 os.path.join(self._tempdir,
163 'endure.%05d.%s.json' % (proc_info['tab_pid'],
164 last_sequence_id)), 'w+')
165 self._proc = subprocess.Popen(
166 '%s json %s' % (self._DMPROF_SCRIPT_PATH,
167 os.path.join(self._tempdir, first_dump)),
168 shell=True, stdout=self._json_file)
169 # Wait only when it is the last profiling. dmprof may take long time.
170 if is_last:
171 self._WaitForDeepMemoryProfiler()
172 else:
173 logging.info(' No dump files.')
174
175 def ParseResultAndOutputPerfGraphValues(
176 self, webapp_name, test_description, output_perf_graph_value):
177 """Parses Deep Memory Profiler result, and outputs perf graph values."""
178 if not self._enabled:
179 return
180
181 results = {}
182 if self._last_json_filename:
183 json_data = {}
184 with open(self._last_json_filename) as json_f:
185 json_data = json.load(json_f)
186 if json_data['version'] == 'JSON_DEEP_1':
187 results = json_data['snapshots']
188 elif json_data['version'] == 'JSON_DEEP_2':
189 results = json_data['policies']['l2']['snapshots']
190 if results and results[-1]['second'] > self._last_time:
191 started = False
192 for legend in json_data['policies']['l2']['legends']:
193 if legend == 'FROM_HERE_FOR_TOTAL':
194 started = True
195 elif legend == 'UNTIL_HERE_FOR_TOTAL':
196 break
197 elif started:
198 output_perf_graph_value(
199 legend.encode('utf-8'), [
200 (int(round(snapshot['second'])), snapshot[legend] / 1024)
201 for snapshot in results
202 if snapshot['second'] > self._last_time],
203 'KB',
204 graph_name='%s%s-DMP' % (webapp_name, test_description),
205 units_x='seconds', is_stacked=True)
206 self._last_time = results[-1]['second']
207
208 def _WaitForDeepMemoryProfiler(self):
209 """Waits for the Deep Memory Profiler to finish if running."""
210 if not self._enabled or not self._proc:
211 return
212
213 self._proc.wait()
214 self._proc = None
215 if self._json_file:
216 self._last_json_filename = self._json_file.name
217 self._json_file.close()
218 self._json_file = None
219
220
48 class ChromeEndureBaseTest(perf.BasePerfTest): 221 class ChromeEndureBaseTest(perf.BasePerfTest):
49 """Implements common functionality for all Chrome Endure tests. 222 """Implements common functionality for all Chrome Endure tests.
50 223
51 All Chrome Endure test classes should inherit from this class. 224 All Chrome Endure test classes should inherit from this class.
52 """ 225 """
53 226
54 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. 227 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
55 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes. 228 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
56 # TODO(dennisjeffrey): Do we still need to tolerate errors? 229 # TODO(dennisjeffrey): Do we still need to tolerate errors?
57 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate. 230 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate.
58 _DEEP_MEMORY_PROFILE = False
59 _DEEP_MEMORY_PROFILE_SAVE = False
60
61 _DMPROF_DIR_PATH = os.path.join(
62 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
63 'tools', 'deep_memory_profiler')
64
65 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
66 231
67 def setUp(self): 232 def setUp(self):
68 # The Web Page Replay environment variables must be parsed before 233 # The Web Page Replay environment variables must be parsed before
69 # perf.BasePerfTest.setUp() 234 # perf.BasePerfTest.setUp()
70 self._ParseReplayEnv() 235 self._ParseReplayEnv()
71 # The environment variables for the Deep Memory Profiler must be set 236 # The environment variables for the Deep Memory Profiler must be set
72 # before perf.BasePerfTest.setUp() to inherit them to Chrome. 237 # before perf.BasePerfTest.setUp() to inherit them to Chrome.
73 self._deep_memory_profile = self._GetDeepMemoryProfileEnv( 238 self._dmprof = DeepMemoryProfiler()
74 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 239 if self._dmprof:
75 240 self._dmprof.SetUp(self.IsLinux())
76 if self._deep_memory_profile:
77 if not self.IsLinux():
78 raise NotSupportedEnvironmentError(
79 'Deep Memory Profiler is not supported in this environment (OS).')
80 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
81 self._deep_tempdir = tempfile.mkdtemp(prefix=dir_prefix)
82 os.environ['HEAPPROFILE'] = os.path.join(self._deep_tempdir, 'endure')
83 os.environ['HEAP_PROFILE_MMAP'] = 'True'
84 os.environ['DEEP_HEAP_PROFILE'] = 'True'
85 241
86 perf.BasePerfTest.setUp(self) 242 perf.BasePerfTest.setUp(self)
87 243
88 self._test_length_sec = int( 244 self._test_length_sec = int(
89 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) 245 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC))
90 self._get_perf_stats_interval = int( 246 self._get_perf_stats_interval = int(
91 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) 247 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL))
92 248
93 self._deep_memory_profile_save = self._GetDeepMemoryProfileEnv(
94 'DEEP_MEMORY_PROFILE_SAVE', bool, self._DEEP_MEMORY_PROFILE_SAVE)
95
96 logging.info('Running test for %d seconds.', self._test_length_sec) 249 logging.info('Running test for %d seconds.', self._test_length_sec)
97 logging.info('Gathering perf stats every %d seconds.', 250 logging.info('Gathering perf stats every %d seconds.',
98 self._get_perf_stats_interval) 251 self._get_perf_stats_interval)
99 if self._deep_memory_profile: 252
100 logging.info('Running with the Deep Memory Profiler.') 253 if self._dmprof:
101 if self._deep_memory_profile_save: 254 self._dmprof.LogFirstMessage()
102 logging.info(' Dumped files won\'t be cleaned.')
103 else:
104 logging.info(' Dumped files will be cleaned up after every test.')
105 255
106 # Set up a remote inspector client associated with tab 0. 256 # Set up a remote inspector client associated with tab 0.
107 logging.info('Setting up connection to remote inspector...') 257 logging.info('Setting up connection to remote inspector...')
108 self._remote_inspector_client = ( 258 self._remote_inspector_client = (
109 remote_inspector_client.RemoteInspectorClient()) 259 remote_inspector_client.RemoteInspectorClient())
110 logging.info('Connection to remote inspector set up successfully.') 260 logging.info('Connection to remote inspector set up successfully.')
111 261
112 self._test_start_time = 0 262 self._test_start_time = 0
113 self._num_errors = 0 263 self._num_errors = 0
114 self._events_to_output = [] 264 self._events_to_output = []
115 self._deep_memory_profile_json_file = None
116 self._deep_memory_profile_last_json_filename = ''
117 self._deep_memory_profile_proc = None
118 self._StartReplayServerIfNecessary() 265 self._StartReplayServerIfNecessary()
119 266
120 def tearDown(self): 267 def tearDown(self):
121 logging.info('Terminating connection to remote inspector...') 268 logging.info('Terminating connection to remote inspector...')
122 self._remote_inspector_client.Stop() 269 self._remote_inspector_client.Stop()
123 logging.info('Connection to remote inspector terminated.') 270 logging.info('Connection to remote inspector terminated.')
124 if self._deep_memory_profile:
125 del os.environ['DEEP_HEAP_PROFILE']
126 del os.environ['HEAP_PROFILE_MMAP']
127 del os.environ['HEAPPROFILE']
128 271
129 # Must be done at end of this function except for post-cleaning after 272 # Must be done at end of this function except for post-cleaning after
130 # Chrome finishes. 273 # Chrome finishes.
131 perf.BasePerfTest.tearDown(self) 274 perf.BasePerfTest.tearDown(self)
132 275
133 # Remove the temporary directory after Chrome finishes in tearDown.
134 if (self._deep_memory_profile and
135 not self._deep_memory_profile_save and
136 self._deep_tempdir):
137 pyauto_utils.RemovePath(self._deep_tempdir)
138 # Must be done after perf.BasePerfTest.tearDown() 276 # Must be done after perf.BasePerfTest.tearDown()
139 self._StopReplayServerIfNecessary() 277 self._StopReplayServerIfNecessary()
278 if self._dmprof:
279 self._dmprof.TearDown()
140 280
141 def _GetArchiveName(self): 281 def _GetArchiveName(self):
142 """Return the Web Page Replay archive name that corresponds to a test. 282 """Return the Web Page Replay archive name that corresponds to a test.
143 283
144 Override this function to return the name of an archive that 284 Override this function to return the name of an archive that
145 corresponds to the test, e.g "ChromeEndureGmailTest.wpr". 285 corresponds to the test, e.g "ChromeEndureGmailTest.wpr".
146 286
147 Returns: 287 Returns:
148 None, by default no archive name is provided. 288 None, by default no archive name is provided.
149 """ 289 """
(...skipping 23 matching lines...) Expand all
173 '_GetArchiveName() in your test?') 313 '_GetArchiveName() in your test?')
174 else: 314 else:
175 if self._archive_path and os.path.exists(self._archive_path): 315 if self._archive_path and os.path.exists(self._archive_path):
176 self._use_wpr = True 316 self._use_wpr = True
177 else: 317 else:
178 self._use_wpr = False 318 self._use_wpr = False
179 logging.info( 319 logging.info(
180 'Skipping Web Page Replay since archive file %sdoes not exist.', 320 'Skipping Web Page Replay since archive file %sdoes not exist.',
181 self._archive_path + ' ' if self._archive_path else '') 321 self._archive_path + ' ' if self._archive_path else '')
182 322
183 def _GetDeepMemoryProfileEnv(self, env_name, converter, default):
184 """Returns a converted environment variable for the Deep Memory Profiler.
185
186 Args:
187 env_name: A string name of an environment variable.
188 converter: A function taking a string to convert an environment variable.
189 default: A value used if the environment variable is not specified.
190
191 Returns:
192 A value converted from the environment variable with 'converter'.
193 """
194 return converter(os.environ.get(env_name, default))
195
196 def _WaitForDeepMemoryProfiler(self):
197 """Waits for the Deep Memory Profiler to finish if running."""
198 if self._deep_memory_profile and self._deep_memory_profile_proc:
199 self._deep_memory_profile_proc.wait()
200 self._deep_memory_profile_proc = None
201 if self._deep_memory_profile_json_file:
202 self._deep_memory_profile_last_json_filename = (
203 self._deep_memory_profile_json_file.name)
204 self._deep_memory_profile_json_file.close()
205 self._deep_memory_profile_json_file = None
206
207 def ExtraChromeFlags(self): 323 def ExtraChromeFlags(self):
208 """Ensures Chrome is launched with custom flags. 324 """Ensures Chrome is launched with custom flags.
209 325
210 Returns: 326 Returns:
211 A list of extra flags to pass to Chrome when it is launched. 327 A list of extra flags to pass to Chrome when it is launched.
212 """ 328 """
213 # The same with setUp, but need to fetch the environment variable since 329 # The same with setUp, but need to fetch the environment variable since
214 # ExtraChromeFlags is called before setUp. 330 # ExtraChromeFlags is called before setUp.
215 deep_memory_profile = self._GetDeepMemoryProfileEnv( 331 deep_memory_profile = DeepMemoryProfiler.GetEnvironmentVariable(
216 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 332 'DEEP_MEMORY_PROFILE', bool, DeepMemoryProfiler.DEEP_MEMORY_PROFILE)
217 333
218 # Ensure Chrome enables remote debugging on port 9222. This is required to 334 # Ensure Chrome enables remote debugging on port 9222. This is required to
219 # interact with Chrome's remote inspector. 335 # interact with Chrome's remote inspector.
220 extra_flags = ['--remote-debugging-port=9222'] 336 extra_flags = ['--remote-debugging-port=9222']
221 if deep_memory_profile: 337 if deep_memory_profile:
222 extra_flags.append('--no-sandbox') 338 extra_flags.append('--no-sandbox')
223 if self._use_wpr: 339 if self._use_wpr:
224 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS) 340 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS)
225 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags 341 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags
226 342
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 do_scenario: A callable to be invoked that implements the scenario to be 377 do_scenario: A callable to be invoked that implements the scenario to be
262 performed by this test. The callable is invoked iteratively for the 378 performed by this test. The callable is invoked iteratively for the
263 duration of the test. 379 duration of the test.
264 frame_xpath: The string xpath of the frame in which to inject javascript 380 frame_xpath: The string xpath of the frame in which to inject javascript
265 to clear chromedriver's cache (a temporary workaround until the 381 to clear chromedriver's cache (a temporary workaround until the
266 WebDriver team changes how they handle their DOM node cache). 382 WebDriver team changes how they handle their DOM node cache).
267 """ 383 """
268 self._num_errors = 0 384 self._num_errors = 0
269 self._test_start_time = time.time() 385 self._test_start_time = time.time()
270 last_perf_stats_time = time.time() 386 last_perf_stats_time = time.time()
271 if self._deep_memory_profile: 387 if self._dmprof:
272 self.HeapProfilerDump('renderer', 'Chrome Endure (first)') 388 self.HeapProfilerDump('renderer', 'Chrome Endure (first)')
273 self._GetPerformanceStats( 389 self._GetPerformanceStats(
274 webapp_name, test_description, tab_title_substring) 390 webapp_name, test_description, tab_title_substring)
275 self._iteration_num = 0 # Available to |do_scenario| if needed. 391 self._iteration_num = 0 # Available to |do_scenario| if needed.
276 392
277 self._remote_inspector_client.StartTimelineEventMonitoring( 393 self._remote_inspector_client.StartTimelineEventMonitoring(
278 self._OnTimelineEvent) 394 self._OnTimelineEvent)
279 395
280 while time.time() - self._test_start_time < self._test_length_sec: 396 while time.time() - self._test_start_time < self._test_length_sec:
281 self._iteration_num += 1 397 self._iteration_num += 1
282 398
283 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: 399 if self._num_errors >= self._ERROR_COUNT_THRESHOLD:
284 logging.error('Error count threshold (%d) reached. Terminating test ' 400 logging.error('Error count threshold (%d) reached. Terminating test '
285 'early.' % self._ERROR_COUNT_THRESHOLD) 401 'early.' % self._ERROR_COUNT_THRESHOLD)
286 break 402 break
287 403
288 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: 404 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
289 last_perf_stats_time = time.time() 405 last_perf_stats_time = time.time()
290 if self._deep_memory_profile: 406 if self._dmprof:
291 self.HeapProfilerDump('renderer', 'Chrome Endure') 407 self.HeapProfilerDump('renderer', 'Chrome Endure')
292 self._GetPerformanceStats( 408 self._GetPerformanceStats(
293 webapp_name, test_description, tab_title_substring) 409 webapp_name, test_description, tab_title_substring)
294 410
295 if self._iteration_num % 10 == 0: 411 if self._iteration_num % 10 == 0:
296 remaining_time = self._test_length_sec - (time.time() - 412 remaining_time = self._test_length_sec - (time.time() -
297 self._test_start_time) 413 self._test_start_time)
298 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % 414 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' %
299 (self._iteration_num, remaining_time)) 415 (self._iteration_num, remaining_time))
300 416
301 do_scenario() 417 do_scenario()
302 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the 418 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the
303 # results of Chrome Endure. 419 # results of Chrome Endure.
304 # TODO(dennisjeffrey): Once the WebDriver team implements changes to 420 # TODO(dennisjeffrey): Once the WebDriver team implements changes to
305 # handle their DOM node cache differently, we need to revisit this. It 421 # handle their DOM node cache differently, we need to revisit this. It
306 # may no longer be necessary at that point to forcefully delete the cache. 422 # may no longer be necessary at that point to forcefully delete the cache.
307 # Additionally, the Javascript below relies on an internal property of 423 # Additionally, the Javascript below relies on an internal property of
308 # WebDriver that may change at any time. This is only a temporary 424 # WebDriver that may change at any time. This is only a temporary
309 # workaround to stabilize the Chrome Endure test results. 425 # workaround to stabilize the Chrome Endure test results.
310 js = """ 426 js = """
311 (function() { 427 (function() {
312 delete document.$wdc_; 428 delete document.$wdc_;
313 window.domAutomationController.send('done'); 429 window.domAutomationController.send('done');
314 })(); 430 })();
315 """ 431 """
316 self.ExecuteJavascript(js, frame_xpath=frame_xpath) 432 self.ExecuteJavascript(js, frame_xpath=frame_xpath)
317 433
318 self._remote_inspector_client.StopTimelineEventMonitoring() 434 self._remote_inspector_client.StopTimelineEventMonitoring()
319 435
320 if self._deep_memory_profile: 436 if self._dmprof:
321 self.HeapProfilerDump('renderer', 'Chrome Endure (last)') 437 self.HeapProfilerDump('renderer', 'Chrome Endure (last)')
322 self._GetPerformanceStats( 438 self._GetPerformanceStats(
323 webapp_name, test_description, tab_title_substring, is_last=True) 439 webapp_name, test_description, tab_title_substring, is_last=True)
324 440
325 def _GetProcessInfo(self, tab_title_substring): 441 def _GetProcessInfo(self, tab_title_substring):
326 """Gets process info associated with an open browser/tab. 442 """Gets process info associated with an open browser/tab.
327 443
328 Args: 444 Args:
329 tab_title_substring: A unique substring contained within the title of 445 tab_title_substring: A unique substring contained within the title of
330 the tab to use; needed for locating the tab info. 446 the tab to use; needed for locating the tab info.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 the tab to use, for identifying the appropriate tab. 507 the tab to use, for identifying the appropriate tab.
392 is_last: A boolean value which should be True if it's the last call of 508 is_last: A boolean value which should be True if it's the last call of
393 _GetPerformanceStats. The default is False. 509 _GetPerformanceStats. The default is False.
394 """ 510 """
395 logging.info('Gathering performance stats...') 511 logging.info('Gathering performance stats...')
396 elapsed_time = int(round(time.time() - self._test_start_time)) 512 elapsed_time = int(round(time.time() - self._test_start_time))
397 513
398 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() 514 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts()
399 proc_info = self._GetProcessInfo(tab_title_substring) 515 proc_info = self._GetProcessInfo(tab_title_substring)
400 516
401 # Run Deep Memory Profiler in background. 517 if self._dmprof:
402 if self._deep_memory_profile: 518 self._dmprof.StartProfiler(proc_info, is_last)
403 logging.info(' Profiling with the Deep Memory Profiler...')
404
405 # Wait for a running dmprof process for last _GetPerformanceStat call to
406 # cover last dump files.
407 if is_last:
408 logging.info(' Waiting for the last dmprof.')
409 self._WaitForDeepMemoryProfiler()
410
411 if (self._deep_memory_profile_proc and
412 self._deep_memory_profile_proc.poll() is None):
413 logging.info(' Last dmprof is still running.')
414 else:
415 if self._deep_memory_profile_json_file:
416 self._deep_memory_profile_last_json_filename = (
417 self._deep_memory_profile_json_file.name)
418 self._deep_memory_profile_json_file.close()
419 self._deep_memory_profile_json_file = None
420 first_dump = ''
421 last_dump = ''
422 for filename in sorted(os.listdir(self._deep_tempdir)):
423 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
424 filename):
425 logging.info(' Profiled dump file: %s' % filename)
426 last_dump = filename
427 if not first_dump:
428 first_dump = filename
429 if first_dump:
430 logging.info(' First dump file: %s' % first_dump)
431 matched= re.match('^endure.\d+.(\d+).heap$', last_dump)
432 last_sequence_id = matched.group(1)
433 self._deep_memory_profile_json_file = open(
434 os.path.join(self._deep_tempdir,
435 'endure.%05d.%s.json' % (proc_info['tab_pid'],
436 last_sequence_id)), 'w+')
437 self._deep_memory_profile_proc = subprocess.Popen(
438 '%s json %s' % (self._DMPROF_SCRIPT_PATH,
439 os.path.join(self._deep_tempdir, first_dump)),
440 shell=True, stdout=self._deep_memory_profile_json_file)
441 # Don't wait for the new process since dmprof may take long time.
442
443 if is_last:
444 self._WaitForDeepMemoryProfiler()
445
446 else:
447 logging.info(' No dump files.')
448 519
449 # DOM node count. 520 # DOM node count.
450 dom_node_count = memory_counts['DOMNodeCount'] 521 dom_node_count = memory_counts['DOMNodeCount']
451 self._OutputPerfGraphValue( 522 self._OutputPerfGraphValue(
452 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes', 523 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes',
453 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), 524 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description),
454 units_x='seconds') 525 units_x='seconds')
455 526
456 # Event listener count. 527 # Event listener count.
457 event_listener_count = memory_counts['EventListenerCount'] 528 event_listener_count = memory_counts['EventListenerCount']
(...skipping 25 matching lines...) Expand all
483 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), 554 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description),
484 units_x='seconds') 555 units_x='seconds')
485 556
486 # V8 memory allocated. 557 # V8 memory allocated.
487 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB. 558 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB.
488 self._OutputPerfGraphValue( 559 self._OutputPerfGraphValue(
489 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB', 560 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB',
490 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description), 561 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description),
491 units_x='seconds') 562 units_x='seconds')
492 563
493 # Deep Memory Profiler result. 564 if self._dmprof:
494 if self._deep_memory_profile: 565 self._dmprof.ParseResultAndOutputPerfGraphValues(
495 deep_memory_profile_results = {} 566 webapp_name, test_description, self._OutputPerfGraphValue)
496 if self._deep_memory_profile_last_json_filename:
497 json_data = {}
498 with open(self._deep_memory_profile_last_json_filename) as json_f:
499 json_data = json.load(json_f)
500 if json_data['version'] == 'JSON_DEEP_1':
501 deep_memory_profile_results = json_data['snapshots']
502 elif json_data['version'] == 'JSON_DEEP_2':
503 deep_memory_profile_results = json_data['policies']['l0']['snapshots']
504 if deep_memory_profile_results:
505 self._OutputPerfGraphValue(
506 'DMP-TCMallocUsed', [
507 (snapshot['second'], snapshot['tc-used-all'] / 1024.0)
508 for snapshot in deep_memory_profile_results],
509 'KB',
510 graph_name='%s%s-DMP-TCUsed' % (webapp_name, test_description),
511 units_x='seconds')
512 # TODO(dmikurube): Output graph values (for multi-lined graphs), here.
513 # 'deep_memory_profile_results' is the value to be output.
514 567
515 logging.info(' Total DOM node count: %d nodes' % dom_node_count) 568 logging.info(' Total DOM node count: %d nodes' % dom_node_count)
516 logging.info(' Event listener count: %d listeners' % event_listener_count) 569 logging.info(' Event listener count: %d listeners' % event_listener_count)
517 logging.info(' Browser process private memory: %d KB' % 570 logging.info(' Browser process private memory: %d KB' %
518 proc_info['browser_private_mem']) 571 proc_info['browser_private_mem'])
519 logging.info(' Tab process private memory: %d KB' % 572 logging.info(' Tab process private memory: %d KB' %
520 proc_info['tab_private_mem']) 573 proc_info['tab_private_mem'])
521 logging.info(' V8 memory used: %f KB' % v8_mem_used) 574 logging.info(' V8 memory used: %f KB' % v8_mem_used)
522 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated) 575 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated)
523 576
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after
1242 if not os.path.exists(scripts): 1295 if not os.path.exists(scripts):
1243 raise IOError('Injected scripts %s not found.' % scripts) 1296 raise IOError('Injected scripts %s not found.' % scripts)
1244 replay_options = ['--inject_scripts', scripts] 1297 replay_options = ['--inject_scripts', scripts]
1245 if 'WPR_RECORD' in os.environ: 1298 if 'WPR_RECORD' in os.environ:
1246 replay_options.append('--append') 1299 replay_options.append('--append')
1247 return webpagereplay.ReplayServer(archive_path, replay_options) 1300 return webpagereplay.ReplayServer(archive_path, replay_options)
1248 1301
1249 1302
1250 if __name__ == '__main__': 1303 if __name__ == '__main__':
1251 pyauto_functional.Main() 1304 pyauto_functional.Main()
OLDNEW
« no previous file with comments | « chrome/test/functional/perf.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698