1 // Copyright 2015 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 #include "chrome/browser/metrics/metrics_memory_details.h"
9 #include "base/location.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "components/nacl/common/nacl_process_type.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/common/content_constants.h"
17 #include "content/public/common/process_type.h"
19 MemoryGrowthTracker::MemoryGrowthTracker() {
22 MemoryGrowthTracker::~MemoryGrowthTracker() {
25 bool MemoryGrowthTracker::UpdateSample(base::ProcessId pid
,
28 // |sample| is memory usage in kB.
29 const base::TimeTicks current_time
= base::TimeTicks::Now();
30 std::map
<base::ProcessId
, int>::iterator found_size
= memory_sizes_
.find(pid
);
31 if (found_size
!= memory_sizes_
.end()) {
32 const int last_size
= found_size
->second
;
33 std::map
<base::ProcessId
, base::TimeTicks
>::iterator found_time
=
35 const base::TimeTicks last_time
= found_time
->second
;
36 if (last_time
< (current_time
- base::TimeDelta::FromMinutes(30))) {
37 // Note that it is undefined how division of a negative integer gets
38 // rounded. |*diff| may have a difference of 1 from the correct number
39 // if |sample| < |last_size|. We ignore it as 1 is small enough.
41 ((sample
- last_size
) * 30 / (current_time
- last_time
).InMinutes());
42 found_size
->second
= sample
;
43 found_time
->second
= current_time
;
46 // Skip if a last record is found less than 30 minutes ago.
48 // Not reporting if it's the first record for |pid|.
49 times_
[pid
] = current_time
;
50 memory_sizes_
[pid
] = sample
;
55 MetricsMemoryDetails::MetricsMemoryDetails(
56 const base::Closure
& callback
,
57 MemoryGrowthTracker
* memory_growth_tracker
)
58 : callback_(callback
), memory_growth_tracker_(memory_growth_tracker
) {
59 memory_growth_tracker_
= memory_growth_tracker
;
62 MetricsMemoryDetails::~MetricsMemoryDetails() {
65 void MetricsMemoryDetails::OnDetailsAvailable() {
67 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback_
);
70 void MetricsMemoryDetails::UpdateHistograms() {
71 // Reports a set of memory metrics to UMA.
72 // Memory is measured in KB.
74 const ProcessData
& browser
= *ChromeBrowser();
75 size_t aggregate_memory
= 0;
77 int extension_count
= 0;
79 int pepper_plugin_count
= 0;
80 int pepper_plugin_broker_count
= 0;
81 int renderer_count
= 0;
84 int process_limit
= content::RenderProcessHost::GetMaxRendererProcessCount();
85 for (size_t index
= 0; index
< browser
.processes
.size(); index
++) {
86 int sample
= static_cast<int>(browser
.processes
[index
].working_set
.priv
);
87 aggregate_memory
+= sample
;
88 switch (browser
.processes
[index
].process_type
) {
89 case content::PROCESS_TYPE_BROWSER
:
90 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample
);
92 case content::PROCESS_TYPE_RENDERER
: {
93 ProcessMemoryInformation::RendererProcessType renderer_type
=
94 browser
.processes
[index
].renderer_type
;
95 switch (renderer_type
) {
96 case ProcessMemoryInformation::RENDERER_EXTENSION
:
97 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample
);
100 case ProcessMemoryInformation::RENDERER_CHROME
:
101 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample
);
104 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
105 NOTREACHED() << "Unknown renderer process type.";
107 case ProcessMemoryInformation::RENDERER_NORMAL
:
109 // TODO(erikkay): Should we bother splitting out the other subtypes?
110 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample
);
112 if (memory_growth_tracker_
&&
113 memory_growth_tracker_
->UpdateSample(
114 browser
.processes
[index
].pid
, sample
, &diff
)) {
116 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff
);
118 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff
);
124 case content::PROCESS_TYPE_PLUGIN
:
125 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample
);
128 case content::PROCESS_TYPE_UTILITY
:
129 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample
);
132 case content::PROCESS_TYPE_ZYGOTE
:
133 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample
);
136 case content::PROCESS_TYPE_SANDBOX_HELPER
:
137 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample
);
140 case content::PROCESS_TYPE_GPU
:
141 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample
);
144 #if defined(ENABLE_PLUGINS)
145 case content::PROCESS_TYPE_PPAPI_PLUGIN
: {
146 const std::vector
<base::string16
>& titles
=
147 browser
.processes
[index
].titles
;
148 if (titles
.size() == 1 &&
149 titles
[0] == base::ASCIIToUTF16(content::kFlashPluginName
)) {
150 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperFlashPlugin", sample
);
152 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample
);
153 pepper_plugin_count
++;
156 case content::PROCESS_TYPE_PPAPI_BROKER
:
157 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample
);
158 pepper_plugin_broker_count
++;
161 case PROCESS_TYPE_NACL_LOADER
:
162 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample
);
165 case PROCESS_TYPE_NACL_BROKER
:
166 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample
);
174 #if defined(OS_CHROMEOS)
175 // Chrome OS exposes system-wide graphics driver memory which has historically
176 // been a source of leak/bloat.
177 base::SystemMemoryInfoKB meminfo
;
178 if (base::GetSystemMemoryInfo(&meminfo
) && meminfo
.gem_size
!= -1)
179 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo
.gem_size
/ 1024 / 1024);
182 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit
);
183 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
184 static_cast<int>(browser
.processes
.size()));
185 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count
);
186 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count
);
187 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count
);
188 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count
);
189 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount",
190 pepper_plugin_count
);
191 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount",
192 pepper_plugin_broker_count
);
193 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count
);
194 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count
);
195 // TODO(viettrungluu): Do we want separate counts for the other
196 // (platform-specific) process types?
198 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
199 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample
);
201 // Predict the number of processes needed when isolating all sites and when
202 // isolating only HTTPS sites.
203 int all_renderer_count
= renderer_count
+ chrome_count
+ extension_count
;
204 int non_renderer_count
= browser
.processes
.size() - all_renderer_count
;
205 DCHECK_GE(non_renderer_count
, 1);
206 SiteDetails::UpdateHistograms(browser
.site_data
, all_renderer_count
,
209 #if defined(OS_CHROMEOS)
210 UpdateSwapHistograms();
214 #if defined(OS_CHROMEOS)
215 void MetricsMemoryDetails::UpdateSwapHistograms() {
216 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info().num_writes
> 0);
217 if (swap_info().num_writes
== 0)
220 // Only record swap info when any swaps have happened, to give us more
221 // detail in the histograms.
222 const ProcessData
& browser
= *ChromeBrowser();
223 size_t aggregate_memory
= 0;
224 for (size_t index
= 0; index
< browser
.processes
.size(); index
++) {
225 int sample
= static_cast<int>(browser
.processes
[index
].working_set
.swapped
);
226 aggregate_memory
+= sample
;
227 switch (browser
.processes
[index
].process_type
) {
228 case content::PROCESS_TYPE_BROWSER
:
229 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample
);
231 case content::PROCESS_TYPE_RENDERER
: {
232 ProcessMemoryInformation::RendererProcessType renderer_type
=
233 browser
.processes
[index
].renderer_type
;
234 switch (renderer_type
) {
235 case ProcessMemoryInformation::RENDERER_EXTENSION
:
236 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample
);
238 case ProcessMemoryInformation::RENDERER_CHROME
:
239 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample
);
241 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
242 NOTREACHED() << "Unknown renderer process type.";
244 case ProcessMemoryInformation::RENDERER_NORMAL
:
246 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample
);
250 case content::PROCESS_TYPE_PLUGIN
:
251 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample
);
253 case content::PROCESS_TYPE_UTILITY
:
254 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample
);
256 case content::PROCESS_TYPE_ZYGOTE
:
257 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample
);
259 case content::PROCESS_TYPE_SANDBOX_HELPER
:
260 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample
);
262 case content::PROCESS_TYPE_GPU
:
263 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample
);
265 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
266 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample
);
268 case content::PROCESS_TYPE_PPAPI_BROKER
:
269 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample
);
271 case PROCESS_TYPE_NACL_LOADER
:
272 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample
);
274 case PROCESS_TYPE_NACL_BROKER
:
275 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample
);
283 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
284 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample
);
286 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
287 swap_info().compr_data_size
/ (1024 * 1024), 1,
289 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
290 swap_info().orig_data_size
/ (1024 * 1024), 1,
292 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
293 swap_info().mem_used_total
/ (1024 * 1024), 1,
295 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads", swap_info().num_reads
, 1,
297 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites", swap_info().num_writes
,
300 if (swap_info().orig_data_size
> 0 && swap_info().compr_data_size
> 0) {
301 UMA_HISTOGRAM_CUSTOM_COUNTS(
302 "Memory.Swap.CompressionRatio",
303 swap_info().orig_data_size
/ swap_info().compr_data_size
, 1, 20, 20);
306 #endif // defined(OS_CHROMEOS)