OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/browser/metrics/metrics_memory_details.h" | |
6 | |
7 #include <vector> | |
8 | |
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" | |
16 | |
17 MemoryGrowthTracker::MemoryGrowthTracker() { | |
18 } | |
19 | |
20 MemoryGrowthTracker::~MemoryGrowthTracker() { | |
21 } | |
22 | |
23 bool MemoryGrowthTracker::UpdateSample(base::ProcessId pid, | |
24 int sample, | |
25 int* diff) { | |
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 = | |
32 times_.find(pid); | |
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. | |
38 *diff = | |
39 ((sample - last_size) * 30 / (current_time - last_time).InMinutes()); | |
40 found_size->second = sample; | |
41 found_time->second = current_time; | |
42 return true; | |
43 } | |
44 // Skip if a last record is found less than 30 minutes ago. | |
45 } else { | |
46 // Not reporting if it's the first record for |pid|. | |
47 times_[pid] = current_time; | |
48 memory_sizes_[pid] = sample; | |
49 } | |
50 return false; | |
51 } | |
52 | |
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; | |
58 } | |
59 | |
60 MetricsMemoryDetails::~MetricsMemoryDetails() { | |
61 } | |
62 | |
63 void MetricsMemoryDetails::OnDetailsAvailable() { | |
64 UpdateHistograms(); | |
65 base::MessageLoop::current()->PostTask(FROM_HERE, callback_); | |
66 } | |
67 | |
68 void MetricsMemoryDetails::UpdateHistograms() { | |
69 // Reports a set of memory metrics to UMA. | |
70 // Memory is measured in KB. | |
71 | |
72 const ProcessData& browser = *ChromeBrowser(); | |
73 size_t aggregate_memory = 0; | |
74 int chrome_count = 0; | |
75 int extension_count = 0; | |
76 int plugin_count = 0; | |
77 int pepper_plugin_count = 0; | |
78 int pepper_plugin_broker_count = 0; | |
79 int renderer_count = 0; | |
80 int other_count = 0; | |
81 int worker_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); | |
89 continue; | |
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); | |
96 extension_count++; | |
97 continue; | |
98 case ProcessMemoryInformation::RENDERER_CHROME: | |
99 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); | |
100 chrome_count++; | |
101 continue; | |
102 case ProcessMemoryInformation::RENDERER_UNKNOWN: | |
103 NOTREACHED() << "Unknown renderer process type."; | |
104 continue; | |
105 case ProcessMemoryInformation::RENDERER_NORMAL: | |
106 default: | |
107 // TODO(erikkay): Should we bother splitting out the other subtypes? | |
108 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); | |
109 int diff; | |
110 if (memory_growth_tracker_ && | |
111 memory_growth_tracker_->UpdateSample( | |
112 browser.processes[index].pid, sample, &diff)) { | |
113 if (diff < 0) | |
114 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff); | |
115 else | |
116 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff); | |
117 } | |
118 renderer_count++; | |
119 continue; | |
120 } | |
121 } | |
122 case content::PROCESS_TYPE_PLUGIN: | |
123 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); | |
124 plugin_count++; | |
125 continue; | |
126 case content::PROCESS_TYPE_UTILITY: | |
127 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); | |
128 other_count++; | |
129 continue; | |
130 case content::PROCESS_TYPE_ZYGOTE: | |
131 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); | |
132 other_count++; | |
133 continue; | |
134 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
135 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); | |
136 other_count++; | |
137 continue; | |
138 case content::PROCESS_TYPE_GPU: | |
139 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); | |
140 other_count++; | |
141 continue; | |
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); | |
149 } | |
150 } | |
Ilya Sherman
2015/01/16 04:57:36
nit: The placement of this curly brace looks reall
Alexei Svitkine (slow)
2015/01/16 16:07:49
Indeed - I guess clang format got confused here. F
| |
151 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample); | |
152 pepper_plugin_count++; | |
153 continue; | |
154 case content::PROCESS_TYPE_PPAPI_BROKER: | |
155 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample); | |
156 pepper_plugin_broker_count++; | |
157 continue; | |
158 #endif | |
159 case PROCESS_TYPE_NACL_LOADER: | |
160 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); | |
161 other_count++; | |
162 continue; | |
163 case PROCESS_TYPE_NACL_BROKER: | |
164 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); | |
165 other_count++; | |
166 continue; | |
167 default: | |
168 NOTREACHED(); | |
169 continue; | |
170 } | |
171 } | |
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); | |
178 #endif | |
179 | |
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? | |
195 | |
196 int total_sample = static_cast<int>(aggregate_memory / 1000); | |
197 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); | |
198 | |
199 #if defined(OS_CHROMEOS) | |
200 UpdateSwapHistograms(); | |
201 #endif | |
202 } | |
203 | |
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) | |
208 return; | |
209 | |
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); | |
220 continue; | |
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); | |
227 continue; | |
228 case ProcessMemoryInformation::RENDERER_CHROME: | |
229 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample); | |
230 continue; | |
231 case ProcessMemoryInformation::RENDERER_UNKNOWN: | |
232 NOTREACHED() << "Unknown renderer process type."; | |
233 continue; | |
234 case ProcessMemoryInformation::RENDERER_NORMAL: | |
235 default: | |
236 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample); | |
237 continue; | |
238 } | |
239 } | |
240 case content::PROCESS_TYPE_PLUGIN: | |
241 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample); | |
242 continue; | |
243 case content::PROCESS_TYPE_UTILITY: | |
244 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample); | |
245 continue; | |
246 case content::PROCESS_TYPE_ZYGOTE: | |
247 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample); | |
248 continue; | |
249 case content::PROCESS_TYPE_SANDBOX_HELPER: | |
250 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample); | |
251 continue; | |
252 case content::PROCESS_TYPE_GPU: | |
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample); | |
254 continue; | |
255 case content::PROCESS_TYPE_PPAPI_PLUGIN: | |
256 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample); | |
257 continue; | |
258 case content::PROCESS_TYPE_PPAPI_BROKER: | |
259 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample); | |
260 continue; | |
261 case PROCESS_TYPE_NACL_LOADER: | |
262 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample); | |
263 continue; | |
264 case PROCESS_TYPE_NACL_BROKER: | |
265 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample); | |
266 continue; | |
267 default: | |
268 NOTREACHED(); | |
269 continue; | |
270 } | |
271 } | |
272 | |
273 int total_sample = static_cast<int>(aggregate_memory / 1000); | |
274 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample); | |
275 | |
276 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize", | |
277 swap_info().compr_data_size / (1024 * 1024), 1, | |
278 4096, 50); | |
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize", | |
280 swap_info().orig_data_size / (1024 * 1024), 1, | |
281 4096, 50); | |
282 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal", | |
283 swap_info().mem_used_total / (1024 * 1024), 1, | |
284 4096, 50); | |
285 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads", swap_info().num_reads, 1, | |
286 100000000, 100); | |
287 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites", swap_info().num_writes, | |
288 1, 100000000, 100); | |
289 | |
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); | |
294 } | |
295 } | |
296 #endif // defined(OS_CHROMEOS) | |
OLD | NEW |