OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #include "chrome/browser/memory_details.h" | 5 #include "chrome/browser/memory_details.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
8 #include "base/file_version_info.h" | 8 #include "base/file_version_info.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/process_util.h" | 10 #include "base/process_util.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "chrome/browser/browser_child_process_host.h" | 13 #include "chrome/browser/browser_child_process_host.h" |
14 #include "chrome/browser/browser_thread.h" | 14 #include "chrome/browser/browser_thread.h" |
15 #include "chrome/browser/extensions/extension_host.h" | |
15 #include "chrome/browser/renderer_host/backing_store_manager.h" | 16 #include "chrome/browser/renderer_host/backing_store_manager.h" |
16 #include "chrome/browser/renderer_host/render_process_host.h" | 17 #include "chrome/browser/renderer_host/render_process_host.h" |
17 #include "chrome/browser/renderer_host/render_view_host.h" | 18 #include "chrome/browser/renderer_host/render_view_host.h" |
18 #include "chrome/browser/tab_contents/navigation_entry.h" | 19 #include "chrome/browser/tab_contents/navigation_entry.h" |
19 #include "chrome/browser/tab_contents/tab_contents.h" | 20 #include "chrome/browser/tab_contents/tab_contents.h" |
21 #include "chrome/common/bindings_policy.h" | |
22 #include "chrome/common/extensions/extension.h" | |
20 #include "chrome/common/url_constants.h" | 23 #include "chrome/common/url_constants.h" |
21 #include "grit/chromium_strings.h" | 24 #include "grit/chromium_strings.h" |
22 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
23 | 26 |
24 #if defined(OS_LINUX) | 27 #if defined(OS_LINUX) |
25 #include "chrome/browser/zygote_host_linux.h" | 28 #include "chrome/browser/zygote_host_linux.h" |
26 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" | 29 #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" |
27 #endif | 30 #endif |
28 | 31 |
29 ProcessMemoryInformation::ProcessMemoryInformation() | 32 ProcessMemoryInformation::ProcessMemoryInformation() |
30 : pid(0), | 33 : pid(0), |
31 num_processes(0), | 34 num_processes(0), |
32 is_diagnostics(false), | 35 is_diagnostics(false), |
33 type(ChildProcessInfo::UNKNOWN_PROCESS) { | 36 type(ChildProcessInfo::UNKNOWN_PROCESS), |
37 renderer_type(ChildProcessInfo::RENDERER_UNKNOWN) { | |
34 } | 38 } |
35 | 39 |
36 ProcessMemoryInformation::~ProcessMemoryInformation() {} | 40 ProcessMemoryInformation::~ProcessMemoryInformation() {} |
37 | 41 |
38 ProcessData::ProcessData() {} | 42 ProcessData::ProcessData() {} |
39 | 43 |
40 ProcessData::ProcessData(const ProcessData& rhs) | 44 ProcessData::ProcessData(const ProcessData& rhs) |
41 : name(rhs.name), | 45 : name(rhs.name), |
42 process_name(rhs.process_name), | 46 process_name(rhs.process_name), |
43 processes(rhs.processes) { | 47 processes(rhs.processes) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 std::vector<ProcessMemoryInformation> child_info; | 87 std::vector<ProcessMemoryInformation> child_info; |
84 | 88 |
85 // Collect the list of child processes. | 89 // Collect the list of child processes. |
86 for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) { | 90 for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) { |
87 ProcessMemoryInformation info; | 91 ProcessMemoryInformation info; |
88 info.pid = base::GetProcId(iter->handle()); | 92 info.pid = base::GetProcId(iter->handle()); |
89 if (!info.pid) | 93 if (!info.pid) |
90 continue; | 94 continue; |
91 | 95 |
92 info.type = iter->type(); | 96 info.type = iter->type(); |
97 info.renderer_type = iter->renderer_type(); | |
93 info.titles.push_back(WideToUTF16Hack(iter->name())); | 98 info.titles.push_back(WideToUTF16Hack(iter->name())); |
94 child_info.push_back(info); | 99 child_info.push_back(info); |
95 } | 100 } |
96 | 101 |
97 // Now go do expensive memory lookups from the file thread. | 102 // Now go do expensive memory lookups from the file thread. |
98 BrowserThread::PostTask( | 103 BrowserThread::PostTask( |
99 BrowserThread::FILE, FROM_HERE, | 104 BrowserThread::FILE, FROM_HERE, |
100 NewRunnableMethod(this, &MemoryDetails::CollectProcessData, child_info)); | 105 NewRunnableMethod(this, &MemoryDetails::CollectProcessData, child_info)); |
101 } | 106 } |
102 | 107 |
103 void MemoryDetails::CollectChildInfoOnUIThread() { | 108 void MemoryDetails::CollectChildInfoOnUIThread() { |
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
105 | 110 |
106 #if defined(OS_LINUX) | 111 #if defined(OS_LINUX) |
107 const pid_t zygote_pid = ZygoteHost::GetInstance()->pid(); | 112 const pid_t zygote_pid = ZygoteHost::GetInstance()->pid(); |
108 const pid_t sandbox_helper_pid = RenderSandboxHostLinux::GetInstance()->pid(); | 113 const pid_t sandbox_helper_pid = RenderSandboxHostLinux::GetInstance()->pid(); |
109 #endif | 114 #endif |
110 | 115 |
111 ProcessData* const chrome_browser = ChromeBrowser(); | 116 ProcessData* const chrome_browser = ChromeBrowser(); |
112 // Get more information about the process. | 117 // Get more information about the process. |
113 for (size_t index = 0; index < chrome_browser->processes.size(); | 118 for (size_t index = 0; index < chrome_browser->processes.size(); |
114 index++) { | 119 index++) { |
115 // Check if it's a renderer, if so get the list of page titles in it and | 120 // Check if it's a renderer, if so get the list of page titles in it and |
116 // check if it's a diagnostics-related process. We skip all diagnostics | 121 // check if it's a diagnostics-related process. We skip about:memory pages. |
117 // pages (e.g. "about:xxx" URLs). Iterate the RenderProcessHosts to find | 122 // Iterate the RenderProcessHosts to find the tab contents. |
118 // the tab contents. | |
119 ProcessMemoryInformation& process = | 123 ProcessMemoryInformation& process = |
120 chrome_browser->processes[index]; | 124 chrome_browser->processes[index]; |
121 | 125 |
122 for (RenderProcessHost::iterator renderer_iter( | 126 for (RenderProcessHost::iterator renderer_iter( |
123 RenderProcessHost::AllHostsIterator()); !renderer_iter.IsAtEnd(); | 127 RenderProcessHost::AllHostsIterator()); !renderer_iter.IsAtEnd(); |
124 renderer_iter.Advance()) { | 128 renderer_iter.Advance()) { |
125 DCHECK(renderer_iter.GetCurrentValue()); | 129 RenderProcessHost* rph = renderer_iter.GetCurrentValue(); |
Mike Belshe
2010/12/24 00:50:53
nit: I have to think when I see "rph" as to what
Erik does not do reviews
2010/12/28 16:59:18
Done.
| |
130 DCHECK(rph); | |
126 // Ignore processes that don't have a connection, such as crashed tabs. | 131 // Ignore processes that don't have a connection, such as crashed tabs. |
127 if (!renderer_iter.GetCurrentValue()->HasConnection() || process.pid != | 132 if (!rph->HasConnection() || |
128 base::GetProcId(renderer_iter.GetCurrentValue()->GetHandle())) { | 133 process.pid != base::GetProcId(rph->GetHandle())) { |
129 continue; | 134 continue; |
130 } | 135 } |
131 process.type = ChildProcessInfo::RENDER_PROCESS; | 136 process.type = ChildProcessInfo::RENDER_PROCESS; |
132 // The RenderProcessHost may host multiple TabContents. Any | 137 // The RenderProcessHost may host multiple TabContents. Any |
133 // of them which contain diagnostics information make the whole | 138 // of them which contain diagnostics information make the whole |
134 // process be considered a diagnostics process. | 139 // process be considered a diagnostics process. |
135 // | 140 // |
136 // NOTE: This is a bit dangerous. We know that for now, listeners | 141 // NOTE: This is a bit dangerous. We know that for now, listeners |
137 // are always RenderWidgetHosts. But in theory, they don't | 142 // are always RenderWidgetHosts. But in theory, they don't |
138 // have to be. | 143 // have to be. |
139 RenderProcessHost::listeners_iterator iter( | 144 RenderProcessHost::listeners_iterator iter(rph->ListenersIterator()); |
140 renderer_iter.GetCurrentValue()->ListenersIterator()); | |
141 for (; !iter.IsAtEnd(); iter.Advance()) { | 145 for (; !iter.IsAtEnd(); iter.Advance()) { |
142 const RenderWidgetHost* widget = | 146 const RenderWidgetHost* widget = |
143 static_cast<const RenderWidgetHost*>(iter.GetCurrentValue()); | 147 static_cast<const RenderWidgetHost*>(iter.GetCurrentValue()); |
144 DCHECK(widget); | 148 DCHECK(widget); |
145 if (!widget || !widget->IsRenderView()) | 149 if (!widget || !widget->IsRenderView()) |
146 continue; | 150 continue; |
147 | 151 |
148 const RenderViewHost* host = static_cast<const RenderViewHost*>(widget); | 152 const RenderViewHost* host = static_cast<const RenderViewHost*>(widget); |
153 if (host->enabled_bindings() && BindingsPolicy::EXTENSION) { | |
154 process.renderer_type = ChildProcessInfo::RENDERER_EXTENSION; | |
155 } else if (host->enabled_bindings() && BindingsPolicy::DOM_UI) { | |
156 process.renderer_type = ChildProcessInfo::RENDERER_CHROME; | |
157 } else { | |
158 process.renderer_type = ChildProcessInfo::RENDERER_NORMAL; | |
159 } | |
149 TabContents* contents = NULL; | 160 TabContents* contents = NULL; |
150 if (host->delegate()) | 161 if (host->delegate()) |
151 contents = host->delegate()->GetAsTabContents(); | 162 contents = host->delegate()->GetAsTabContents(); |
152 if (!contents) | 163 if (!contents) { |
164 if (host->is_extension_process()) { | |
165 // TODO(erikkay) should we just add GetAsExtensionHost to | |
166 // TabContents? | |
167 ExtensionHost* eh = static_cast<ExtensionHost*>(host->delegate()); | |
168 std::wstring title = UTF8ToWide(eh->extension()->name()); | |
169 process.titles.push_back(title); | |
170 } else { | |
171 process.renderer_type = ChildProcessInfo::RENDERER_UNKNOWN; | |
172 } | |
153 continue; | 173 continue; |
174 } | |
175 | |
154 string16 title = contents->GetTitle(); | 176 string16 title = contents->GetTitle(); |
155 if (!title.length()) | 177 if (!title.length()) |
156 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); | 178 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); |
157 process.titles.push_back(title); | 179 process.titles.push_back(title); |
158 | 180 |
159 // We need to check the pending entry as well as the virtual_url to | 181 // We need to check the pending entry as well as the virtual_url to |
160 // see if it's an about:memory URL (we don't want to count these in the | 182 // see if it's an about:memory URL (we don't want to count these in the |
161 // total memory usage of the browser). | 183 // total memory usage of the browser). |
162 // | 184 // |
163 // When we reach here, about:memory will be the pending entry since we | 185 // When we reach here, about:memory will be the pending entry since we |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
205 | 227 |
206 OnDetailsAvailable(); | 228 OnDetailsAvailable(); |
207 } | 229 } |
208 | 230 |
209 void MemoryDetails::UpdateHistograms() { | 231 void MemoryDetails::UpdateHistograms() { |
210 // Reports a set of memory metrics to UMA. | 232 // Reports a set of memory metrics to UMA. |
211 // Memory is measured in KB. | 233 // Memory is measured in KB. |
212 | 234 |
213 const ProcessData& browser = *ChromeBrowser(); | 235 const ProcessData& browser = *ChromeBrowser(); |
214 size_t aggregate_memory = 0; | 236 size_t aggregate_memory = 0; |
237 int chrome_count = 0; | |
238 int extension_count = 0; | |
215 int plugin_count = 0; | 239 int plugin_count = 0; |
240 int renderer_count = 0; | |
241 int other_count = 0; | |
216 int worker_count = 0; | 242 int worker_count = 0; |
217 for (size_t index = 0; index < browser.processes.size(); index++) { | 243 for (size_t index = 0; index < browser.processes.size(); index++) { |
218 int sample = static_cast<int>(browser.processes[index].working_set.priv); | 244 int sample = static_cast<int>(browser.processes[index].working_set.priv); |
219 aggregate_memory += sample; | 245 aggregate_memory += sample; |
220 switch (browser.processes[index].type) { | 246 switch (browser.processes[index].type) { |
221 case ChildProcessInfo::BROWSER_PROCESS: | 247 case ChildProcessInfo::BROWSER_PROCESS: |
222 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); | 248 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); |
223 break; | 249 break; |
224 case ChildProcessInfo::RENDER_PROCESS: | 250 case ChildProcessInfo::RENDER_PROCESS: { |
225 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); | 251 ChildProcessInfo::RendererProcessType renderer_type = |
252 browser.processes[index].renderer_type; | |
253 switch (renderer_type) { | |
254 case ChildProcessInfo::RENDERER_EXTENSION: | |
255 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample); | |
256 extension_count++; | |
257 break; | |
258 case ChildProcessInfo::RENDERER_CHROME: | |
259 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); | |
260 chrome_count++; | |
261 break; | |
262 case ChildProcessInfo::RENDERER_UNKNOWN: | |
Mike Belshe
2010/12/24 00:50:53
should there be a DCHECK in the RENDERER_UNKNOWN c
Erik does not do reviews
2010/12/28 16:59:18
Done.
| |
263 case ChildProcessInfo::RENDERER_NORMAL: | |
264 default: | |
265 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); | |
266 renderer_count++; | |
267 break; | |
268 } | |
226 break; | 269 break; |
270 } | |
227 case ChildProcessInfo::PLUGIN_PROCESS: | 271 case ChildProcessInfo::PLUGIN_PROCESS: |
228 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); | 272 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); |
229 plugin_count++; | 273 plugin_count++; |
230 break; | 274 break; |
231 case ChildProcessInfo::WORKER_PROCESS: | 275 case ChildProcessInfo::WORKER_PROCESS: |
232 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample); | 276 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample); |
233 worker_count++; | 277 worker_count++; |
234 break; | 278 break; |
235 case ChildProcessInfo::UTILITY_PROCESS: | 279 case ChildProcessInfo::UTILITY_PROCESS: |
236 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); | 280 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); |
281 other_count++; | |
237 break; | 282 break; |
238 case ChildProcessInfo::ZYGOTE_PROCESS: | 283 case ChildProcessInfo::ZYGOTE_PROCESS: |
239 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); | 284 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); |
285 other_count++; | |
240 break; | 286 break; |
241 case ChildProcessInfo::SANDBOX_HELPER_PROCESS: | 287 case ChildProcessInfo::SANDBOX_HELPER_PROCESS: |
242 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); | 288 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); |
289 other_count++; | |
243 break; | 290 break; |
244 case ChildProcessInfo::NACL_LOADER_PROCESS: | 291 case ChildProcessInfo::NACL_LOADER_PROCESS: |
245 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); | 292 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); |
293 other_count++; | |
246 break; | 294 break; |
247 case ChildProcessInfo::NACL_BROKER_PROCESS: | 295 case ChildProcessInfo::NACL_BROKER_PROCESS: |
248 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); | 296 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); |
297 other_count++; | |
249 break; | 298 break; |
250 case ChildProcessInfo::GPU_PROCESS: | 299 case ChildProcessInfo::GPU_PROCESS: |
251 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); | 300 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); |
301 other_count++; | |
252 break; | 302 break; |
253 default: | 303 default: |
254 NOTREACHED(); | 304 NOTREACHED(); |
255 } | 305 } |
256 } | 306 } |
257 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", | 307 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", |
258 BackingStoreManager::MemorySize() / 1024); | 308 BackingStoreManager::MemorySize() / 1024); |
259 | 309 |
260 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", | 310 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", |
261 static_cast<int>(browser.processes.size())); | 311 static_cast<int>(browser.processes.size())); |
312 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); | |
313 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); | |
314 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); | |
262 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); | 315 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); |
316 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); | |
263 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); | 317 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); |
264 // TODO(viettrungluu): Do we want separate counts for the other | 318 // TODO(viettrungluu): Do we want separate counts for the other |
265 // (platform-specific) process types? | 319 // (platform-specific) process types? |
266 | 320 |
267 int total_sample = static_cast<int>(aggregate_memory / 1000); | 321 int total_sample = static_cast<int>(aggregate_memory / 1000); |
268 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); | 322 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); |
269 } | 323 } |
OLD | NEW |