summaryrefslogtreecommitdiffstats
path: root/chrome/test
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/functional/perf_endure.py108
-rwxr-xr-xchrome/test/pyautolib/perf_snapshot.py92
2 files changed, 168 insertions, 32 deletions
diff --git a/chrome/test/functional/perf_endure.py b/chrome/test/functional/perf_endure.py
index 4ce65ee..eaa2fe6 100644
--- a/chrome/test/functional/perf_endure.py
+++ b/chrome/test/functional/perf_endure.py
@@ -30,7 +30,9 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
self._full_snapshot_results = []
self._snapshot_iteration = 0
self._heap_size_results = []
- self._node_count_results = []
+ self._v8_node_count_results = []
+ self._dom_node_count_results = []
+ self._event_listener_count_results = []
def ExtraChromeFlags(self):
"""Ensures Chrome is launched with custom flags.
@@ -43,18 +45,38 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
return (perf.BasePerfTest.ExtraChromeFlags(self) +
['--remote-debugging-port=9222'])
- def _TakeHeapSnapshot(self):
+ def _TakeHeapSnapshot(self, webapp_name):
"""Takes a v8 heap snapshot and outputs/stores the results.
- This function will fail the current test if no snapshot can be taken.
+ This function will fail the current test if no snapshot can be taken. A
+ snapshot stored by this function is represented by a dictionary with the
+ following format:
+ {
+ 'url': string, # URL of the webpage that was snapshotted.
+ 'timestamp': float, # Time when snapshot taken (seconds since epoch).
+ 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
+ 'total_heap_size': integer, # Total heap size (number of bytes).
+ 'total_dom_node_count': integer, # Total number of DOM nodes.
+ 'event_listener_count': integer, # Total number of event listeners.
+ }
+
+ Args:
+ webapp_name: A string name for the webapp being testing. Should not
+ include spaces. For example, 'Gmail', 'Docs', or 'Plus'.
"""
# Take the snapshot and store the associated information.
- logging.info('Taking heap snapshot...')
+ logging.info('Taking v8 heap snapshot...')
start_time = time.time()
snapshot = self._snapshotter.HeapSnapshot()
elapsed_time = time.time() - start_time
self.assertTrue(snapshot, msg='Failed to take a v8 heap snapshot.')
snapshot_info = snapshot[0]
+
+ # Collect other count information to add to the snapshot data.
+ memory_counts = self._snapshotter.GetMemoryObjectCounts()
+ snapshot_info['total_dom_node_count'] = memory_counts['DOMNodeCount']
+ snapshot_info['event_listener_count'] = memory_counts['EventListenerCount']
+
self._full_snapshot_results.append(snapshot_info)
logging.info('Snapshot taken (%.2f sec).' % elapsed_time)
@@ -66,38 +88,76 @@ class ChromeEndureBaseTest(perf.BasePerfTest):
logging.info(' Total heap size: %.2f MB' % heap_size)
self._heap_size_results.append((self._snapshot_iteration, heap_size))
- node_count = snapshot_info['total_node_count']
- logging.info(' Total node count: %d nodes' % node_count)
- self._node_count_results.append((self._snapshot_iteration, node_count))
+ v8_node_count = snapshot_info['total_v8_node_count']
+ logging.info(' Total v8 node count: %d nodes' % v8_node_count)
+ self._v8_node_count_results.append((self._snapshot_iteration,
+ v8_node_count))
+
+ dom_node_count = snapshot_info['total_dom_node_count']
+ logging.info(' Total DOM node count: %d nodes' % dom_node_count)
+ self._dom_node_count_results.append((self._snapshot_iteration,
+ dom_node_count))
+
+ event_listener_count = snapshot_info['event_listener_count']
+ logging.info(' Event listener count: %d listeners' % event_listener_count)
+ self._event_listener_count_results.append((self._snapshot_iteration,
+ event_listener_count))
+
self._snapshot_iteration += 1
# Output the results seen so far, to be graphed.
self._OutputPerfGraphValue(
- 'HeapSize', self._heap_size_results, 'MB', graph_name='Gmail-Heap',
- units_x='iteration')
+ 'HeapSize', self._heap_size_results, 'MB',
+ graph_name='%s-Heap' % webapp_name, units_x='iteration')
self._OutputPerfGraphValue(
- 'TotalNodeCount', self._node_count_results, 'nodes',
- graph_name='Gmail-Nodes', units_x='iteration')
+ 'TotalV8NodeCount', self._v8_node_count_results, 'nodes',
+ graph_name='%s-Nodes-V8' % webapp_name, units_x='iteration')
+ self._OutputPerfGraphValue(
+ 'TotalDOMNodeCount', self._dom_node_count_results, 'nodes',
+ graph_name='%s-Nodes-DOM' % webapp_name, units_x='iteration')
+ self._OutputPerfGraphValue(
+ 'EventListenerCount', self._event_listener_count_results, 'listeners',
+ graph_name='%s-EventListeners' % webapp_name, units_x='iteration')
- def _OutputFinalHeapSnapshotResults(self):
+ def _OutputFinalHeapSnapshotResults(self, webapp_name):
"""Outputs final snapshot results to be graphed at the end of a test.
Assumes that at least one snapshot was previously taken by the current test.
+
+ Args:
+ webapp_name: A string name for the webapp being testing. Should not
+ include spaces. For example, 'Gmail', 'Docs', or 'Plus'.
"""
assert len(self._full_snapshot_results) >= 1
max_heap_size = 0
- max_node_count = 0
+ max_v8_node_count = 0
+ max_dom_node_count = 0
+ max_event_listener_count = 0
for index, snapshot_info in enumerate(self._full_snapshot_results):
heap_size = snapshot_info['total_heap_size'] / (1024.0 * 1024.0)
if heap_size > max_heap_size:
max_heap_size = heap_size
- node_count = snapshot_info['total_node_count']
- if node_count > max_node_count:
- max_node_count = node_count
+ v8_node_count = snapshot_info['total_v8_node_count']
+ if v8_node_count > max_v8_node_count:
+ max_v8_node_count = v8_node_count
+ dom_node_count = snapshot_info['total_dom_node_count']
+ if dom_node_count > max_dom_node_count:
+ max_dom_node_count = dom_node_count
+ event_listener_count = snapshot_info['event_listener_count']
+ if event_listener_count > max_event_listener_count:
+ max_event_listener_count = event_listener_count
+ self._OutputPerfGraphValue(
+ 'MaxHeapSize', max_heap_size, 'MB',
+ graph_name='%s-Heap-Max' % webapp_name)
+ self._OutputPerfGraphValue(
+ 'MaxV8NodeCount', max_v8_node_count, 'nodes',
+ graph_name='%s-Nodes-V8-Max' % webapp_name)
self._OutputPerfGraphValue(
- 'HeapSize', max_heap_size, 'MB', graph_name='Gmail-Heap-Max')
+ 'MaxDOMNodeCount', max_dom_node_count, 'nodes',
+ graph_name='%s-Nodes-DOM-Max' % webapp_name)
self._OutputPerfGraphValue(
- 'TotalNodeCount', max_node_count, 'nodes', graph_name='Gmail-Nodes-Max')
+ 'MaxEventListenerCount', max_event_listener_count, 'listeners',
+ graph_name='%s-EventListeners-Max' % webapp_name)
def _GetElement(self, find_by, value):
"""Gets a WebDriver element object from the webpage DOM.
@@ -201,9 +261,9 @@ class ChromeEndureGmailTest(ChromeEndureBaseTest):
# Snapshot after the first iteration, then every 50 iterations after that.
if i % 50 == 0:
- self._TakeHeapSnapshot()
+ self._TakeHeapSnapshot('Gmail')
- self._OutputFinalHeapSnapshotResults()
+ self._OutputFinalHeapSnapshotResults('Gmail')
class ChromeEndureDocsTest(ChromeEndureBaseTest):
@@ -268,9 +328,9 @@ class ChromeEndureDocsTest(ChromeEndureBaseTest):
# Snapshot after the first iteration, then every 100 iterations after
# that.
if i % 100 == 0:
- self._TakeHeapSnapshot()
+ self._TakeHeapSnapshot('Docs')
- self._OutputFinalHeapSnapshotResults()
+ self._OutputFinalHeapSnapshotResults('Docs')
class ChromeEndurePlusTest(ChromeEndureBaseTest):
@@ -331,9 +391,9 @@ class ChromeEndurePlusTest(ChromeEndureBaseTest):
# Snapshot after the first iteration, then every 100 iterations after
# that.
if i % 100 == 0:
- self._TakeHeapSnapshot()
+ self._TakeHeapSnapshot('Plus')
- self._OutputFinalHeapSnapshotResults()
+ self._OutputFinalHeapSnapshotResults('Plus')
if __name__ == '__main__':
diff --git a/chrome/test/pyautolib/perf_snapshot.py b/chrome/test/pyautolib/perf_snapshot.py
index e27d638..577a709 100755
--- a/chrome/test/pyautolib/perf_snapshot.py
+++ b/chrome/test/pyautolib/perf_snapshot.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -82,7 +82,7 @@ class _V8HeapSnapshotParser(object):
Returns:
A dictionary containing the summarized v8 heap snapshot data:
{
- 'total_node_count': integer, # Total number of nodes in the v8 heap.
+ 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
'total_shallow_size': integer, # Total heap size, in bytes.
}
"""
@@ -162,7 +162,7 @@ class _V8HeapSnapshotParser(object):
# TODO(dennisjeffrey): Have this function also return more detailed v8
# heap snapshot data when a need for it arises (e.g., using |constructors|).
result = {}
- result['total_node_count'] = total_node_count
+ result['total_v8_node_count'] = total_node_count
result['total_shallow_size'] = total_shallow_size
return result
@@ -411,7 +411,7 @@ class _RemoteInspectorBaseThread(threading.Thread):
result handling needs to be performed.
run: Starts the thread of execution for this object. Invoked implicitly
by calling the start() method on this object. Should be overridden
- by a subclass.
+ by a subclass, and should call self._client.close() when done.
"""
def __init__(self, tab_index, verbose, show_socket_messages):
"""Initialize.
@@ -692,7 +692,7 @@ class _PerformanceSnapshotterThread(_RemoteInspectorBaseThread):
result = parser.ParseSnapshotData(raw_snapshot_data)
self._logger.debug('Time to parse data: %.2f sec',
time.time() - time_start)
- num_nodes = result['total_node_count']
+ num_nodes = result['total_v8_node_count']
total_size = result['total_shallow_size']
total_size_str = self._ConvertBytesToHumanReadableString(total_size)
timestamp = time.time()
@@ -700,7 +700,7 @@ class _PerformanceSnapshotterThread(_RemoteInspectorBaseThread):
self.collected_heap_snapshot_data.append(
{'url': self._url,
'timestamp': timestamp,
- 'total_node_count': num_nodes,
+ 'total_v8_node_count': num_nodes,
'total_heap_size': total_size,})
if self._output_file:
@@ -836,7 +836,56 @@ class _GarbageCollectThread(_RemoteInspectorBaseThread):
return
time.sleep(0.1)
self._client.close()
- return
+
+
+class _MemoryCountThread(_RemoteInspectorBaseThread):
+ """Manages communication with a remote Chrome to get memory count info."""
+
+ _MEMORY_COUNT_MESSAGES = [
+ 'Memory.getDOMNodeCount',
+ ]
+
+ def HandleReply(self, reply_dict):
+ """Processes a reply message received from the remote Chrome instance.
+
+ Args:
+ reply_dict: A dictionary object representing the reply message received
+ from the remote Chrome instance.
+ """
+ if 'result' in reply_dict and 'count' in reply_dict['result']:
+ dom_group_list = reply_dict['result']['count']
+ for dom_group in dom_group_list:
+ listener_array = dom_group['listenerCount']
+ for listener in listener_array:
+ self.event_listener_count += listener['count']
+ dom_node_array = dom_group['nodeCount']
+ for dom_element in dom_node_array:
+ self.dom_node_count += dom_element['count']
+
+ def run(self):
+ """Start _MemoryCountThread; overridden from threading.Thread."""
+ if self._killed:
+ return
+
+ self.dom_node_count = 0
+ self.event_listener_count = 0
+
+ # Prepare the request list.
+ for message in self._MEMORY_COUNT_MESSAGES:
+ self._requests.append(
+ _DevToolsSocketRequest(message, self._next_request_id))
+ self._next_request_id += 1
+
+ # Send out each request. Wait until each request is complete before sending
+ # the next request.
+ for request in self._requests:
+ self._FillInParams(request)
+ self._client.SendMessage(str(request))
+ while not request.is_complete:
+ if self._killed:
+ return
+ time.sleep(0.1)
+ self._client.close()
# TODO(dennisjeffrey): The "verbose" option used in this file should re-use
@@ -898,7 +947,7 @@ class PerformanceSnapshotter(object):
{
'url': string, # URL of the webpage that was snapshotted.
'timestamp': float, # Time when snapshot taken (seconds since epoch).
- 'total_node_count': integer, # Total number of nodes in the v8 heap.
+ 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
'total_heap_size': integer, # Total heap size (number of bytes).
}
"""
@@ -932,6 +981,33 @@ class PerformanceSnapshotter(object):
pass
gc_thread.join()
+ def GetMemoryObjectCounts(self):
+ """Retrieves memory object count information.
+
+ Returns:
+ A dictionary containing the memory object count information:
+ {
+ 'DOMNodeCount': integer, # Total number of DOM nodes.
+ 'EventListenerCount': integer, # Total number of event listeners.
+ }
+ """
+ mem_count_thread = _MemoryCountThread(self._tab_index, self._verbose,
+ self._show_socket_messages)
+ mem_count_thread.start()
+ try:
+ while asyncore.socket_map:
+ if not mem_count_thread.is_alive():
+ break
+ asyncore.loop(timeout=1, count=1)
+ except KeyboardInterrupt:
+ pass
+ mem_count_thread.join()
+ result = {
+ 'DOMNodeCount': mem_count_thread.dom_node_count,
+ 'EventListenerCount': mem_count_thread.event_listener_count,
+ }
+ return result
+
def SetInteractiveMode(self):
"""Sets the current object to take snapshots in interactive mode."""
self._interactive_mode = True