Chromium Code Reviews| 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 |