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

Unified Diff: chrome/test/functional/perf_endure.py

Issue 9655016: Enable Deep Memory Profiler in perf_endure.py. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: don't run DMP by default. Created 8 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/functional/perf_endure.py
diff --git a/chrome/test/functional/perf_endure.py b/chrome/test/functional/perf_endure.py
old mode 100644
new mode 100755
index df80e73fdedb323f19f132d46f88c635cc189edb..2f79e07c8072d929db37df54c881b56338b1623a
--- a/chrome/test/functional/perf_endure.py
+++ b/chrome/test/functional/perf_endure.py
@@ -9,21 +9,29 @@ This module accepts the following environment variable inputs:
TEST_LENGTH: The number of seconds in which to run each test.
PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling
of performance/memory statistics.
+
+ DEEP_MEMORY_PROFILE_INTERVAL: The number of seconds to wait in-between each
+ sampling for the Deep Memory Profiler.
+ DEEP_MEMORY_PROFILE_SAVE: Don't clean-up profile dump files if it's set.
"""
+from datetime import datetime
+import json
import logging
import os
import re
+import subprocess
+import tempfile
import time
import perf
import pyauto_functional # Must be imported before pyauto.
import pyauto
+import pyauto_utils
import remote_inspector_client
import selenium.common.exceptions
from selenium.webdriver.support.ui import WebDriverWait
-
class ChromeEndureBaseTest(perf.BasePerfTest):
"""Implements common functionality for all Chrome Endure tests.
@@ -33,8 +41,40 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
_DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
_GET_PERF_STATS_INTERVAL = 60 * 10 # Measure perf stats every 10 minutes.
_ERROR_COUNT_THRESHOLD = 300 # Number of ChromeDriver errors to tolerate.
+ _DEEP_MEMORY_PROFILE_INTERVAL = 0
+ _DEEP_MEMORY_PROFILE_SAVE = False
+
+ _DMPROF_DIR_PATH = os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+ 'tools', 'deep_memory_profiler')
+
+ _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
+
+ # TODO(dmikurube): Need to find an actual running chrome.
+ _CHROME_BIN_PATH = os.path.join(
+ os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+ 'out', 'Debug', 'chrome')
def setUp(self):
+ # These environment variables for the Deep Memory Profiler must be set
+ # before perf.BasePerfTest.setUp() to inherit them to Chrome.
+ self._deep_memory_profile_interval = 0
+ if self.IsLinux():
+ self._deep_memory_profile_interval = int(
+ os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL',
+ self._DEEP_MEMORY_PROFILE_INTERVAL))
+
+ if self._deep_memory_profile_interval > 0:
+ dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
+ self._deep_tempdir = tempfile.mkdtemp(prefix=dir_prefix)
+ os.environ['HEAPPROFILE'] = os.path.join(self._deep_tempdir, 'endure')
+ os.environ['HEAP_PROFILE_MMAP'] = 'True'
+ os.environ['DEEP_HEAP_PROFILE'] = 'True'
+ # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL when PyAuto
+ # supports to dump renderer heap profile.
+ os.environ['HEAP_PROFILE_TIME_INTERVAL'] = (
+ '%d' % self._deep_memory_profile_interval)
+
perf.BasePerfTest.setUp(self)
self._test_length_sec = int(
@@ -42,9 +82,21 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._get_perf_stats_interval = int(
os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL))
+ self._deep_memory_profile_save = False
+ if self.IsLinux():
+ self._deep_memory_profile_save = bool(
+ os.environ.get('DEEP_MEMORY_PROFILE_SAVE',
+ self._DEEP_MEMORY_PROFILE_SAVE))
+ self._deep_memory_profile_last_json_filename = ''
+
logging.info('Running test for %d seconds.', self._test_length_sec)
logging.info('Gathering perf stats every %d seconds.',
self._get_perf_stats_interval)
+ if self._deep_memory_profile_interval > 0:
+ logging.info('Running with the Deep Memory Profiler every %d seconds.',
+ self._deep_memory_profile_interval)
+ if self._deep_memory_profile_save:
+ logging.info('Dump files by the Deep Memory Profiler are not cleaned.')
# Set up a remote inspector client associated with tab 0.
logging.info('Setting up connection to remote inspector...')
@@ -60,12 +112,25 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._test_start_time = 0
self._num_errors = 0
self._iteration_num = 0
+ self._deep_memory_profile_json_f = None
dennis_jeffrey 2012/04/17 22:36:14 I recommend using "file" instead of just "f", just
Dai Mikurube (NOT FULLTIME) 2012/04/18 04:59:51 Done.
+ self._deep_memory_profile_proc = None
def tearDown(self):
logging.info('Terminating connection to remote inspector...')
self._remote_inspector_client.Stop()
logging.info('Connection to remote inspector terminated.')
+ if self._deep_memory_profile_interval > 0:
+ # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL in setUp when
+ # PyAuto supports to dump renderer heap profile.
+ del os.environ['HEAP_PROFILE_TIME_INTERVAL']
+ del os.environ['DEEP_HEAP_PROFILE']
+ del os.environ['HEAP_PROFILE_MMAP']
+ del os.environ['HEAPPROFILE']
perf.BasePerfTest.tearDown(self) # Must be done at end of this function.
dennis_jeffrey 2012/04/17 22:36:14 Maybe we should move this line to the bottom of th
Dai Mikurube (NOT FULLTIME) 2012/04/18 04:59:51 We have to remove the temporary directory after Ch
+ if (self._deep_memory_profile_interval > 0 and
+ not self._deep_memory_profile_save and
+ self._deep_tempdir):
+ pyauto_utils.RemovePath(self._deep_tempdir)
def ExtraChromeFlags(self):
"""Ensures Chrome is launched with custom flags.
@@ -73,10 +138,20 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
Returns:
A list of extra flags to pass to Chrome when it is launched.
"""
+ # The same with setUp, but need to fetch the environment variable since
+ # ExtraChromeFlags is called before setUp.
+ deep_memory_profile_interval = 0
+ if self.IsLinux():
+ deep_memory_profile_interval = int(
+ os.environ.get('DEEP_MEMORY_PROFILE_INTERVAL',
+ self._DEEP_MEMORY_PROFILE_INTERVAL))
+
# Ensure Chrome enables remote debugging on port 9222. This is required to
# interact with Chrome's remote inspector.
- return (perf.BasePerfTest.ExtraChromeFlags(self) +
- ['--remote-debugging-port=9222'])
+ extra_flags = ['--remote-debugging-port=9222']
+ if deep_memory_profile_interval > 0:
+ extra_flags.append('--no-sandbox')
+ return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags)
def _RunEndureTest(self, webapp_name, tab_title_substring, test_description,
do_scenario):
@@ -100,6 +175,8 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._num_errors = 0
self._test_start_time = time.time()
last_perf_stats_time = time.time()
+ # Note: this variable will be removed when committing.
+ last_deep_memory_profile_time = time.time()
self._GetPerformanceStats(
webapp_name, test_description, tab_title_substring)
self._iteration_num = 0
@@ -111,6 +188,14 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
'early.' % self._ERROR_COUNT_THRESHOLD)
break
+ # Note: this block will be removed when committing.
+ # TODO(dmikurube): Need pid of the target process.
+ if (self._deep_memory_profile_interval > 0 and
+ time.time() - last_deep_memory_profile_time >=
+ self._deep_memory_profile_interval):
+ last_deep_memory_profile_time = time.time()
+ logging.info('HeapProfilerDump would be called here.')
+
if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
last_perf_stats_time = time.time()
self._GetPerformanceStats(
@@ -124,8 +209,12 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
do_scenario()
+ # Note: this block will be removed when committing.
+ if self._deep_memory_profile_interval > 0:
+ logging.info('HeapProfilerDump would be called here.')
+
self._GetPerformanceStats(
- webapp_name, test_description, tab_title_substring)
+ webapp_name, test_description, tab_title_substring, is_last=True)
def _GetProcessInfo(self, tab_title_substring):
"""Gets process info associated with an open browser/tab.
@@ -142,6 +231,7 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
# browser process, in KB.
'tab_private_mem': integer, # Private memory associated with the tab
# process, in KB.
+ 'tab_pid': integer, # Process ID of the tab process.
}
"""
browser_process_name = (
@@ -178,10 +268,11 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
return {
'browser_private_mem': browser_proc_info['working_set_mem']['priv'],
'tab_private_mem': tab_proc_info['working_set_mem']['priv'],
+ 'tab_pid': tab_proc_info['pid'],
}
def _GetPerformanceStats(self, webapp_name, test_description,
- tab_title_substring):
+ tab_title_substring, is_last=False):
"""Gets performance statistics and outputs the results.
Args:
@@ -192,6 +283,8 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
example, 'ComposeDiscard' for Gmail.
tab_title_substring: A unique substring contained within the title of
the tab to use, for identifying the appropriate tab.
+ is_last: A boolean value which should be True if it's the last call of
+ _GetPerformanceStats. The default is False.
"""
logging.info('Gathering performance stats...')
elapsed_time = time.time() - self._test_start_time
@@ -223,6 +316,67 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
logging.info(' V8 memory used: %f KB' % v8_mem_used)
self._v8_mem_used_results.append((elapsed_time, v8_mem_used))
+ # TODO(dmikurube): A part of this block should be carved out as a function.
+ if self._deep_memory_profile_interval > 0:
+ logging.info('Profiling with the Deep Memory Profiler...')
+
+ # Wait for a running dmprof process for last _GetPerformanceStat call to
+ # cover last dump files.
+ if is_last and self._deep_memory_profile_proc:
+ logging.info(' Waiting for the last dmprof.')
+ self._deep_memory_profile_proc.wait()
+ self._deep_memory_profile_proc = None
+ if self._deep_memory_profile_json_f:
+ self._deep_memory_profile_last_json_filename = (
+ self._deep_memory_profile_json_f.name)
+ self._deep_memory_profile_json_f.close()
+ self._deep_memory_profile_json_f = None
+
+ if (self._deep_memory_profile_proc and
+ self._deep_memory_profile_proc.poll() is None):
+ logging.info(' Last dmprof is still running.')
+ else:
+ if self._deep_memory_profile_json_f:
+ self._deep_memory_profile_last_json_filename = (
+ self._deep_memory_profile_json_f.name)
+ self._deep_memory_profile_json_f.close()
+ self._deep_memory_profile_json_f = None
+ first_dump = ''
+ last_dump = ''
+ for filename in sorted(os.listdir(self._deep_tempdir)):
+ if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
+ filename):
+ logging.info(' Profiled dump file: %s' % filename)
+ last_dump = filename
+ if not first_dump:
+ first_dump = filename
+ if first_dump:
+ logging.info(' First dump file: %s' % first_dump)
+ matched= re.match('^endure.\d+.(\d+).heap$', last_dump)
+ last_sequence_id = matched.group(1)
+ self._deep_memory_profile_json_f = open(
+ os.path.join(self._deep_tempdir,
+ 'endure.%05d.%s.json' % (proc_info['tab_pid'],
+ last_sequence_id)), 'w+')
+ self._deep_memory_profile_proc = subprocess.Popen(
+ '%s --json %s %s %s' % (self._DMPROF_SCRIPT_PATH,
+ self._CHROME_BIN_PATH,
+ os.path.join(self._DMPROF_DIR_PATH,
+ 'policy.l2.txt'),
+ os.path.join(self._deep_tempdir,
+ first_dump)),
+ shell=True, stdout=self._deep_memory_profile_json_f)
+ # Don't wait for the new process since dmprof may take long time.
+
+ if is_last:
+ self._deep_memory_profile_proc.wait()
+ self._deep_memory_profile_last_json_filename = (
+ self._deep_memory_profile_json_f.name)
+ self._deep_memory_profile_json_f.close()
+
+ else:
+ logging.info(' No dump files.')
+
# Output the results seen so far, to be graphed.
self._OutputPerfGraphValue(
'TotalDOMNodeCount', self._dom_node_count_results, 'nodes',
@@ -244,6 +398,19 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
'V8MemoryUsed', self._v8_mem_used_results, 'KB',
graph_name='%s%s-V8MemUsed' % (webapp_name, test_description),
units_x='seconds')
+ if self._deep_memory_profile_interval > 0:
+ deep_memory_profile_results = {}
+ if self._deep_memory_profile_last_json_filename:
+ json_data = {}
+ with open(self._deep_memory_profile_last_json_filename) as json_f:
+ json_data = json.load(json_f)
+ if json_data['version'] == 'JSON_DEEP_1':
+ for component in json_data['legends']:
+ deep_memory_profile_results[component] = []
+ for snapshot in json_data['snapshots']:
+ deep_memory_profile_results[component].append(snapshot[component])
+ # TODO(dmikurube): Output graph values (for multi-lined graphs), here.
+ # 'deep_memory_profile_results' is the value to be output.
def _GetElement(self, find_by, value):
"""Gets a WebDriver element object from the webpage DOM.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698