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(); |
| 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 |