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

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: renamed 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
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 19 matching lines...) Expand all
30 import pyauto_utils 30 import pyauto_utils
31 import remote_inspector_client 31 import remote_inspector_client
32 import selenium.common.exceptions 32 import selenium.common.exceptions
33 from selenium.webdriver.support.ui import WebDriverWait 33 from selenium.webdriver.support.ui import WebDriverWait
34 34
35 35
36 class NotSupportedEnvironmentError(RuntimeError): 36 class NotSupportedEnvironmentError(RuntimeError):
37 """Represent an error raised since the environment (OS) is not supported.""" 37 """Represent an error raised since the environment (OS) is not supported."""
38 pass 38 pass
39 39
40
41 class DeepMemoryProfiler(object):
dennis_jeffrey 2012/09/05 17:34:12 add a docstring for this class
Dai Mikurube (NOT FULLTIME) 2012/09/06 05:30:10 Done.
42 DEEP_MEMORY_PROFILE = False
43 DEEP_MEMORY_PROFILE_SAVE = False
44
45 _DMPROF_DIR_PATH = os.path.join(
46 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
47 'tools', 'deep_memory_profiler')
48 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
49
50 def __init__(self):
51 self._enabled = self.GetDeepMemoryProfileEnv(
52 'DEEP_MEMORY_PROFILE', bool, self.DEEP_MEMORY_PROFILE)
53 self._save = False
54 self._json_file = None
55 self._last_json_filename = ''
56 self._proc = None
57 self._last_time = -1.0
58
59 def SetUp(self, is_linux):
60 if self._enabled:
dennis_jeffrey 2012/09/05 17:34:12 Rather than adding the "is enabled" checks at the
Dai Mikurube (NOT FULLTIME) 2012/09/06 05:30:10 Added checks at the call sites, but kept DeepMemor
61 if not is_linux:
62 raise NotSupportedEnvironmentError(
63 'Deep Memory Profiler is not supported in this environment (OS).')
64 dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
65 self._tempdir = tempfile.mkdtemp(prefix=dir_prefix)
66 os.environ['HEAPPROFILE'] = os.path.join(self._tempdir, 'endure')
67 os.environ['HEAP_PROFILE_MMAP'] = '1'
68 os.environ['DEEP_HEAP_PROFILE'] = '1'
69 self._save = self.GetDeepMemoryProfileEnv(
70 'DEEP_MEMORY_PROFILE_SAVE', bool, self.DEEP_MEMORY_PROFILE_SAVE)
71
72 def TearDown(self):
73 if self._enabled:
74 del os.environ['DEEP_HEAP_PROFILE']
75 del os.environ['HEAP_PROFILE_MMAP']
76 del os.environ['HEAPPROFILE']
77
78 def RemoveTemporaryFiles(self):
79 """Remove the temporary directory after Chrome finishes."""
80 if self._enabled and not self._save and self._tempdir:
81 pyauto_utils.RemovePath(self._tempdir)
82
83 def IsEnabled(self):
84 return self._enabled
85
86 def LogFirstMessage(self):
87 if self._enabled:
88 logging.info('Running with the Deep Memory Profiler.')
89 if self._save:
90 logging.info(' Dumped files won\'t be cleaned.')
91 else:
92 logging.info(' Dumped files will be cleaned up after every test.')
93
94 def GetDeepMemoryProfileEnv(self, env_name, converter, default):
95 """Returns a converted environment variable for the Deep Memory Profiler.
96
97 Args:
98 env_name: A string name of an environment variable.
99 converter: A function taking a string to convert an environment variable.
100 default: A value used if the environment variable is not specified.
101
102 Returns:
103 A value converted from the environment variable with 'converter'.
104 """
105 return converter(os.environ.get(env_name, default))
106
107 def StartProfiler(self, proc_info, is_last):
108 """Starts Deep Memory Profiler in background."""
109 if self._enabled:
110 logging.info(' Profiling with the Deep Memory Profiler...')
111
112 # Wait for a running dmprof process for last _GetPerformanceStat call to
113 # cover last dump files.
114 if is_last:
115 logging.info(' Waiting for the last dmprof.')
116 self._WaitForDeepMemoryProfiler()
117
118 if self._proc and self._proc.poll() is None:
119 logging.info(' Last dmprof is still running.')
120 else:
121 if self._json_file:
122 self._last_json_filename = self._json_file.name
123 self._json_file.close()
124 self._json_file = None
125 first_dump = ''
126 last_dump = ''
127 for filename in sorted(os.listdir(self._tempdir)):
128 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
129 filename):
130 logging.info(' Profiled dump file: %s' % filename)
131 last_dump = filename
132 if not first_dump:
133 first_dump = filename
134 if first_dump:
135 logging.info(' First dump file: %s' % first_dump)
136 matched = re.match('^endure.\d+.(\d+).heap$', last_dump)
137 last_sequence_id = matched.group(1)
138 self._json_file = open(
139 os.path.join(self._tempdir,
140 'endure.%05d.%s.json' % (proc_info['tab_pid'],
141 last_sequence_id)), 'w+')
142 self._proc = subprocess.Popen(
143 '%s json %s' % (self._DMPROF_SCRIPT_PATH,
144 os.path.join(self._tempdir, first_dump)),
145 shell=True, stdout=self._json_file)
146 # Don't wait for the new process since dmprof may take long time.
147
dennis_jeffrey 2012/09/05 17:34:12 remove this blank line; the comment above goes wit
Dai Mikurube (NOT FULLTIME) 2012/09/06 05:30:10 Done.
148 if is_last:
149 self._WaitForDeepMemoryProfiler()
150
151 else:
152 logging.info(' No dump files.')
153
154 def ParseResultAndOutputPerfGraphValues(
155 self, webapp_name, test_description, output_perf_graph_value):
156 """Parses Deep Memory Profiler result, and outputs perf graph values."""
157 if self._enabled:
158 results = {}
159 if self._last_json_filename:
160 json_data = {}
161 with open(self._last_json_filename) as json_f:
162 json_data = json.load(json_f)
163 if json_data['version'] == 'JSON_DEEP_1':
164 results = json_data['snapshots']
165 elif json_data['version'] == 'JSON_DEEP_2':
166 results = json_data['policies']['l2']['snapshots']
167 if results and results[-1]['second'] > self._last_time:
168 started = False
169 for legend in json_data['policies']['l2']['legends']:
170 if legend == 'FROM_HERE_FOR_TOTAL':
171 started = True
172 elif legend == 'UNTIL_HERE_FOR_TOTAL':
173 break
174 elif started:
175 output_perf_graph_value(
176 legend.encode('utf-8'), [
177 (int(round(snapshot['second'])), snapshot[legend] / 1024)
178 for snapshot in results
179 if snapshot['second'] > self._last_time],
180 'KB',
181 graph_name='%s%s-DMP' % (webapp_name, test_description),
182 units_x='seconds', is_stacked=True)
183 self._last_time = results[-1]['second']
184
185 def _WaitForDeepMemoryProfiler(self):
186 """Waits for the Deep Memory Profiler to finish if running."""
187 if self._enabled and self._proc:
188 self._proc.wait()
189 self._proc = None
190 if self._json_file:
191 self._last_json_filename = self._json_file.name
192 self._json_file.close()
193 self._json_file = None
194
195
40 class ChromeEndureBaseTest(perf.BasePerfTest): 196 class ChromeEndureBaseTest(perf.BasePerfTest):
41 """Implements common functionality for all Chrome Endure tests. 197 """Implements common functionality for all Chrome Endure tests.
42 198
43 All Chrome Endure test classes should inherit from this class. 199 All Chrome Endure test classes should inherit from this class.
44 """ 200 """
45 201
46 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. 202 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
47 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes. 203 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
48 # TODO(dennisjeffrey): Do we still need to tolerate errors? 204 # TODO(dennisjeffrey): Do we still need to tolerate errors?
49 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate. 205 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate.
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
57 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
58 206
59 def setUp(self): 207 def setUp(self):
60 # The environment variables for the Deep Memory Profiler must be set 208 # The environment variables for the Deep Memory Profiler must be set
61 # before perf.BasePerfTest.setUp() to inherit them to Chrome. 209 # before perf.BasePerfTest.setUp() to inherit them to Chrome.
62 self._deep_memory_profile = self._GetDeepMemoryProfileEnv( 210 self._dmprof = DeepMemoryProfiler()
63 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 211 self._dmprof.SetUp(self.IsLinux())
64
65 if self._deep_memory_profile:
66 if not self.IsLinux():
67 raise NotSupportedEnvironmentError(
68 'Deep Memory Profiler is not supported in this environment (OS).')
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 212
75 perf.BasePerfTest.setUp(self) 213 perf.BasePerfTest.setUp(self)
76 214
77 self._test_length_sec = int( 215 self._test_length_sec = int(
78 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC)) 216 os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC))
79 self._get_perf_stats_interval = int( 217 self._get_perf_stats_interval = int(
80 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL)) 218 os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL))
81 219
82 self._deep_memory_profile_save = self._GetDeepMemoryProfileEnv(
83 'DEEP_MEMORY_PROFILE_SAVE', bool, self._DEEP_MEMORY_PROFILE_SAVE)
84
85 logging.info('Running test for %d seconds.', self._test_length_sec) 220 logging.info('Running test for %d seconds.', self._test_length_sec)
86 logging.info('Gathering perf stats every %d seconds.', 221 logging.info('Gathering perf stats every %d seconds.',
87 self._get_perf_stats_interval) 222 self._get_perf_stats_interval)
88 if self._deep_memory_profile: 223
89 logging.info('Running with the Deep Memory Profiler.') 224 self._dmprof.LogFirstMessage()
90 if self._deep_memory_profile_save:
91 logging.info(' Dumped files won\'t be cleaned.')
92 else:
93 logging.info(' Dumped files will be cleaned up after every test.')
94 225
95 # Set up a remote inspector client associated with tab 0. 226 # Set up a remote inspector client associated with tab 0.
96 logging.info('Setting up connection to remote inspector...') 227 logging.info('Setting up connection to remote inspector...')
97 self._remote_inspector_client = ( 228 self._remote_inspector_client = (
98 remote_inspector_client.RemoteInspectorClient()) 229 remote_inspector_client.RemoteInspectorClient())
99 logging.info('Connection to remote inspector set up successfully.') 230 logging.info('Connection to remote inspector set up successfully.')
100 231
101 self._test_start_time = 0 232 self._test_start_time = 0
102 self._num_errors = 0 233 self._num_errors = 0
103 self._events_to_output = [] 234 self._events_to_output = []
104 self._deep_memory_profile_json_file = None
105 self._deep_memory_profile_last_json_filename = ''
106 self._deep_memory_profile_proc = None
107 235
108 def tearDown(self): 236 def tearDown(self):
109 logging.info('Terminating connection to remote inspector...') 237 logging.info('Terminating connection to remote inspector...')
110 self._remote_inspector_client.Stop() 238 self._remote_inspector_client.Stop()
111 logging.info('Connection to remote inspector terminated.') 239 logging.info('Connection to remote inspector terminated.')
112 if self._deep_memory_profile: 240
113 del os.environ['DEEP_HEAP_PROFILE'] 241 self._dmprof.TearDown()
114 del os.environ['HEAP_PROFILE_MMAP']
115 del os.environ['HEAPPROFILE']
116 242
117 # Must be done at end of this function except for post-cleaning after 243 # Must be done at end of this function except for post-cleaning after
118 # Chrome finishes. 244 # Chrome finishes.
119 perf.BasePerfTest.tearDown(self) 245 perf.BasePerfTest.tearDown(self)
120 246
121 # Remove the temporary directory after Chrome finishes in tearDown. 247 self._dmprof.RemoveTemporaryFiles()
dennis_jeffrey 2012/09/05 17:34:12 is there a reason this is done after calling the b
Dai Mikurube (NOT FULLTIME) 2012/09/06 05:30:10 It must be called after Chrome finishes. Chrome m
122 if (self._deep_memory_profile and
123 not self._deep_memory_profile_save and
124 self._deep_tempdir):
125 pyauto_utils.RemovePath(self._deep_tempdir)
126
127 def _GetDeepMemoryProfileEnv(self, env_name, converter, default):
128 """Returns a converted environment variable for the Deep Memory Profiler.
129
130 Args:
131 env_name: A string name of an environment variable.
132 converter: A function taking a string to convert an environment variable.
133 default: A value used if the environment variable is not specified.
134
135 Returns:
136 A value converted from the environment variable with 'converter'.
137 """
138 return converter(os.environ.get(env_name, default))
139
140 def _WaitForDeepMemoryProfiler(self):
141 """Waits for the Deep Memory Profiler to finish if running."""
142 if self._deep_memory_profile and self._deep_memory_profile_proc:
143 self._deep_memory_profile_proc.wait()
144 self._deep_memory_profile_proc = None
145 if self._deep_memory_profile_json_file:
146 self._deep_memory_profile_last_json_filename = (
147 self._deep_memory_profile_json_file.name)
148 self._deep_memory_profile_json_file.close()
149 self._deep_memory_profile_json_file = None
150 248
151 def ExtraChromeFlags(self): 249 def ExtraChromeFlags(self):
152 """Ensures Chrome is launched with custom flags. 250 """Ensures Chrome is launched with custom flags.
153 251
154 Returns: 252 Returns:
155 A list of extra flags to pass to Chrome when it is launched. 253 A list of extra flags to pass to Chrome when it is launched.
156 """ 254 """
157 # The same with setUp, but need to fetch the environment variable since 255 # The same with setUp, but need to fetch the environment variable since
158 # ExtraChromeFlags is called before setUp. 256 # ExtraChromeFlags is called before setUp.
159 deep_memory_profile = self._GetDeepMemoryProfileEnv( 257 deep_memory_profile = self._dmprof.GetDeepMemoryProfileEnv(
160 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 258 'DEEP_MEMORY_PROFILE', bool, self._dmprof.DEEP_MEMORY_PROFILE)
161 259
162 # Ensure Chrome enables remote debugging on port 9222. This is required to 260 # Ensure Chrome enables remote debugging on port 9222. This is required to
163 # interact with Chrome's remote inspector. 261 # interact with Chrome's remote inspector.
164 extra_flags = ['--remote-debugging-port=9222'] 262 extra_flags = ['--remote-debugging-port=9222']
165 if deep_memory_profile: 263 if deep_memory_profile:
166 extra_flags.append('--no-sandbox') 264 extra_flags.append('--no-sandbox')
167 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags) 265 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags)
168 266
169 def _OnTimelineEvent(self, event_info): 267 def _OnTimelineEvent(self, event_info):
170 """Invoked by the Remote Inspector Client when a timeline event occurs. 268 """Invoked by the Remote Inspector Client when a timeline event occurs.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 do_scenario: A callable to be invoked that implements the scenario to be 301 do_scenario: A callable to be invoked that implements the scenario to be
204 performed by this test. The callable is invoked iteratively for the 302 performed by this test. The callable is invoked iteratively for the
205 duration of the test. 303 duration of the test.
206 frame_xpath: The string xpath of the frame in which to inject javascript 304 frame_xpath: The string xpath of the frame in which to inject javascript
207 to clear chromedriver's cache (a temporary workaround until the 305 to clear chromedriver's cache (a temporary workaround until the
208 WebDriver team changes how they handle their DOM node cache). 306 WebDriver team changes how they handle their DOM node cache).
209 """ 307 """
210 self._num_errors = 0 308 self._num_errors = 0
211 self._test_start_time = time.time() 309 self._test_start_time = time.time()
212 last_perf_stats_time = time.time() 310 last_perf_stats_time = time.time()
213 if self._deep_memory_profile: 311 if self._dmprof.IsEnabled():
214 self.HeapProfilerDump('renderer', 'Chrome Endure (first)') 312 self.HeapProfilerDump('renderer', 'Chrome Endure (first)')
215 self._GetPerformanceStats( 313 self._GetPerformanceStats(
216 webapp_name, test_description, tab_title_substring) 314 webapp_name, test_description, tab_title_substring)
217 self._iteration_num = 0 # Available to |do_scenario| if needed. 315 self._iteration_num = 0 # Available to |do_scenario| if needed.
218 316
219 self._remote_inspector_client.StartTimelineEventMonitoring( 317 self._remote_inspector_client.StartTimelineEventMonitoring(
220 self._OnTimelineEvent) 318 self._OnTimelineEvent)
221 319
222 while time.time() - self._test_start_time < self._test_length_sec: 320 while time.time() - self._test_start_time < self._test_length_sec:
223 self._iteration_num += 1 321 self._iteration_num += 1
224 322
225 if self._num_errors >= self._ERROR_COUNT_THRESHOLD: 323 if self._num_errors >= self._ERROR_COUNT_THRESHOLD:
226 logging.error('Error count threshold (%d) reached. Terminating test ' 324 logging.error('Error count threshold (%d) reached. Terminating test '
227 'early.' % self._ERROR_COUNT_THRESHOLD) 325 'early.' % self._ERROR_COUNT_THRESHOLD)
228 break 326 break
229 327
230 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval: 328 if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
231 last_perf_stats_time = time.time() 329 last_perf_stats_time = time.time()
232 if self._deep_memory_profile: 330 if self._dmprof.IsEnabled():
233 self.HeapProfilerDump('renderer', 'Chrome Endure') 331 self.HeapProfilerDump('renderer', 'Chrome Endure')
234 self._GetPerformanceStats( 332 self._GetPerformanceStats(
235 webapp_name, test_description, tab_title_substring) 333 webapp_name, test_description, tab_title_substring)
236 334
237 if self._iteration_num % 10 == 0: 335 if self._iteration_num % 10 == 0:
238 remaining_time = self._test_length_sec - (time.time() - 336 remaining_time = self._test_length_sec - (time.time() -
239 self._test_start_time) 337 self._test_start_time)
240 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' % 338 logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' %
241 (self._iteration_num, remaining_time)) 339 (self._iteration_num, remaining_time))
242 340
243 do_scenario() 341 do_scenario()
244 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the 342 # Clear ChromeDriver's DOM node cache so its growth doesn't affect the
245 # results of Chrome Endure. 343 # results of Chrome Endure.
246 # TODO(dennisjeffrey): Once the WebDriver team implements changes to 344 # TODO(dennisjeffrey): Once the WebDriver team implements changes to
247 # handle their DOM node cache differently, we need to revisit this. It 345 # handle their DOM node cache differently, we need to revisit this. It
248 # may no longer be necessary at that point to forcefully delete the cache. 346 # may no longer be necessary at that point to forcefully delete the cache.
249 # Additionally, the Javascript below relies on an internal property of 347 # Additionally, the Javascript below relies on an internal property of
250 # WebDriver that may change at any time. This is only a temporary 348 # WebDriver that may change at any time. This is only a temporary
251 # workaround to stabilize the Chrome Endure test results. 349 # workaround to stabilize the Chrome Endure test results.
252 js = """ 350 js = """
253 (function() { 351 (function() {
254 delete document.$wdc_; 352 delete document.$wdc_;
255 window.domAutomationController.send('done'); 353 window.domAutomationController.send('done');
256 })(); 354 })();
257 """ 355 """
258 self.ExecuteJavascript(js, frame_xpath=frame_xpath) 356 self.ExecuteJavascript(js, frame_xpath=frame_xpath)
259 357
260 self._remote_inspector_client.StopTimelineEventMonitoring() 358 self._remote_inspector_client.StopTimelineEventMonitoring()
261 359
262 if self._deep_memory_profile: 360 if self._dmprof.IsEnabled():
263 self.HeapProfilerDump('renderer', 'Chrome Endure (last)') 361 self.HeapProfilerDump('renderer', 'Chrome Endure (last)')
264 self._GetPerformanceStats( 362 self._GetPerformanceStats(
265 webapp_name, test_description, tab_title_substring, is_last=True) 363 webapp_name, test_description, tab_title_substring, is_last=True)
266 364
267 def _GetProcessInfo(self, tab_title_substring): 365 def _GetProcessInfo(self, tab_title_substring):
268 """Gets process info associated with an open browser/tab. 366 """Gets process info associated with an open browser/tab.
269 367
270 Args: 368 Args:
271 tab_title_substring: A unique substring contained within the title of 369 tab_title_substring: A unique substring contained within the title of
272 the tab to use; needed for locating the tab info. 370 the tab to use; needed for locating the tab info.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 the tab to use, for identifying the appropriate tab. 431 the tab to use, for identifying the appropriate tab.
334 is_last: A boolean value which should be True if it's the last call of 432 is_last: A boolean value which should be True if it's the last call of
335 _GetPerformanceStats. The default is False. 433 _GetPerformanceStats. The default is False.
336 """ 434 """
337 logging.info('Gathering performance stats...') 435 logging.info('Gathering performance stats...')
338 elapsed_time = int(round(time.time() - self._test_start_time)) 436 elapsed_time = int(round(time.time() - self._test_start_time))
339 437
340 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts() 438 memory_counts = self._remote_inspector_client.GetMemoryObjectCounts()
341 proc_info = self._GetProcessInfo(tab_title_substring) 439 proc_info = self._GetProcessInfo(tab_title_substring)
342 440
343 # Run Deep Memory Profiler in background. 441 self._dmprof.StartProfiler(proc_info, is_last)
344 if self._deep_memory_profile:
345 logging.info(' Profiling with the Deep Memory Profiler...')
346
347 # Wait for a running dmprof process for last _GetPerformanceStat call to
348 # cover last dump files.
349 if is_last:
350 logging.info(' Waiting for the last dmprof.')
351 self._WaitForDeepMemoryProfiler()
352
353 if (self._deep_memory_profile_proc and
354 self._deep_memory_profile_proc.poll() is None):
355 logging.info(' Last dmprof is still running.')
356 else:
357 if self._deep_memory_profile_json_file:
358 self._deep_memory_profile_last_json_filename = (
359 self._deep_memory_profile_json_file.name)
360 self._deep_memory_profile_json_file.close()
361 self._deep_memory_profile_json_file = None
362 first_dump = ''
363 last_dump = ''
364 for filename in sorted(os.listdir(self._deep_tempdir)):
365 if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
366 filename):
367 logging.info(' Profiled dump file: %s' % filename)
368 last_dump = filename
369 if not first_dump:
370 first_dump = filename
371 if first_dump:
372 logging.info(' First dump file: %s' % first_dump)
373 matched= re.match('^endure.\d+.(\d+).heap$', last_dump)
374 last_sequence_id = matched.group(1)
375 self._deep_memory_profile_json_file = open(
376 os.path.join(self._deep_tempdir,
377 'endure.%05d.%s.json' % (proc_info['tab_pid'],
378 last_sequence_id)), 'w+')
379 self._deep_memory_profile_proc = subprocess.Popen(
380 '%s json %s' % (self._DMPROF_SCRIPT_PATH,
381 os.path.join(self._deep_tempdir, first_dump)),
382 shell=True, stdout=self._deep_memory_profile_json_file)
383 # Don't wait for the new process since dmprof may take long time.
384
385 if is_last:
386 self._WaitForDeepMemoryProfiler()
387
388 else:
389 logging.info(' No dump files.')
390 442
391 # DOM node count. 443 # DOM node count.
392 dom_node_count = memory_counts['DOMNodeCount'] 444 dom_node_count = memory_counts['DOMNodeCount']
393 self._OutputPerfGraphValue( 445 self._OutputPerfGraphValue(
394 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes', 446 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes',
395 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description), 447 graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description),
396 units_x='seconds') 448 units_x='seconds')
397 449
398 # Event listener count. 450 # Event listener count.
399 event_listener_count = memory_counts['EventListenerCount'] 451 event_listener_count = memory_counts['EventListenerCount']
(...skipping 25 matching lines...) Expand all
425 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description), 477 graph_name='%s%s-V8MemUsed' % (webapp_name, test_description),
426 units_x='seconds') 478 units_x='seconds')
427 479
428 # V8 memory allocated. 480 # V8 memory allocated.
429 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB. 481 v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB.
430 self._OutputPerfGraphValue( 482 self._OutputPerfGraphValue(
431 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB', 483 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB',
432 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description), 484 graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description),
433 units_x='seconds') 485 units_x='seconds')
434 486
435 # Deep Memory Profiler result. 487 self._dmprof.ParseResultAndOutputPerfGraphValues(
436 if self._deep_memory_profile: 488 webapp_name, test_description, self._OutputPerfGraphValue)
437 deep_memory_profile_results = {}
438 if self._deep_memory_profile_last_json_filename:
439 json_data = {}
440 with open(self._deep_memory_profile_last_json_filename) as json_f:
441 json_data = json.load(json_f)
442 if json_data['version'] == 'JSON_DEEP_1':
443 deep_memory_profile_results = json_data['snapshots']
444 elif json_data['version'] == 'JSON_DEEP_2':
445 deep_memory_profile_results = json_data['policies']['l0']['snapshots']
446 if deep_memory_profile_results:
447 self._OutputPerfGraphValue(
448 'DMP-TCMallocUsed', [
449 (snapshot['second'], snapshot['tc-used-all'] / 1024.0)
450 for snapshot in deep_memory_profile_results],
451 'KB',
452 graph_name='%s%s-DMP-TCUsed' % (webapp_name, test_description),
453 units_x='seconds')
454 # TODO(dmikurube): Output graph values (for multi-lined graphs), here.
455 # 'deep_memory_profile_results' is the value to be output.
456 489
457 logging.info(' Total DOM node count: %d nodes' % dom_node_count) 490 logging.info(' Total DOM node count: %d nodes' % dom_node_count)
458 logging.info(' Event listener count: %d listeners' % event_listener_count) 491 logging.info(' Event listener count: %d listeners' % event_listener_count)
459 logging.info(' Browser process private memory: %d KB' % 492 logging.info(' Browser process private memory: %d KB' %
460 proc_info['browser_private_mem']) 493 proc_info['browser_private_mem'])
461 logging.info(' Tab process private memory: %d KB' % 494 logging.info(' Tab process private memory: %d KB' %
462 proc_info['tab_private_mem']) 495 proc_info['tab_private_mem'])
463 logging.info(' V8 memory used: %f KB' % v8_mem_used) 496 logging.info(' V8 memory used: %f KB' % v8_mem_used)
464 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated) 497 logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated)
465 498
(...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 self._num_errors += 1 1156 self._num_errors += 1
1124 1157
1125 time.sleep(1) 1158 time.sleep(1)
1126 1159
1127 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING, 1160 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
1128 test_description, scenario) 1161 test_description, scenario)
1129 1162
1130 1163
1131 if __name__ == '__main__': 1164 if __name__ == '__main__':
1132 pyauto_functional.Main() 1165 pyauto_functional.Main()
OLDNEW
« chrome/test/functional/perf.py ('K') | « chrome/test/functional/perf.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698