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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/functional/perf.py ('k') | 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
index 2cd9280ba302db92677c64f04de2dce40592f805..592f11e399fa058df88bb9420c796071d9ab6f1d 100755
--- a/chrome/test/functional/perf_endure.py
+++ b/chrome/test/functional/perf_endure.py
@@ -45,6 +45,180 @@ class NotSupportedEnvironmentError(RuntimeError):
pass
+class DeepMemoryProfiler(object):
+ """Controls Deep Memory Profiler (dmprof) for endurance tests."""
+ DEEP_MEMORY_PROFILE = False
+ 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')
+
+ def __init__(self):
+ self._enabled = self.GetEnvironmentVariable(
+ 'DEEP_MEMORY_PROFILE', bool, self.DEEP_MEMORY_PROFILE)
+ self._save = self.GetEnvironmentVariable(
+ 'DEEP_MEMORY_PROFILE_SAVE', bool, self.DEEP_MEMORY_PROFILE_SAVE)
+ self._json_file = None
+ self._last_json_filename = ''
+ self._proc = None
+ self._last_time = -1.0
+
+ def __nonzero__(self):
+ return self._enabled
+
+ @staticmethod
+ def GetEnvironmentVariable(env_name, converter, default):
+ """Returns a converted environment variable for Deep Memory Profiler.
+
+ Args:
+ env_name: A string name of an environment variable.
+ converter: A function taking a string to convert an environment variable.
+ default: A value used if the environment variable is not specified.
+
+ Returns:
+ A value converted from the environment variable with 'converter'.
+ """
+ return converter(os.environ.get(env_name, default))
+
+ def SetUp(self, is_linux):
+ """Sets up Deep Memory Profiler settings for a Chrome process.
+
+ It sets environment variables and makes a working directory.
+ """
+ if not self._enabled:
+ return
+
+ if not is_linux:
+ raise NotSupportedEnvironmentError(
+ 'Deep Memory Profiler is not supported in this environment (OS).')
+ dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
+ self._tempdir = tempfile.mkdtemp(prefix=dir_prefix)
+ os.environ['HEAPPROFILE'] = os.path.join(self._tempdir, 'endure')
+ os.environ['HEAP_PROFILE_MMAP'] = '1'
+ os.environ['DEEP_HEAP_PROFILE'] = '1'
+
+ def TearDown(self):
+ """Tear down Deep Memory Profiler settings for the Chrome process.
+
+ It removes the environment variables and the temporary directory.
+ Call it after Chrome finishes. Chrome may dump last files at the end.
+ """
+ if not self._enabled:
+ return
+
+ del os.environ['DEEP_HEAP_PROFILE']
+ del os.environ['HEAP_PROFILE_MMAP']
+ del os.environ['HEAPPROFILE']
+ if not self._save and self._tempdir:
+ pyauto_utils.RemovePath(self._tempdir)
+
+ def LogFirstMessage(self):
+ """Logs first messages."""
+ if not self._enabled:
+ return
+
+ logging.info('Running with the Deep Memory Profiler.')
+ if self._save:
+ logging.info(' Dumped files won\'t be cleaned.')
+ else:
+ logging.info(' Dumped files will be cleaned up after every test.')
+
+ def StartProfiler(self, proc_info, is_last):
+ """Starts Deep Memory Profiler in background."""
+ if not self._enabled:
+ return
+
+ 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:
+ logging.info(' Waiting for the last dmprof.')
+ self._WaitForDeepMemoryProfiler()
+
+ if self._proc and self._proc.poll() is None:
+ logging.info(' Last dmprof is still running.')
+ else:
+ if self._json_file:
+ self._last_json_filename = self._json_file.name
+ self._json_file.close()
+ self._json_file = None
+ first_dump = ''
+ last_dump = ''
+ for filename in sorted(os.listdir(self._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._json_file = open(
+ os.path.join(self._tempdir,
+ 'endure.%05d.%s.json' % (proc_info['tab_pid'],
+ last_sequence_id)), 'w+')
+ self._proc = subprocess.Popen(
+ '%s json %s' % (self._DMPROF_SCRIPT_PATH,
+ os.path.join(self._tempdir, first_dump)),
+ shell=True, stdout=self._json_file)
+ # Wait only when it is the last profiling. dmprof may take long time.
+ if is_last:
+ self._WaitForDeepMemoryProfiler()
+
dennis_jeffrey 2012/09/11 20:57:29 maybe remove this blank line
Dai Mikurube (NOT FULLTIME) 2012/09/12 02:23:24 Done.
+ else:
+ logging.info(' No dump files.')
+
+ def ParseResultAndOutputPerfGraphValues(
+ self, webapp_name, test_description, output_perf_graph_value):
+ """Parses Deep Memory Profiler result, and outputs perf graph values."""
+ if not self._enabled:
+ return
+
+ results = {}
+ if self._last_json_filename:
+ json_data = {}
+ with open(self._last_json_filename) as json_f:
+ json_data = json.load(json_f)
+ if json_data['version'] == 'JSON_DEEP_1':
+ results = json_data['snapshots']
+ elif json_data['version'] == 'JSON_DEEP_2':
+ results = json_data['policies']['l2']['snapshots']
+ if results and results[-1]['second'] > self._last_time:
+ started = False
+ for legend in json_data['policies']['l2']['legends']:
+ if legend == 'FROM_HERE_FOR_TOTAL':
+ started = True
+ elif legend == 'UNTIL_HERE_FOR_TOTAL':
+ break
+ elif started:
+ output_perf_graph_value(
+ legend.encode('utf-8'), [
+ (int(round(snapshot['second'])), snapshot[legend] / 1024)
+ for snapshot in results
+ if snapshot['second'] > self._last_time],
+ 'KB',
+ graph_name='%s%s-DMP' % (webapp_name, test_description),
+ units_x='seconds', is_stacked=True)
+ self._last_time = results[-1]['second']
+
+ def _WaitForDeepMemoryProfiler(self):
+ """Waits for the Deep Memory Profiler to finish if running."""
+ if not self._enabled or not self._proc:
+ return
+
+ self._proc.wait()
+ self._proc = None
+ if self._json_file:
+ self._last_json_filename = self._json_file.name
+ self._json_file.close()
+ self._json_file = None
+
+
class ChromeEndureBaseTest(perf.BasePerfTest):
"""Implements common functionality for all Chrome Endure tests.
@@ -55,14 +229,6 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
_GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
# TODO(dennisjeffrey): Do we still need to tolerate errors?
_ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate.
- _DEEP_MEMORY_PROFILE = False
- _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')
def setUp(self):
# The Web Page Replay environment variables must be parsed before
@@ -70,18 +236,9 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._ParseReplayEnv()
# The environment variables for the Deep Memory Profiler must be set
# before perf.BasePerfTest.setUp() to inherit them to Chrome.
- self._deep_memory_profile = self._GetDeepMemoryProfileEnv(
- 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
-
- if self._deep_memory_profile:
- if not self.IsLinux():
- raise NotSupportedEnvironmentError(
- 'Deep Memory Profiler is not supported in this environment (OS).')
- 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'
+ self._dmprof = DeepMemoryProfiler()
+ if self._dmprof:
+ self._dmprof.SetUp(self.IsLinux())
perf.BasePerfTest.setUp(self)
@@ -90,18 +247,12 @@ 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 = self._GetDeepMemoryProfileEnv(
- 'DEEP_MEMORY_PROFILE_SAVE', bool, self._DEEP_MEMORY_PROFILE_SAVE)
-
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:
- logging.info('Running with the Deep Memory Profiler.')
- if self._deep_memory_profile_save:
- logging.info(' Dumped files won\'t be cleaned.')
- else:
- logging.info(' Dumped files will be cleaned up after every test.')
+
+ if self._dmprof:
+ self._dmprof.LogFirstMessage()
# Set up a remote inspector client associated with tab 0.
logging.info('Setting up connection to remote inspector...')
@@ -112,31 +263,21 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._test_start_time = 0
self._num_errors = 0
self._events_to_output = []
- self._deep_memory_profile_json_file = None
- self._deep_memory_profile_last_json_filename = ''
- self._deep_memory_profile_proc = None
self._StartReplayServerIfNecessary()
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:
- del os.environ['DEEP_HEAP_PROFILE']
- del os.environ['HEAP_PROFILE_MMAP']
- del os.environ['HEAPPROFILE']
# Must be done at end of this function except for post-cleaning after
# Chrome finishes.
perf.BasePerfTest.tearDown(self)
- # Remove the temporary directory after Chrome finishes in tearDown.
- if (self._deep_memory_profile and
- not self._deep_memory_profile_save and
- self._deep_tempdir):
- pyauto_utils.RemovePath(self._deep_tempdir)
# Must be done after perf.BasePerfTest.tearDown()
self._StopReplayServerIfNecessary()
+ if self._dmprof:
+ self._dmprof.TearDown()
def _GetArchiveName(self):
"""Return the Web Page Replay archive name that corresponds to a test.
@@ -180,30 +321,6 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
'Skipping Web Page Replay since archive file %sdoes not exist.',
self._archive_path + ' ' if self._archive_path else '')
- def _GetDeepMemoryProfileEnv(self, env_name, converter, default):
- """Returns a converted environment variable for the Deep Memory Profiler.
-
- Args:
- env_name: A string name of an environment variable.
- converter: A function taking a string to convert an environment variable.
- default: A value used if the environment variable is not specified.
-
- Returns:
- A value converted from the environment variable with 'converter'.
- """
- return converter(os.environ.get(env_name, default))
-
- def _WaitForDeepMemoryProfiler(self):
- """Waits for the Deep Memory Profiler to finish if running."""
- if self._deep_memory_profile and self._deep_memory_profile_proc:
- self._deep_memory_profile_proc.wait()
- self._deep_memory_profile_proc = None
- if self._deep_memory_profile_json_file:
- self._deep_memory_profile_last_json_filename = (
- self._deep_memory_profile_json_file.name)
- self._deep_memory_profile_json_file.close()
- self._deep_memory_profile_json_file = None
-
def ExtraChromeFlags(self):
"""Ensures Chrome is launched with custom flags.
@@ -212,8 +329,8 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
"""
# The same with setUp, but need to fetch the environment variable since
# ExtraChromeFlags is called before setUp.
- deep_memory_profile = self._GetDeepMemoryProfileEnv(
- 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
+ deep_memory_profile = DeepMemoryProfiler.GetEnvironmentVariable(
+ 'DEEP_MEMORY_PROFILE', bool, DeepMemoryProfiler.DEEP_MEMORY_PROFILE)
# Ensure Chrome enables remote debugging on port 9222. This is required to
# interact with Chrome's remote inspector.
@@ -268,7 +385,7 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._num_errors = 0
self._test_start_time = time.time()
last_perf_stats_time = time.time()
- if self._deep_memory_profile:
+ if self._dmprof:
self.HeapProfilerDump('renderer', 'Chrome Endure (first)')
self._GetPerformanceStats(
webapp_name, test_description, tab_title_substring)
@@ -287,7 +404,7 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
last_perf_stats_time = time.time()
- if self._deep_memory_profile:
+ if self._dmprof:
self.HeapProfilerDump('renderer', 'Chrome Endure')
self._GetPerformanceStats(
webapp_name, test_description, tab_title_substring)
@@ -317,7 +434,7 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._remote_inspector_client.StopTimelineEventMonitoring()
- if self._deep_memory_profile:
+ if self._dmprof:
self.HeapProfilerDump('renderer', 'Chrome Endure (last)')
self._GetPerformanceStats(
webapp_name, test_description, tab_title_substring, is_last=True)
@@ -398,53 +515,8 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
memory_counts = self._remote_inspector_client.GetMemoryObjectCounts()
proc_info = self._GetProcessInfo(tab_title_substring)
- # Run Deep Memory Profiler in background.
- if self._deep_memory_profile:
- 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:
- logging.info(' Waiting for the last dmprof.')
- self._WaitForDeepMemoryProfiler()
-
- 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_file:
- self._deep_memory_profile_last_json_filename = (
- self._deep_memory_profile_json_file.name)
- self._deep_memory_profile_json_file.close()
- self._deep_memory_profile_json_file = 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_file = 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' % (self._DMPROF_SCRIPT_PATH,
- os.path.join(self._deep_tempdir, first_dump)),
- shell=True, stdout=self._deep_memory_profile_json_file)
- # Don't wait for the new process since dmprof may take long time.
-
- if is_last:
- self._WaitForDeepMemoryProfiler()
-
- else:
- logging.info(' No dump files.')
+ if self._dmprof:
+ self._dmprof.StartProfiler(proc_info, is_last)
# DOM node count.
dom_node_count = memory_counts['DOMNodeCount']
@@ -490,27 +562,9 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description),
units_x='seconds')
- # Deep Memory Profiler result.
- if self._deep_memory_profile:
- 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':
- deep_memory_profile_results = json_data['snapshots']
- elif json_data['version'] == 'JSON_DEEP_2':
- deep_memory_profile_results = json_data['policies']['l0']['snapshots']
- if deep_memory_profile_results:
- self._OutputPerfGraphValue(
- 'DMP-TCMallocUsed', [
- (snapshot['second'], snapshot['tc-used-all'] / 1024.0)
- for snapshot in deep_memory_profile_results],
- 'KB',
- graph_name='%s%s-DMP-TCUsed' % (webapp_name, test_description),
- units_x='seconds')
- # TODO(dmikurube): Output graph values (for multi-lined graphs), here.
- # 'deep_memory_profile_results' is the value to be output.
+ if self._dmprof:
+ self._dmprof.ParseResultAndOutputPerfGraphValues(
+ webapp_name, test_description, self._OutputPerfGraphValue)
logging.info(' Total DOM node count: %d nodes' % dom_node_count)
logging.info(' Event listener count: %d listeners' % event_listener_count)
« 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