OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import sys | 5 import sys |
6 | 6 |
7 from metrics import histogram_util | 7 from metrics import histogram_util |
8 from metrics import Metric | 8 from metrics import Metric |
9 from telemetry.value import histogram | 9 from telemetry.value import histogram |
10 from telemetry.value import scalar | 10 from telemetry.value import scalar |
11 | 11 |
12 | 12 |
13 _HISTOGRAMS = [ | 13 _HISTOGRAMS = [ |
14 {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent', | 14 { |
15 'display_name': 'V8_MemoryExternalFragmentationTotal', | 15 'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent', |
16 'type': histogram_util.RENDERER_HISTOGRAM}, | 16 'display_name': 'V8_MemoryExternalFragmentationTotal', |
17 {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb', | 17 'type': histogram_util.RENDERER_HISTOGRAM, |
18 'display_name': 'V8_MemoryHeapSampleTotalCommitted', | 18 'description': 'Total external memory fragmentation after each GC in ' |
19 'type': histogram_util.RENDERER_HISTOGRAM}, | 19 'percent.', |
20 {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb', | 20 }, |
21 'display_name': 'V8_MemoryHeapSampleTotalUsed', | 21 { |
22 'type': histogram_util.RENDERER_HISTOGRAM}, | 22 'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb', |
23 {'name': 'V8.MemoryHeapSampleMaximumCommitted', 'units': 'kb', | 23 'display_name': 'V8_MemoryHeapSampleTotalCommitted', |
24 'display_name': 'V8_MemoryHeapSampleMaximumCommitted', | 24 'type': histogram_util.RENDERER_HISTOGRAM, |
25 'type': histogram_util.RENDERER_HISTOGRAM}, | 25 'description': 'The total size of committed memory used by V8 after ' |
26 {'name': 'Memory.RendererUsed', 'units': 'kb', | 26 'each GC in KB.' |
27 'display_name': 'Memory_RendererUsed', | 27 }, |
28 'type': histogram_util.RENDERER_HISTOGRAM}, | 28 { |
29 {'name': 'Memory.BrowserUsed', 'units': 'kb', | 29 'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb', |
30 'display_name': 'Memory_BrowserUsed', | 30 'display_name': 'V8_MemoryHeapSampleTotalUsed', |
31 'type': histogram_util.BROWSER_HISTOGRAM}] | 31 'type': histogram_util.RENDERER_HISTOGRAM, |
| 32 'description': 'The total size of live memory used by V8 after each ' |
| 33 'GC in KB.', |
| 34 }, |
| 35 { |
| 36 'name': 'V8.MemoryHeapSampleMaximumCommitted', 'units': 'kb', |
| 37 'display_name': 'V8_MemoryHeapSampleMaximumCommitted', |
| 38 'type': histogram_util.RENDERER_HISTOGRAM |
| 39 }, |
| 40 { |
| 41 'name': 'Memory.RendererUsed', 'units': 'kb', |
| 42 'display_name': 'Memory_RendererUsed', |
| 43 'type': histogram_util.RENDERER_HISTOGRAM |
| 44 }, |
| 45 { |
| 46 'name': 'Memory.BrowserUsed', 'units': 'kb', |
| 47 'display_name': 'Memory_BrowserUsed', |
| 48 'type': histogram_util.BROWSER_HISTOGRAM |
| 49 }, |
| 50 ] |
32 | 51 |
33 class MemoryMetric(Metric): | 52 class MemoryMetric(Metric): |
34 """MemoryMetric gathers memory statistics from the browser object. | 53 """MemoryMetric gathers memory statistics from the browser object. |
35 | 54 |
36 This includes both per-page histogram stats, most about javascript | 55 This includes both per-page histogram stats, most about javascript |
37 memory usage, and overall memory stats from the system for the whole | 56 memory usage, and overall memory stats from the system for the whole |
38 test run.""" | 57 test run.""" |
39 | 58 |
40 def __init__(self, browser): | 59 def __init__(self, browser): |
41 super(MemoryMetric, self).__init__() | 60 super(MemoryMetric, self).__init__() |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 # pylint: disable=W0221 | 110 # pylint: disable=W0221 |
92 def AddResults(self, tab, results, trace_name=None): | 111 def AddResults(self, tab, results, trace_name=None): |
93 """Add results for this page to the results object.""" | 112 """Add results for this page to the results object.""" |
94 assert self._histogram_delta, 'Must call Stop() first' | 113 assert self._histogram_delta, 'Must call Stop() first' |
95 for h in _HISTOGRAMS: | 114 for h in _HISTOGRAMS: |
96 # Histogram data may not be available | 115 # Histogram data may not be available |
97 if h['name'] not in self._histogram_start: | 116 if h['name'] not in self._histogram_start: |
98 continue | 117 continue |
99 results.AddValue(histogram.HistogramValue( | 118 results.AddValue(histogram.HistogramValue( |
100 results.current_page, h['display_name'], h['units'], | 119 results.current_page, h['display_name'], h['units'], |
101 raw_value_json=self._histogram_delta[h['name']], important=False)) | 120 raw_value_json=self._histogram_delta[h['name']], important=False, |
| 121 description=h.get('description'))) |
102 self._memory_stats = self._browser.memory_stats | 122 self._memory_stats = self._browser.memory_stats |
103 if not self._memory_stats['Browser']: | 123 if not self._memory_stats['Browser']: |
104 return | 124 return |
105 AddResultsForProcesses(results, self._memory_stats, | 125 AddResultsForProcesses(results, self._memory_stats, |
106 metric_trace_name=trace_name) | 126 metric_trace_name=trace_name) |
107 | 127 |
108 end_commit_charge = self._memory_stats['SystemCommitCharge'] | 128 end_commit_charge = self._memory_stats['SystemCommitCharge'] |
109 commit_charge_difference = end_commit_charge - self._start_commit_charge | 129 commit_charge_difference = end_commit_charge - self._start_commit_charge |
110 results.AddValue(scalar.ScalarValue( | 130 results.AddValue(scalar.ScalarValue( |
111 results.current_page, | 131 results.current_page, |
112 'commit_charge.' + (trace_name or 'commit_charge'), | 132 'commit_charge.' + (trace_name or 'commit_charge'), |
113 'kb', | 133 'kb', commit_charge_difference, important=False, |
114 commit_charge_difference, important=False)) | 134 description='System commit charge (committed memory pages).')) |
115 results.AddValue(scalar.ScalarValue( | 135 results.AddValue(scalar.ScalarValue( |
116 results.current_page, | 136 results.current_page, 'processes.' + (trace_name or 'processes'), |
117 'processes.' + (trace_name or 'processes'), | 137 'count', self._memory_stats['ProcessCount'], important=False, |
118 'count', | 138 description='Number of processes used by Chrome.')) |
119 self._memory_stats['ProcessCount'], | |
120 important=False)) | |
121 | 139 |
122 | 140 |
123 def AddResultsForProcesses(results, memory_stats, chart_trace_name='final', | 141 def AddResultsForProcesses(results, memory_stats, chart_trace_name='final', |
124 metric_trace_name=None, | 142 metric_trace_name=None, |
125 exclude_metrics=None): | 143 exclude_metrics=None): |
126 """Adds memory stats for browser, renderer and gpu processes. | 144 """Adds memory stats for browser, renderer and gpu processes. |
127 | 145 |
128 Args: | 146 Args: |
129 results: A PageMeasurement results object. | 147 results: A PageMeasurement results object. |
130 memory_stats: System memory stats collected. | 148 memory_stats: System memory stats collected. |
131 chart_trace_name: Trace to identify memory metrics. Default is 'final'. | 149 chart_trace_name: Trace to identify memory metrics. Default is 'final'. |
132 metric_trace_name: Trace to identify the metric results per test page. | 150 metric_trace_name: Trace to identify the metric results per test page. |
133 exclude_metrics: List of memory metrics to exclude from results, | 151 exclude_metrics: List of memory metrics to exclude from results, |
134 e.g. VM, WorkingSetSize, etc. | 152 e.g. VM, WorkingSetSize, etc. |
135 """ | 153 """ |
136 metric = 'resident_set_size' | 154 metric = 'resident_set_size' |
137 if sys.platform == 'win32': | 155 if sys.platform == 'win32': |
138 metric = 'working_set' | 156 metric = 'working_set' |
139 | 157 |
140 exclude_metrics = exclude_metrics or {} | 158 exclude_metrics = exclude_metrics or {} |
141 | 159 |
142 def AddResultsForProcessTypes(process_types_memory, process_type_trace): | 160 def AddResultsForProcessTypes(process_types_memory, process_type_trace): |
143 """Add all results for a given set of process types. | 161 """Add all results for a given set of process types. |
144 | 162 |
145 Args: | 163 Args: |
146 process_types_memory: A list of process types, e.g. Browser, 'Renderer' | 164 process_types_memory: A list of process types, e.g. Browser, 'Renderer'. |
147 process_type_trace: The name of this set of process types in the output | 165 process_type_trace: The name of this set of process types in the output. |
148 """ | 166 """ |
149 def AddResult(value_name_memory, value_name_trace): | 167 def AddResult(value_name_memory, value_name_trace, description): |
150 """Add a result for a given statistic. | 168 """Add a result for a given statistic. |
151 | 169 |
152 Args: | 170 Args: |
153 value_name_memory: Name of some statistic, e.g. VM, WorkingSetSize | 171 value_name_memory: Name of some statistic, e.g. VM, WorkingSetSize. |
154 value_name_trace: Name of this statistic to be used in the output | 172 value_name_trace: Name of this statistic to be used in the output. |
155 """ | 173 """ |
156 if value_name_memory in exclude_metrics: | 174 if value_name_memory in exclude_metrics: |
157 return | 175 return |
158 if len(process_types_memory) > 1 and value_name_memory.endswith('Peak'): | 176 if len(process_types_memory) > 1 and value_name_memory.endswith('Peak'): |
159 return | 177 return |
160 values = [] | 178 values = [] |
161 for process_type_memory in process_types_memory: | 179 for process_type_memory in process_types_memory: |
162 stats = memory_stats[process_type_memory] | 180 stats = memory_stats[process_type_memory] |
163 if value_name_memory in stats: | 181 if value_name_memory in stats: |
164 values.append(stats[value_name_memory]) | 182 values.append(stats[value_name_memory]) |
165 if values: | 183 if values: |
166 if metric_trace_name: | 184 if metric_trace_name: |
167 current_trace = '%s_%s' % (metric_trace_name, process_type_trace) | 185 current_trace = '%s_%s' % (metric_trace_name, process_type_trace) |
168 chart_name = value_name_trace | 186 chart_name = value_name_trace |
169 else: | 187 else: |
170 current_trace = '%s_%s' % (value_name_trace, process_type_trace) | 188 current_trace = '%s_%s' % (value_name_trace, process_type_trace) |
171 chart_name = current_trace | 189 chart_name = current_trace |
172 results.AddValue(scalar.ScalarValue( | 190 results.AddValue(scalar.ScalarValue( |
173 results.current_page, '%s.%s' % (chart_name, current_trace), 'kb', | 191 results.current_page, '%s.%s' % (chart_name, current_trace), 'kb', |
174 sum(values) / 1024, important=False)) | 192 sum(values) / 1024, important=False, description=description)) |
175 | 193 |
176 AddResult('VM', 'vm_%s_size' % chart_trace_name) | 194 AddResult('VM', 'vm_%s_size' % chart_trace_name, |
177 AddResult('WorkingSetSize', 'vm_%s_%s_size' % (metric, chart_trace_name)) | 195 'Virtual Memory Size (address space allocated).') |
178 AddResult('PrivateDirty', 'vm_private_dirty_%s' % chart_trace_name) | 196 AddResult('WorkingSetSize', 'vm_%s_%s_size' % (metric, chart_trace_name), |
| 197 'Working Set Size (Windows) or Resident Set Size (other ' |
| 198 'platforms).') |
| 199 AddResult('PrivateDirty', 'vm_private_dirty_%s' % chart_trace_name, |
| 200 'Private Dirty is basically the amount of RAM inside the ' |
| 201 'process that can not be paged to disk (it is not backed by the ' |
| 202 'same data on disk), and is not shared with any other ' |
| 203 'processes. Another way to look at this is the RAM that will ' |
| 204 'become available to the system when that process goes away ' |
| 205 '(and probably quickly subsumed into caches and other uses of ' |
| 206 'it).') |
179 AddResult('ProportionalSetSize', | 207 AddResult('ProportionalSetSize', |
180 'vm_proportional_set_size_%s' % chart_trace_name) | 208 'vm_proportional_set_size_%s' % chart_trace_name, |
181 AddResult('SharedDirty', 'vm_shared_dirty_%s' % chart_trace_name) | 209 'The Proportional Set Size (PSS) number is a metric the kernel ' |
182 AddResult('VMPeak', 'vm_peak_size') | 210 'computes that takes into account memory sharing -- basically ' |
183 AddResult('WorkingSetSizePeak', '%s_peak_size' % metric) | 211 'each page of RAM in a process is scaled by a ratio of the ' |
| 212 'number of other processes also using that page. This way you ' |
| 213 'can (in theory) add up the PSS across all processes to see ' |
| 214 'the total RAM they are using, and compare PSS between ' |
| 215 'processes to get a rough idea of their relative weight.') |
| 216 AddResult('SharedDirty', 'vm_shared_dirty_%s' % chart_trace_name, |
| 217 'Shared Dirty is the amount of RAM outside the process that can ' |
| 218 'not be paged to disk, and is shared with other processes.') |
| 219 AddResult('VMPeak', 'vm_peak_size', |
| 220 'The peak Virtual Memory Size (address space allocated) usage ' |
| 221 'achieved by the * process.') |
| 222 AddResult('WorkingSetSizePeak', '%s_peak_size' % metric, |
| 223 'Peak Working Set Size.') |
184 | 224 |
185 AddResultsForProcessTypes(['Browser'], 'browser') | 225 AddResultsForProcessTypes(['Browser'], 'browser') |
186 AddResultsForProcessTypes(['Renderer'], 'renderer') | 226 AddResultsForProcessTypes(['Renderer'], 'renderer') |
187 AddResultsForProcessTypes(['Gpu'], 'gpu') | 227 AddResultsForProcessTypes(['Gpu'], 'gpu') |
188 AddResultsForProcessTypes(['Browser', 'Renderer', 'Gpu'], 'total') | 228 AddResultsForProcessTypes(['Browser', 'Renderer', 'Gpu'], 'total') |
OLD | NEW |