cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / tools / perf / metrics / memory.py
blobc270e3c344d244caca54898388d6ec1e7040f83b
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import logging
6 import sys
8 from telemetry.value import histogram
9 from telemetry.value import histogram_util
10 from telemetry.value import scalar
12 from metrics import Metric
15 _HISTOGRAMS = [
17 'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent',
18 'display_name': 'V8_MemoryExternalFragmentationTotal',
19 'type': histogram_util.RENDERER_HISTOGRAM,
20 'description': 'Total external memory fragmentation after each GC in '
21 'percent.',
24 'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb',
25 'display_name': 'V8_MemoryHeapSampleTotalCommitted',
26 'type': histogram_util.RENDERER_HISTOGRAM,
27 'description': 'The total size of committed memory used by V8 after '
28 'each GC in KB.'
31 'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb',
32 'display_name': 'V8_MemoryHeapSampleTotalUsed',
33 'type': histogram_util.RENDERER_HISTOGRAM,
34 'description': 'The total size of live memory used by V8 after each '
35 'GC in KB.',
38 'name': 'V8.MemoryHeapSampleMaximumCommitted', 'units': 'kb',
39 'display_name': 'V8_MemoryHeapSampleMaximumCommitted',
40 'type': histogram_util.RENDERER_HISTOGRAM
43 'name': 'Memory.RendererUsed', 'units': 'kb',
44 'display_name': 'Memory_RendererUsed',
45 'type': histogram_util.RENDERER_HISTOGRAM
48 'name': 'Memory.BrowserUsed', 'units': 'kb',
49 'display_name': 'Memory_BrowserUsed',
50 'type': histogram_util.BROWSER_HISTOGRAM
54 class MemoryMetric(Metric):
55 """MemoryMetric gathers memory statistics from the browser object.
57 This includes both per-page histogram stats, most about javascript
58 memory usage, and overall memory stats from the system for the whole
59 test run."""
61 def __init__(self, browser):
62 super(MemoryMetric, self).__init__()
63 self._browser = browser
64 start_memory_stats = self._browser.memory_stats
65 self._start_commit_charge = None
66 if 'SystemCommitCharge' in start_memory_stats:
67 self._start_commit_charge = start_memory_stats['SystemCommitCharge']
68 self._memory_stats = None
69 self._histogram_start = dict()
70 self._histogram_delta = dict()
71 self._started = False
73 @classmethod
74 def CustomizeBrowserOptions(cls, options):
75 options.AppendExtraBrowserArgs([
76 '--enable-stats-collection-bindings',
77 # For a hard-coded set of Google pages (such as GMail), we produce
78 # custom memory histograms (V8.Something_gmail) instead of the generic
79 # histograms (V8.Something), if we detect that a renderer is only
80 # rendering this page and no other pages. For this test, we need to
81 # disable histogram customizing, so that we get the same generic
82 # histograms produced for all pages.
83 '--disable-histogram-customizer'
86 def Start(self, page, tab):
87 """Start the per-page preparation for this metric.
89 Here, this consists of recording the start value of all the histograms.
90 """
91 if not self._browser.supports_memory_metrics:
92 logging.warning('Memory metrics not supported.')
93 return
95 self._started = True
97 for h in _HISTOGRAMS:
98 histogram_data = histogram_util.GetHistogram(
99 h['type'], h['name'], tab)
100 # Histogram data may not be available
101 if not histogram_data:
102 continue
103 self._histogram_start[h['name']] = histogram_data
105 def Stop(self, page, tab):
106 """Prepare the results for this page.
108 The results are the differences between the current histogram values
109 and the values when Start() was called.
111 if not self._browser.supports_memory_metrics:
112 return
114 assert self._started, 'Must call Start() first'
115 for h in _HISTOGRAMS:
116 # Histogram data may not be available
117 if h['name'] not in self._histogram_start:
118 continue
119 histogram_data = histogram_util.GetHistogram(
120 h['type'], h['name'], tab)
121 self._histogram_delta[h['name']] = histogram_util.SubtractHistogram(
122 histogram_data, self._histogram_start[h['name']])
124 # Optional argument trace_name is not in base class Metric.
125 # pylint: disable=W0221
126 def AddResults(self, tab, results, trace_name=None):
127 """Add results for this page to the results object."""
128 if not self._browser.supports_memory_metrics:
129 return
131 assert self._histogram_delta, 'Must call Stop() first'
132 for h in _HISTOGRAMS:
133 # Histogram data may not be available
134 if h['name'] not in self._histogram_start:
135 continue
136 results.AddValue(histogram.HistogramValue(
137 results.current_page, h['display_name'], h['units'],
138 raw_value_json=self._histogram_delta[h['name']], important=False,
139 description=h.get('description')))
140 self._memory_stats = self._browser.memory_stats
141 if not self._memory_stats['Browser']:
142 return
143 AddResultsForProcesses(results, self._memory_stats,
144 metric_trace_name=trace_name)
146 if self._start_commit_charge:
147 end_commit_charge = self._memory_stats['SystemCommitCharge']
148 commit_charge_difference = end_commit_charge - self._start_commit_charge
149 results.AddValue(scalar.ScalarValue(
150 results.current_page,
151 'commit_charge.' + (trace_name or 'commit_charge'),
152 'kb', commit_charge_difference, important=False,
153 description='System commit charge (committed memory pages).'))
154 results.AddValue(scalar.ScalarValue(
155 results.current_page, 'processes.' + (trace_name or 'processes'),
156 'count', self._memory_stats['ProcessCount'], important=False,
157 description='Number of processes used by Chrome.'))
160 def AddResultsForProcesses(results, memory_stats, chart_trace_name='final',
161 metric_trace_name=None,
162 exclude_metrics=None):
163 """Adds memory stats for browser, renderer and gpu processes.
165 Args:
166 results: A telemetry.results.PageTestResults object.
167 memory_stats: System memory stats collected.
168 chart_trace_name: Trace to identify memory metrics. Default is 'final'.
169 metric_trace_name: Trace to identify the metric results per test page.
170 exclude_metrics: List of memory metrics to exclude from results,
171 e.g. VM, WorkingSetSize, etc.
173 metric = 'resident_set_size'
174 if sys.platform == 'win32':
175 metric = 'working_set'
177 exclude_metrics = exclude_metrics or {}
179 def AddResultsForProcessTypes(process_types_memory, process_type_trace):
180 """Add all results for a given set of process types.
182 Args:
183 process_types_memory: A list of process types, e.g. Browser, 'Renderer'.
184 process_type_trace: The name of this set of process types in the output.
186 def AddResult(value_name_memory, value_name_trace, description):
187 """Add a result for a given statistic.
189 Args:
190 value_name_memory: Name of some statistic, e.g. VM, WorkingSetSize.
191 value_name_trace: Name of this statistic to be used in the output.
193 if value_name_memory in exclude_metrics:
194 return
195 if len(process_types_memory) > 1 and value_name_memory.endswith('Peak'):
196 return
197 values = []
198 for process_type_memory in process_types_memory:
199 stats = memory_stats[process_type_memory]
200 if value_name_memory in stats:
201 values.append(stats[value_name_memory])
202 if values:
203 if metric_trace_name:
204 current_trace = '%s_%s' % (metric_trace_name, process_type_trace)
205 chart_name = value_name_trace
206 else:
207 current_trace = '%s_%s' % (value_name_trace, process_type_trace)
208 chart_name = current_trace
209 results.AddValue(scalar.ScalarValue(
210 results.current_page, '%s.%s' % (chart_name, current_trace), 'kb',
211 sum(values) / 1024, important=False, description=description))
213 AddResult('VM', 'vm_%s_size' % chart_trace_name,
214 'Virtual Memory Size (address space allocated).')
215 AddResult('WorkingSetSize', 'vm_%s_%s_size' % (metric, chart_trace_name),
216 'Working Set Size (Windows) or Resident Set Size (other '
217 'platforms).')
218 AddResult('PrivateDirty', 'vm_private_dirty_%s' % chart_trace_name,
219 'Private Dirty is basically the amount of RAM inside the '
220 'process that can not be paged to disk (it is not backed by the '
221 'same data on disk), and is not shared with any other '
222 'processes. Another way to look at this is the RAM that will '
223 'become available to the system when that process goes away '
224 '(and probably quickly subsumed into caches and other uses of '
225 'it).')
226 AddResult('ProportionalSetSize',
227 'vm_proportional_set_size_%s' % chart_trace_name,
228 'The Proportional Set Size (PSS) number is a metric the kernel '
229 'computes that takes into account memory sharing -- basically '
230 'each page of RAM in a process is scaled by a ratio of the '
231 'number of other processes also using that page. This way you '
232 'can (in theory) add up the PSS across all processes to see '
233 'the total RAM they are using, and compare PSS between '
234 'processes to get a rough idea of their relative weight.')
235 AddResult('SharedDirty', 'vm_shared_dirty_%s' % chart_trace_name,
236 'Shared Dirty is the amount of RAM outside the process that can '
237 'not be paged to disk, and is shared with other processes.')
238 AddResult('VMPeak', 'vm_peak_size',
239 'The peak Virtual Memory Size (address space allocated) usage '
240 'achieved by the * process.')
241 AddResult('WorkingSetSizePeak', '%s_peak_size' % metric,
242 'Peak Working Set Size.')
244 AddResultsForProcessTypes(['Browser'], 'browser')
245 AddResultsForProcessTypes(['Renderer'], 'renderer')
246 AddResultsForProcessTypes(['Gpu'], 'gpu')
247 AddResultsForProcessTypes(['Browser', 'Renderer', 'Gpu'], 'total')