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/message_loop/message_loop.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/nacl/common/nacl_process_type.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/common/content_constants.h"
15 #include "content/public/common/process_type.h"
17 MemoryGrowthTracker::MemoryGrowthTracker() {
20 MemoryGrowthTracker::~MemoryGrowthTracker() {
23 bool MemoryGrowthTracker::UpdateSample(base::ProcessId pid
,
26 // |sample| is memory usage in kB.
27 const base::TimeTicks current_time
= base::TimeTicks::Now();
28 std::map
<base::ProcessId
, int>::iterator found_size
= memory_sizes_
.find(pid
);
29 if (found_size
!= memory_sizes_
.end()) {
30 const int last_size
= found_size
->second
;
31 std::map
<base::ProcessId
, base::TimeTicks
>::iterator found_time
=
33 const base::TimeTicks last_time
= found_time
->second
;
34 if (last_time
< (current_time
- base::TimeDelta::FromMinutes(30))) {
35 // Note that it is undefined how division of a negative integer gets
36 // rounded. |*diff| may have a difference of 1 from the correct number
37 // if |sample| < |last_size|. We ignore it as 1 is small enough.
39 ((sample
- last_size
) * 30 / (current_time
- last_time
).InMinutes());
40 found_size
->second
= sample
;
41 found_time
->second
= current_time
;
44 // Skip if a last record is found less than 30 minutes ago.
46 // Not reporting if it's the first record for |pid|.
47 times_
[pid
] = current_time
;
48 memory_sizes_
[pid
] = sample
;
53 MetricsMemoryDetails::MetricsMemoryDetails(
54 const base::Closure
& callback
,
55 MemoryGrowthTracker
* memory_growth_tracker
)
56 : callback_(callback
), memory_growth_tracker_(memory_growth_tracker
) {
57 memory_growth_tracker_
= memory_growth_tracker
;
60 MetricsMemoryDetails::~MetricsMemoryDetails() {
63 void MetricsMemoryDetails::OnDetailsAvailable() {
65 base::MessageLoop::current()->PostTask(FROM_HERE
, callback_
);
68 void MetricsMemoryDetails::UpdateHistograms() {
69 // Reports a set of memory metrics to UMA.
70 // Memory is measured in KB.
72 const ProcessData
& browser
= *ChromeBrowser();
73 size_t aggregate_memory
= 0;
75 int extension_count
= 0;
77 int pepper_plugin_count
= 0;
78 int pepper_plugin_broker_count
= 0;
79 int renderer_count
= 0;
82 int process_limit
= content::RenderProcessHost::GetMaxRendererProcessCount();
83 for (size_t index
= 0; index
< browser
.processes
.size(); index
++) {
84 int sample
= static_cast<int>(browser
.processes
[index
].working_set
.priv
);
85 aggregate_memory
+= sample
;
86 switch (browser
.processes
[index
].process_type
) {
87 case content::PROCESS_TYPE_BROWSER
:
88 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample
);
90 case content::PROCESS_TYPE_RENDERER
: {
91 ProcessMemoryInformation::RendererProcessType renderer_type
=
92 browser
.processes
[index
].renderer_type
;
93 switch (renderer_type
) {
94 case ProcessMemoryInformation::RENDERER_EXTENSION
:
95 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample
);
98 case ProcessMemoryInformation::RENDERER_CHROME
:
99 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample
);
102 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
103 NOTREACHED() << "Unknown renderer process type.";
105 case ProcessMemoryInformation::RENDERER_NORMAL
:
107 // TODO(erikkay): Should we bother splitting out the other subtypes?
108 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample
);
110 if (memory_growth_tracker_
&&
111 memory_growth_tracker_
->UpdateSample(
112 browser
.processes
[index
].pid
, sample
, &diff
)) {
114 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff
);
116 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff
);
122 case content::PROCESS_TYPE_PLUGIN
:
123 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample
);
126 case content::PROCESS_TYPE_UTILITY
:
127 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample
);
130 case content::PROCESS_TYPE_ZYGOTE
:
131 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample
);
134 case content::PROCESS_TYPE_SANDBOX_HELPER
:
135 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample
);
138 case content::PROCESS_TYPE_GPU
:
139 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample
);
142 #if defined(ENABLE_PLUGINS)
143 case content::PROCESS_TYPE_PPAPI_PLUGIN
: {
144 const std::vector
<base::string16
>& titles
=
145 browser
.processes
[index
].titles
;
146 if (titles
.size() == 1 &&
147 titles
[0] == base::ASCIIToUTF16(content::kFlashPluginName
)) {
148 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperFlashPlugin", sample
);
150 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample
);
151 pepper_plugin_count
++;
154 case content::PROCESS_TYPE_PPAPI_BROKER
:
155 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample
);
156 pepper_plugin_broker_count
++;
159 case PROCESS_TYPE_NACL_LOADER
:
160 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample
);
163 case PROCESS_TYPE_NACL_BROKER
:
164 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample
);
172 #if defined(OS_CHROMEOS)
173 // Chrome OS exposes system-wide graphics driver memory which has historically
174 // been a source of leak/bloat.
175 base::SystemMemoryInfoKB meminfo
;
176 if (base::GetSystemMemoryInfo(&meminfo
) && meminfo
.gem_size
!= -1)
177 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo
.gem_size
/ 1024 / 1024);
180 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit
);
181 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
182 static_cast<int>(browser
.processes
.size()));
183 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count
);
184 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count
);
185 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count
);
186 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count
);
187 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount",
188 pepper_plugin_count
);
189 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount",
190 pepper_plugin_broker_count
);
191 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count
);
192 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count
);
193 // TODO(viettrungluu): Do we want separate counts for the other
194 // (platform-specific) process types?
196 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
197 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample
);
199 #if defined(OS_CHROMEOS)
200 UpdateSwapHistograms();
204 #if defined(OS_CHROMEOS)
205 void MetricsMemoryDetails::UpdateSwapHistograms() {
206 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info().num_writes
> 0);
207 if (swap_info().num_writes
== 0)
210 // Only record swap info when any swaps have happened, to give us more
211 // detail in the histograms.
212 const ProcessData
& browser
= *ChromeBrowser();
213 size_t aggregate_memory
= 0;
214 for (size_t index
= 0; index
< browser
.processes
.size(); index
++) {
215 int sample
= static_cast<int>(browser
.processes
[index
].working_set
.swapped
);
216 aggregate_memory
+= sample
;
217 switch (browser
.processes
[index
].process_type
) {
218 case content::PROCESS_TYPE_BROWSER
:
219 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample
);
221 case content::PROCESS_TYPE_RENDERER
: {
222 ProcessMemoryInformation::RendererProcessType renderer_type
=
223 browser
.processes
[index
].renderer_type
;
224 switch (renderer_type
) {
225 case ProcessMemoryInformation::RENDERER_EXTENSION
:
226 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample
);
228 case ProcessMemoryInformation::RENDERER_CHROME
:
229 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample
);
231 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
232 NOTREACHED() << "Unknown renderer process type.";
234 case ProcessMemoryInformation::RENDERER_NORMAL
:
236 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample
);
240 case content::PROCESS_TYPE_PLUGIN
:
241 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample
);
243 case content::PROCESS_TYPE_UTILITY
:
244 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample
);
246 case content::PROCESS_TYPE_ZYGOTE
:
247 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample
);
249 case content::PROCESS_TYPE_SANDBOX_HELPER
:
250 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample
);
252 case content::PROCESS_TYPE_GPU
:
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample
);
255 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
256 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample
);
258 case content::PROCESS_TYPE_PPAPI_BROKER
:
259 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample
);
261 case PROCESS_TYPE_NACL_LOADER
:
262 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample
);
264 case PROCESS_TYPE_NACL_BROKER
:
265 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample
);
273 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
274 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample
);
276 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
277 swap_info().compr_data_size
/ (1024 * 1024), 1,
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
280 swap_info().orig_data_size
/ (1024 * 1024), 1,
282 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
283 swap_info().mem_used_total
/ (1024 * 1024), 1,
285 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads", swap_info().num_reads
, 1,
287 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites", swap_info().num_writes
,
290 if (swap_info().orig_data_size
> 0 && swap_info().compr_data_size
> 0) {
291 UMA_HISTOGRAM_CUSTOM_COUNTS(
292 "Memory.Swap.CompressionRatio",
293 swap_info().orig_data_size
/ swap_info().compr_data_size
, 1, 20, 20);
296 #endif // defined(OS_CHROMEOS)