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(); |
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 RenderViewHostDelegate* host_delegate = host->delegate(); | |
154 GURL url = host_delegate->GetURL(); | |
155 ViewType::Type type = host_delegate->GetRenderViewType(); | |
156 if (host->enabled_bindings() & BindingsPolicy::DOM_UI) { | |
157 // TODO(erikkay) the type for devtools doesn't actually appear to | |
158 // be set. | |
159 if (type == ViewType::DEV_TOOLS_UI) | |
160 process.renderer_type = ChildProcessInfo::RENDERER_DEVTOOLS; | |
161 else | |
162 process.renderer_type = ChildProcessInfo::RENDERER_CHROME; | |
163 } else if (host->enabled_bindings() & BindingsPolicy::EXTENSION) { | |
164 process.renderer_type = ChildProcessInfo::RENDERER_EXTENSION; | |
165 } | |
149 TabContents* contents = NULL; | 166 TabContents* contents = NULL; |
150 if (host->delegate()) | 167 if (host_delegate) |
151 contents = host->delegate()->GetAsTabContents(); | 168 contents = host_delegate->GetAsTabContents(); |
152 if (!contents) | 169 if (!contents) { |
170 if (host->is_extension_process()) { | |
171 // TODO(erikkay) should we just add GetAsExtensionHost to | |
172 // TabContents? | |
173 ExtensionHost* eh = static_cast<ExtensionHost*>(host_delegate); | |
174 string16 title = UTF8ToUTF16(eh->extension()->name()); | |
175 process.titles.push_back(title); | |
176 } else if (process.renderer_type == | |
177 ChildProcessInfo::RENDERER_UNKNOWN) { | |
178 switch (type) { | |
179 case ViewType::BACKGROUND_CONTENTS: | |
180 process.renderer_type = | |
181 ChildProcessInfo::RENDERER_BACKGROUND_APP; | |
182 break; | |
183 case ViewType::INTERSTITIAL_PAGE: | |
184 process.renderer_type = ChildProcessInfo::RENDERER_INTERSTITIAL; | |
185 process.titles.push_back(UTF8ToUTF16(url.spec())); | |
186 break; | |
187 case ViewType::NOTIFICATION: | |
188 process.renderer_type = ChildProcessInfo::RENDERER_NOTIFICATION; | |
189 break; | |
190 default: | |
191 process.renderer_type = ChildProcessInfo::RENDERER_UNKNOWN; | |
192 break; | |
193 } | |
194 } | |
153 continue; | 195 continue; |
196 } | |
197 | |
198 if (process.renderer_type == ChildProcessInfo::RENDERER_UNKNOWN) | |
asargent_no_longer_on_chrome
2010/12/25 05:20:12
It's not obvious why you're converting unknown ren
Erik does not do reviews
2010/12/28 16:59:18
I added a comment.
| |
199 process.renderer_type = ChildProcessInfo::RENDERER_NORMAL; | |
200 | |
154 string16 title = contents->GetTitle(); | 201 string16 title = contents->GetTitle(); |
155 if (!title.length()) | 202 if (!title.length()) |
156 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); | 203 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); |
157 process.titles.push_back(title); | 204 process.titles.push_back(title); |
158 | 205 |
159 // We need to check the pending entry as well as the virtual_url to | 206 // 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 | 207 // see if it's an about:memory URL (we don't want to count these in the |
161 // total memory usage of the browser). | 208 // total memory usage of the browser). |
162 // | 209 // |
163 // When we reach here, about:memory will be the pending entry since we | 210 // 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 | 252 |
206 OnDetailsAvailable(); | 253 OnDetailsAvailable(); |
207 } | 254 } |
208 | 255 |
209 void MemoryDetails::UpdateHistograms() { | 256 void MemoryDetails::UpdateHistograms() { |
210 // Reports a set of memory metrics to UMA. | 257 // Reports a set of memory metrics to UMA. |
211 // Memory is measured in KB. | 258 // Memory is measured in KB. |
212 | 259 |
213 const ProcessData& browser = *ChromeBrowser(); | 260 const ProcessData& browser = *ChromeBrowser(); |
214 size_t aggregate_memory = 0; | 261 size_t aggregate_memory = 0; |
262 int chrome_count = 0; | |
263 int extension_count = 0; | |
215 int plugin_count = 0; | 264 int plugin_count = 0; |
265 int renderer_count = 0; | |
266 int other_count = 0; | |
216 int worker_count = 0; | 267 int worker_count = 0; |
217 for (size_t index = 0; index < browser.processes.size(); index++) { | 268 for (size_t index = 0; index < browser.processes.size(); index++) { |
218 int sample = static_cast<int>(browser.processes[index].working_set.priv); | 269 int sample = static_cast<int>(browser.processes[index].working_set.priv); |
219 aggregate_memory += sample; | 270 aggregate_memory += sample; |
220 switch (browser.processes[index].type) { | 271 switch (browser.processes[index].type) { |
221 case ChildProcessInfo::BROWSER_PROCESS: | 272 case ChildProcessInfo::BROWSER_PROCESS: |
222 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); | 273 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); |
223 break; | 274 break; |
224 case ChildProcessInfo::RENDER_PROCESS: | 275 case ChildProcessInfo::RENDER_PROCESS: { |
225 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); | 276 ChildProcessInfo::RendererProcessType renderer_type = |
277 browser.processes[index].renderer_type; | |
278 switch (renderer_type) { | |
279 case ChildProcessInfo::RENDERER_EXTENSION: | |
280 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample); | |
281 extension_count++; | |
282 break; | |
283 case ChildProcessInfo::RENDERER_CHROME: | |
284 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); | |
285 chrome_count++; | |
286 break; | |
287 case ChildProcessInfo::RENDERER_NORMAL: | |
288 default: | |
289 // TODO(erikkay): Should we bother splitting out the other subtypes? | |
290 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); | |
291 renderer_count++; | |
292 break; | |
293 } | |
226 break; | 294 break; |
295 } | |
227 case ChildProcessInfo::PLUGIN_PROCESS: | 296 case ChildProcessInfo::PLUGIN_PROCESS: |
228 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); | 297 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); |
229 plugin_count++; | 298 plugin_count++; |
230 break; | 299 break; |
231 case ChildProcessInfo::WORKER_PROCESS: | 300 case ChildProcessInfo::WORKER_PROCESS: |
232 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample); | 301 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample); |
233 worker_count++; | 302 worker_count++; |
234 break; | 303 break; |
235 case ChildProcessInfo::UTILITY_PROCESS: | 304 case ChildProcessInfo::UTILITY_PROCESS: |
236 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); | 305 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); |
306 other_count++; | |
237 break; | 307 break; |
238 case ChildProcessInfo::ZYGOTE_PROCESS: | 308 case ChildProcessInfo::ZYGOTE_PROCESS: |
239 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); | 309 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); |
310 other_count++; | |
240 break; | 311 break; |
241 case ChildProcessInfo::SANDBOX_HELPER_PROCESS: | 312 case ChildProcessInfo::SANDBOX_HELPER_PROCESS: |
242 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); | 313 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); |
314 other_count++; | |
243 break; | 315 break; |
244 case ChildProcessInfo::NACL_LOADER_PROCESS: | 316 case ChildProcessInfo::NACL_LOADER_PROCESS: |
245 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); | 317 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); |
318 other_count++; | |
246 break; | 319 break; |
247 case ChildProcessInfo::NACL_BROKER_PROCESS: | 320 case ChildProcessInfo::NACL_BROKER_PROCESS: |
248 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); | 321 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); |
322 other_count++; | |
249 break; | 323 break; |
250 case ChildProcessInfo::GPU_PROCESS: | 324 case ChildProcessInfo::GPU_PROCESS: |
251 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); | 325 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); |
326 other_count++; | |
252 break; | 327 break; |
253 default: | 328 default: |
254 NOTREACHED(); | 329 NOTREACHED(); |
255 } | 330 } |
256 } | 331 } |
257 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", | 332 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", |
258 BackingStoreManager::MemorySize() / 1024); | 333 BackingStoreManager::MemorySize() / 1024); |
259 | 334 |
260 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", | 335 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", |
261 static_cast<int>(browser.processes.size())); | 336 static_cast<int>(browser.processes.size())); |
337 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); | |
338 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); | |
339 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); | |
262 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); | 340 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); |
341 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); | |
263 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); | 342 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); |
264 // TODO(viettrungluu): Do we want separate counts for the other | 343 // TODO(viettrungluu): Do we want separate counts for the other |
265 // (platform-specific) process types? | 344 // (platform-specific) process types? |
266 | 345 |
267 int total_sample = static_cast<int>(aggregate_memory / 1000); | 346 int total_sample = static_cast<int>(aggregate_memory / 1000); |
268 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); | 347 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); |
269 } | 348 } |
OLD | NEW |