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

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: removed an empty line 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
dennis_jeffrey 2012/09/11 20:57:29 maybe remove this blank line
Dai Mikurube (NOT FULLTIME) 2012/09/12 02:23:24 Done.
173 else:
174 logging.info(' No dump files.')
175
176 def ParseResultAndOutputPerfGraphValues(
177 self, webapp_name, test_description, output_perf_graph_value):
178 """Parses Deep Memory Profiler result, and outputs perf graph values."""
179 if not self._enabled:
180 return
181
182 results = {}
183 if self._last_json_filename:
184 json_data = {}
185 with open(self._last_json_filename) as json_f:
186 json_data = json.load(json_f)
187 if json_data['version'] == 'JSON_DEEP_1':
188 results = json_data['snapshots']
189 elif json_data['version'] == 'JSON_DEEP_2':
190 results = json_data['policies']['l2']['snapshots']
191 if results and results[-1]['second'] > self._last_time:
192 started = False
193 for legend in json_data['policies']['l2']['legends']:
194 if legend == 'FROM_HERE_FOR_TOTAL':
195 started = True
196 elif legend == 'UNTIL_HERE_FOR_TOTAL':
197 break
198 elif started:
199 output_perf_graph_value(
200 legend.encode('utf-8'), [
201 (int(round(snapshot['second'])), snapshot[legend] / 1024)
202 for snapshot in results
203 if snapshot['second'] > self._last_time],
204 'KB',
205 graph_name='%s%s-DMP' % (webapp_name, test_description),
206 units_x='seconds', is_stacked=True)
207 self._last_time = results[-1]['second']
208
209 def _WaitForDeepMemoryProfiler(self):
210 """Waits for the Deep Memory Profiler to finish if running."""
211 if not self._enabled or not self._proc:
212 return
213
214 self._proc.wait()
215 self._proc = None
216 if self._json_file:
217 self._last_json_filename = self._json_file.name
218 self._json_file.close()
219 self._json_file = None
220
221
48 class ChromeEndureBaseTest(perf.BasePerfTest): 222 class ChromeEndureBaseTest(perf.BasePerfTest):
49 """Implements common functionality for all Chrome Endure tests. 223 """Implements common functionality for all Chrome Endure tests.
50 224
51 All Chrome Endure test classes should inherit from this class. 225 All Chrome Endure test classes should inherit from this class.
52 """ 226 """
53 227
54 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. 228 _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. 229 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
56 # TODO(dennisjeffrey): Do we still need to tolerate errors? 230 # TODO(dennisjeffrey): Do we still need to tolerate errors?
57 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate. 231 _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 232
67 def setUp(self): 233 def setUp(self):
68 # The Web Page Replay environment variables must be parsed before 234 # The Web Page Replay environment variables must be parsed before
69 # perf.BasePerfTest.setUp() 235 # perf.BasePerfTest.setUp()
70 self._ParseReplayEnv() 236 self._ParseReplayEnv()
71 # The environment variables for the Deep Memory Profiler must be set 237 # The environment variables for the Deep Memory Profiler must be set
72 # before perf.BasePerfTest.setUp() to inherit them to Chrome. 238 # before perf.BasePerfTest.setUp() to inherit them to Chrome.
73 self._deep_memory_profile = self._GetDeepMemoryProfileEnv( 239 self._dmprof = DeepMemoryProfiler()
74 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 240 if self._dmprof:
75 241 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 242
86 perf.BasePerfTest.setUp(self) 243 perf.BasePerfTest.setUp(self)
87 244
88 self._test_length_sec = int( 245 self._test_length_sec = int(
89 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) 246 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC))
90 self._get_perf_stats_interval = int( 247 self._get_perf_stats_interval = int(
91 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) 248 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL))
92 249
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) 250 logging.info('Running test for %d seconds.', self._test_length_sec)
97 logging.info('Gathering perf stats every %d seconds.', 251 logging.info('Gathering perf stats every %d seconds.',
98 self._get_perf_stats_interval) 252 self._get_perf_stats_interval)
99 if self._deep_memory_profile: 253
100 logging.info('Running with the Deep Memory Profiler.') 254 if self._dmprof:
101 if self._deep_memory_profile_save: 255 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 256
106 # Set up a remote inspector client associated with tab 0. 257 # Set up a remote inspector client associated with tab 0.
107 logging.info('Setting up connection to remote inspector...') 258 logging.info('Setting up connection to remote inspector...')
108 self._remote_inspector_client = ( 259 self._remote_inspector_client = (
109 remote_inspector_client.RemoteInspectorClient()) 260 remote_inspector_client.RemoteInspectorClient())
110 logging.info('Connection to remote inspector set up successfully.') 261 logging.info('Connection to remote inspector set up successfully.')
111 262
112 self._test_start_time = 0 263 self._test_start_time = 0
113 self._num_errors = 0 264 self._num_errors = 0
114 self._events_to_output = [] 265 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() 266 self._StartReplayServerIfNecessary()
119 267
120 def tearDown(self): 268 def tearDown(self):
121 logging.info('Terminating connection to remote inspector...') 269 logging.info('Terminating connection to remote inspector...')
122 self._remote_inspector_client.Stop() 270 self._remote_inspector_client.Stop()
123 logging.info('Connection to remote inspector terminated.') 271 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 272
129 # Must be done at end of this function except for post-cleaning after 273 # Must be done at end of this function except for post-cleaning after
130 # Chrome finishes. 274 # Chrome finishes.
131 perf.BasePerfTest.tearDown(self) 275 perf.BasePerfTest.tearDown(self)
132 276
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() 277 # Must be done after perf.BasePerfTest.tearDown()
139 self._StopReplayServerIfNecessary() 278 self._StopReplayServerIfNecessary()
279 if self._dmprof:
280 self._dmprof.TearDown()
140 281
141 def _GetArchiveName(self): 282 def _GetArchiveName(self):
142 """Return the Web Page Replay archive name that corresponds to a test. 283 """Return the Web Page Replay archive name that corresponds to a test.
143 284
144 Override this function to return the name of an archive that 285 Override this function to return the name of an archive that
145 corresponds to the test, e.g "ChromeEndureGmailTest.wpr". 286 corresponds to the test, e.g "ChromeEndureGmailTest.wpr".
146 287
147 Returns: 288 Returns:
148 None, by default no archive name is provided. 289 None, by default no archive name is provided.
149 """ 290 """
(...skipping 23 matching lines...) Expand all
173 '_GetArchiveName() in your test?') 314 '_GetArchiveName() in your test?')
174 else: 315 else:
175 if self._archive_path and os.path.exists(self._archive_path): 316 if self._archive_path and os.path.exists(self._archive_path):
176 self._use_wpr = True 317 self._use_wpr = True
177 else: 318 else:
178 self._use_wpr = False 319 self._use_wpr = False
179 logging.info( 320 logging.info(
180 'Skipping Web Page Replay since archive file %sdoes not exist.', 321 'Skipping Web Page Replay since archive file %sdoes not exist.',
181 self._archive_path + ' ' if self._archive_path else '') 322 self._archive_path + ' ' if self._archive_path else '')
182 323
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): 324 def ExtraChromeFlags(self):
208 """Ensures Chrome is launched with custom flags. 325 """Ensures Chrome is launched with custom flags.
209 326
210 Returns: 327 Returns:
211 A list of extra flags to pass to Chrome when it is launched. 328 A list of extra flags to pass to Chrome when it is launched.
212 """ 329 """
213 # The same with setUp, but need to fetch the environment variable since 330 # The same with setUp, but need to fetch the environment variable since
214 # ExtraChromeFlags is called before setUp. 331 # ExtraChromeFlags is called before setUp.
215 deep_memory_profile = self._GetDeepMemoryProfileEnv( 332 deep_memory_profile = DeepMemoryProfiler.GetEnvironmentVariable(
216 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 333 'DEEP_MEMORY_PROFILE', bool, DeepMemoryProfiler.DEEP_MEMORY_PROFILE)
217 334
218 # Ensure Chrome enables remote debugging on port 9222. This is required to 335 # Ensure Chrome enables remote debugging on port 9222. This is required to
219 # interact with Chrome's remote inspector. 336 # interact with Chrome's remote inspector.
220 extra_flags = ['--remote-debugging-port=9222'] 337 extra_flags = ['--remote-debugging-port=9222']
221 if deep_memory_profile: 338 if deep_memory_profile:
222 extra_flags.append('--no-sandbox') 339 extra_flags.append('--no-sandbox')
223 if self._use_wpr: 340 if self._use_wpr:
224 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS) 341 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS)
225 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags 342 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags
226 343
(...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 378 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 379 performed by this test. The callable is invoked iteratively for the
263 duration of the test. 380 duration of the test.
264 frame_xpath: The string xpath of the frame in which to inject javascript 381 frame_xpath: The string xpath of the frame in which to inject javascript
265 to clear chromedriver's cache (a temporary workaround until the 382 to clear chromedriver's cache (a temporary workaround until the
266 WebDriver team changes how they handle their DOM node cache). 383 WebDriver team changes how they handle their DOM node cache).
267 """ 384 """
268 self._num_errors = 0 385 self._num_errors = 0
269 self._test_start_time = time.time() 386 self._test_start_time = time.time()
270 last_perf_stats_time = time.time() 387 last_perf_stats_time = time.time()
271 if self._deep_memory_profile: 388 if self._dmprof:
272 self.HeapProfilerDump('renderer', 'Chrome Endure (first)') 389 self.HeapProfilerDump('renderer', 'Chrome Endure (first)')
273 self._GetPerformanceStats( 390 self._GetPerformanceStats(
274 webapp_name, test_description, tab_title_substring) 391 webapp_name, test_description, tab_title_substring)
275 self._iteration_num = 0 # Available to |do_scenario| if needed. 392 self._iteration_num = 0 # Available to |do_scenario| if needed.
276 393
277 self._remote_inspector_client.StartTimelineEventMonitoring( 394 self._remote_inspector_client.StartTimelineEventMonitoring(
278 self._OnTimelineEvent) 395 self._OnTimelineEvent)
279 396
280 while time.time() - self._test_start_time < self._test_length_sec: 397 while time.time() - self._test_start_time < self._test_length_sec:
281 self._iteration_num += 1 398 self._iteration_num += 1
282 399
283 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: 400 if self._num_errors >= self._ERROR_COUNT_THRESHOLD:
284 logging.error('Error count threshold (%d) reached. Terminating test ' 401 logging.error('Error count threshold (%d) reached. Terminating test '
285 'early.' % self._ERROR_COUNT_THRESHOLD) 402 'early.' % self._ERROR_COUNT_THRESHOLD)
286 break 403 break
287 404
288 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: 405 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
289 last_perf_stats_time = time.time() 406 last_perf_stats_time = time.time()
290 if self._deep_memory_profile: 407 if self._dmprof:
291 self.HeapProfilerDump('renderer', 'Chrome Endure') 408 self.HeapProfilerDump('renderer', 'Chrome Endure')
292 self._GetPerformanceStats( 409 self._GetPerformanceStats(
293 webapp_name, test_description, tab_title_substring) 410 webapp_name, test_description, tab_title_substring)
294 411
295 if self._iteration_num % 10 == 0: 412 if self._iteration_num % 10 == 0:
296 remaining_time = self._test_length_sec - (time.time() - 413 remaining_time = self._test_length_sec - (time.time() -
297 self._test_start_time) 414 self._test_start_time)
298 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % 415 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' %
299 (self._iteration_num, remaining_time)) 416 (self._iteration_num, remaining_time))
300 417
301 do_scenario() 418 do_scenario()
302 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the 419 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the
303 # results of Chrome Endure. 420 # results of Chrome Endure.
304 # TODO(dennisjeffrey): Once the WebDriver team implements changes to 421 # TODO(dennisjeffrey): Once the WebDriver team implements changes to
305 # handle their DOM node cache differently, we need to revisit this. It 422 # 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. 423 # may no longer be necessary at that point to forcefully delete the cache.
307 # Additionally, the Javascript below relies on an internal property of 424 # Additionally, the Javascript below relies on an internal property of
308 # WebDriver that may change at any time. This is only a temporary 425 # WebDriver that may change at any time. This is only a temporary
309 # workaround to stabilize the Chrome Endure test results. 426 # workaround to stabilize the Chrome Endure test results.
310 js = """ 427 js = """
311 (function() { 428 (function() {
312 delete document.$wdc_; 429 delete document.$wdc_;
313 window.domAutomationController.send('done'); 430 window.domAutomationController.send('done');
314 })(); 431 })();
315 """ 432 """
316 self.ExecuteJavascript(js, frame_xpath=frame_xpath) 433 self.ExecuteJavascript(js, frame_xpath=frame_xpath)
317 434
318 self._remote_inspector_client.StopTimelineEventMonitoring() 435 self._remote_inspector_client.StopTimelineEventMonitoring()
319 436
320 if self._deep_memory_profile: 437 if self._dmprof:
321 self.HeapProfilerDump('renderer', 'Chrome Endure (last)') 438 self.HeapProfilerDump('renderer', 'Chrome Endure (last)')
322 self._GetPerformanceStats( 439 self._GetPerformanceStats(
323 webapp_name, test_description, tab_title_substring, is_last=True) 440 webapp_name, test_description, tab_title_substring, is_last=True)
324 441
325 def _GetProcessInfo(self, tab_title_substring): 442 def _GetProcessInfo(self, tab_title_substring):
326 """Gets process info associated with an open browser/tab. 443 """Gets process info associated with an open browser/tab.
327 444
328 Args: 445 Args:
329 tab_title_substring: A unique substring contained within the title of 446 tab_title_substring: A unique substring contained within the title of
330 the tab to use; needed for locating the tab info. 447 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. 508 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 509 is_last: A boolean value which should be True if it's the last call of
393 _GetPerformanceStats. The default is False. 510 _GetPerformanceStats. The default is False.
394 """ 511 """
395 logging.info('Gathering performance stats...') 512 logging.info('Gathering performance stats...')
396 elapsed_time = int(round(time.time() - self._test_start_time)) 513 elapsed_time = int(round(time.time() - self._test_start_time))
397 514
398 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() 515 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts()
399 proc_info = self._GetProcessInfo(tab_title_substring) 516 proc_info = self._GetProcessInfo(tab_title_substring)
400 517
401 # Run Deep Memory Profiler in background. 518 if self._dmprof:
402 if self._deep_memory_profile: 519 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 520
449 # DOM node count. 521 # DOM node count.
450 dom_node_count = memory_counts['DOMNodeCount'] 522 dom_node_count = memory_counts['DOMNodeCount']
451 self._OutputPerfGraphValue( 523 self._OutputPerfGraphValue(
452 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes', 524 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes',
453 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), 525 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description),
454 units_x='seconds') 526 units_x='seconds')
455 527
456 # Event listener count. 528 # Event listener count.
457 event_listener_count = memory_counts['EventListenerCount'] 529 event_listener_count = memory_counts['EventListenerCount']
(...skipping 25 matching lines...) Expand all
483 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), 555 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description),
484 units_x='seconds') 556 units_x='seconds')
485 557
486 # V8 memory allocated. 558 # V8 memory allocated.
487 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB. 559 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB.
488 self._OutputPerfGraphValue( 560 self._OutputPerfGraphValue(
489 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB', 561 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB',
490 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description), 562 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description),
491 units_x='seconds') 563 units_x='seconds')
492 564
493 # Deep Memory Profiler result. 565 if self._dmprof:
494 if self._deep_memory_profile: 566 self._dmprof.ParseResultAndOutputPerfGraphValues(
495 deep_memory_profile_results = {} 567 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 568
515 logging.info(' Total DOM node count: %d nodes' % dom_node_count) 569 logging.info(' Total DOM node count: %d nodes' % dom_node_count)
516 logging.info(' Event listener count: %d listeners' % event_listener_count) 570 logging.info(' Event listener count: %d listeners' % event_listener_count)
517 logging.info(' Browser process private memory: %d KB' % 571 logging.info(' Browser process private memory: %d KB' %
518 proc_info['browser_private_mem']) 572 proc_info['browser_private_mem'])
519 logging.info(' Tab process private memory: %d KB' % 573 logging.info(' Tab process private memory: %d KB' %
520 proc_info['tab_private_mem']) 574 proc_info['tab_private_mem'])
521 logging.info(' V8 memory used: %f KB' % v8_mem_used) 575 logging.info(' V8 memory used: %f KB' % v8_mem_used)
522 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated) 576 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated)
523 577
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after
1242 if not os.path.exists(scripts): 1296 if not os.path.exists(scripts):
1243 raise IOError('Injected scripts %s not found.' % scripts) 1297 raise IOError('Injected scripts %s not found.' % scripts)
1244 replay_options = ['--inject_scripts', scripts] 1298 replay_options = ['--inject_scripts', scripts]
1245 if 'WPR_RECORD' in os.environ: 1299 if 'WPR_RECORD' in os.environ:
1246 replay_options.append('--append') 1300 replay_options.append('--append')
1247 return webpagereplay.ReplayServer(archive_path, replay_options) 1301 return webpagereplay.ReplayServer(archive_path, replay_options)
1248 1302
1249 1303
1250 if __name__ == '__main__': 1304 if __name__ == '__main__':
1251 pyauto_functional.Main() 1305 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