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