Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/bind.h" | 7 #include "base/bind.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" |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 #include "ui/base/l10n/l10n_util.h" | 32 #include "ui/base/l10n/l10n_util.h" |
| 33 | 33 |
| 34 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) | 34 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 35 #include "content/public/browser/zygote_host_linux.h" | 35 #include "content/public/browser/zygote_host_linux.h" |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 using base::StringPrintf; | 38 using base::StringPrintf; |
| 39 using content::BrowserChildProcessHostIterator; | 39 using content::BrowserChildProcessHostIterator; |
| 40 using content::BrowserThread; | 40 using content::BrowserThread; |
| 41 using content::NavigationEntry; | 41 using content::NavigationEntry; |
| 42 using content::RenderProcessHost; | |
| 42 using content::RenderViewHost; | 43 using content::RenderViewHost; |
| 43 using content::RenderWidgetHost; | 44 using content::RenderWidgetHost; |
| 45 using content::SiteInstance; | |
| 44 using content::WebContents; | 46 using content::WebContents; |
| 45 using extensions::Extension; | 47 using extensions::Extension; |
| 46 | 48 |
| 47 // static | 49 // static |
| 48 std::string ProcessMemoryInformation::GetRendererTypeNameInEnglish( | 50 std::string ProcessMemoryInformation::GetRendererTypeNameInEnglish( |
| 49 RendererProcessType type) { | 51 RendererProcessType type) { |
| 50 switch (type) { | 52 switch (type) { |
| 51 case RENDERER_NORMAL: | 53 case RENDERER_NORMAL: |
| 52 return "Tab"; | 54 return "Tab"; |
| 53 case RENDERER_CHROME: | 55 case RENDERER_CHROME: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 renderer_type(RENDERER_UNKNOWN) { | 88 renderer_type(RENDERER_UNKNOWN) { |
| 87 } | 89 } |
| 88 | 90 |
| 89 ProcessMemoryInformation::~ProcessMemoryInformation() {} | 91 ProcessMemoryInformation::~ProcessMemoryInformation() {} |
| 90 | 92 |
| 91 bool ProcessMemoryInformation::operator<( | 93 bool ProcessMemoryInformation::operator<( |
| 92 const ProcessMemoryInformation& rhs) const { | 94 const ProcessMemoryInformation& rhs) const { |
| 93 return working_set.priv < rhs.working_set.priv; | 95 return working_set.priv < rhs.working_set.priv; |
| 94 } | 96 } |
| 95 | 97 |
| 98 SiteData::SiteData() {} | |
| 99 | |
| 100 SiteData::~SiteData() {} | |
| 101 | |
| 96 ProcessData::ProcessData() {} | 102 ProcessData::ProcessData() {} |
| 97 | 103 |
| 98 ProcessData::ProcessData(const ProcessData& rhs) | 104 ProcessData::ProcessData(const ProcessData& rhs) |
| 99 : name(rhs.name), | 105 : name(rhs.name), |
| 100 process_name(rhs.process_name), | 106 process_name(rhs.process_name), |
| 101 processes(rhs.processes) { | 107 processes(rhs.processes) { |
| 102 } | 108 } |
| 103 | 109 |
| 104 ProcessData::~ProcessData() {} | 110 ProcessData::~ProcessData() {} |
| 105 | 111 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 for (; !iter.IsAtEnd(); iter.Advance()) { | 249 for (; !iter.IsAtEnd(); iter.Advance()) { |
| 244 const RenderWidgetHost* widget = iter.GetCurrentValue(); | 250 const RenderWidgetHost* widget = iter.GetCurrentValue(); |
| 245 DCHECK(widget); | 251 DCHECK(widget); |
| 246 if (!widget || !widget->IsRenderView()) | 252 if (!widget || !widget->IsRenderView()) |
| 247 continue; | 253 continue; |
| 248 | 254 |
| 249 RenderViewHost* host = | 255 RenderViewHost* host = |
| 250 RenderViewHost::From(const_cast<RenderWidgetHost*>(widget)); | 256 RenderViewHost::From(const_cast<RenderWidgetHost*>(widget)); |
| 251 WebContents* contents = WebContents::FromRenderViewHost(host); | 257 WebContents* contents = WebContents::FromRenderViewHost(host); |
| 252 GURL url; | 258 GURL url; |
| 253 if (contents) | 259 if (contents) { |
| 254 url = contents->GetURL(); | 260 url = contents->GetURL(); |
| 261 CollectSiteInfo(contents); | |
| 262 } | |
| 255 extensions::ViewType type = extensions::GetViewType(contents); | 263 extensions::ViewType type = extensions::GetViewType(contents); |
| 256 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) { | 264 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) { |
| 257 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; | 265 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; |
| 258 } else if (extension_process_map && | 266 } else if (extension_process_map && |
| 259 extension_process_map->Contains(host->GetProcess()->GetID())) { | 267 extension_process_map->Contains(host->GetProcess()->GetID())) { |
| 260 // For our purposes, don't count processes containing only hosted apps | 268 // For our purposes, don't count processes containing only hosted apps |
| 261 // as extension processes. See also: crbug.com/102533. | 269 // as extension processes. See also: crbug.com/102533. |
| 262 std::set<std::string> extension_ids = | 270 std::set<std::string> extension_ids = |
| 263 extension_process_map->GetExtensionsInProcess( | 271 extension_process_map->GetExtensionsInProcess( |
| 264 host->GetProcess()->GetID()); | 272 host->GetProcess()->GetID()); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 360 index--; | 368 index--; |
| 361 } | 369 } |
| 362 } | 370 } |
| 363 | 371 |
| 364 if (user_metrics_mode_ == UPDATE_USER_METRICS) | 372 if (user_metrics_mode_ == UPDATE_USER_METRICS) |
| 365 UpdateHistograms(); | 373 UpdateHistograms(); |
| 366 | 374 |
| 367 OnDetailsAvailable(); | 375 OnDetailsAvailable(); |
| 368 } | 376 } |
| 369 | 377 |
| 378 void MemoryDetails::CollectSiteInfo(WebContents* contents) { | |
|
darin (slow to review)
2013/06/12 04:40:48
nit: It is perhaps expanding the scope of this cla
Charlie Reis
2013/06/12 18:59:16
It's kind of intermediate data to report process c
| |
| 379 ProcessData* const chrome_browser = ChromeBrowser(); | |
| 380 | |
| 381 // Keep track of data for each BrowserContext separately, since tabs in | |
| 382 // different BrowserContexts can't share processes. | |
| 383 content::BrowserContext* browser_context = contents->GetBrowserContext(); | |
| 384 SiteData* site_data = &chrome_browser->site_data[browser_context]; | |
| 385 | |
| 386 // Find the BrowsingInstance this WebContents belongs to by iterating over | |
| 387 // the "primary" SiteInstances of each BrowsingInstance we've seen so far. | |
| 388 SiteInstance* instance = contents->GetSiteInstance(); | |
| 389 SiteInstance* primary = NULL; | |
| 390 for (size_t i = 0; i < site_data->instances.size(); ++i) { | |
| 391 if (instance->IsRelatedSiteInstance(site_data->instances[i])) { | |
| 392 primary = site_data->instances[i]; | |
| 393 break; | |
| 394 } | |
| 395 } | |
| 396 if (!primary) { | |
| 397 // Remember this as the "primary" SiteInstance of a new BrowsingInstance. | |
| 398 primary = instance; | |
| 399 site_data->instances.push_back(instance); | |
| 400 } | |
| 401 | |
| 402 // Now keep track of how many sites we have in this BrowsingInstance (and | |
| 403 // overall), including sites in iframes. | |
| 404 std::set<GURL> sites_in_tab = contents->GetSitesInTab(); | |
| 405 for (std::set<GURL>::iterator iter = sites_in_tab.begin(); | |
| 406 iter != sites_in_tab.end(); ++iter) { | |
| 407 // Skip about:blank, since we won't usually give it its own process. | |
| 408 // Because about:blank has no host, its site URL will be blank. | |
| 409 if (iter->is_empty()) | |
| 410 continue; | |
| 411 | |
| 412 // Make sure we don't overcount process-per-site sites, like the NTP. | |
| 413 if (RenderProcessHost::ShouldUseProcessPerSite(browser_context, *iter) && | |
| 414 site_data->sites.find(*iter) != site_data->sites.end()) { | |
| 415 continue; | |
| 416 } | |
| 417 | |
| 418 site_data->sites.insert(*iter); | |
| 419 site_data->instance_site_map[primary->GetId()].insert(*iter); | |
| 420 | |
| 421 // Also keep track of how things would look if we only isolated HTTPS sites. | |
| 422 // In this model, all HTTP sites are grouped into one "http://" site. HTTPS | |
| 423 // and other schemes (e.g., chrome:) are still isolated. | |
| 424 GURL https_site = iter->SchemeIs("http") ? GURL("http://") : *iter; | |
| 425 site_data->https_sites.insert(https_site); | |
| 426 site_data->instance_https_site_map[primary->GetId()].insert(https_site); | |
| 427 } | |
| 428 } | |
| 429 | |
| 370 void MemoryDetails::UpdateHistograms() { | 430 void MemoryDetails::UpdateHistograms() { |
| 371 // Reports a set of memory metrics to UMA. | 431 // Reports a set of memory metrics to UMA. |
| 372 // Memory is measured in KB. | 432 // Memory is measured in KB. |
| 373 | 433 |
| 374 const ProcessData& browser = *ChromeBrowser(); | 434 const ProcessData& browser = *ChromeBrowser(); |
| 375 size_t aggregate_memory = 0; | 435 size_t aggregate_memory = 0; |
| 376 int chrome_count = 0; | 436 int chrome_count = 0; |
| 377 int extension_count = 0; | 437 int extension_count = 0; |
| 378 int plugin_count = 0; | 438 int plugin_count = 0; |
| 379 int pepper_plugin_count = 0; | 439 int pepper_plugin_count = 0; |
| 380 int pepper_plugin_broker_count = 0; | 440 int pepper_plugin_broker_count = 0; |
| 381 int renderer_count = 0; | 441 int renderer_count = 0; |
| 382 int other_count = 0; | 442 int other_count = 0; |
| 383 int worker_count = 0; | 443 int worker_count = 0; |
| 444 int process_limit = RenderProcessHost::GetMaxRendererProcessCount(); | |
| 384 for (size_t index = 0; index < browser.processes.size(); index++) { | 445 for (size_t index = 0; index < browser.processes.size(); index++) { |
| 385 int sample = static_cast<int>(browser.processes[index].working_set.priv); | 446 int sample = static_cast<int>(browser.processes[index].working_set.priv); |
| 386 aggregate_memory += sample; | 447 aggregate_memory += sample; |
| 387 switch (browser.processes[index].process_type) { | 448 switch (browser.processes[index].process_type) { |
| 388 case content::PROCESS_TYPE_BROWSER: | 449 case content::PROCESS_TYPE_BROWSER: |
| 389 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); | 450 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); |
| 390 break; | 451 break; |
| 391 case content::PROCESS_TYPE_RENDERER: { | 452 case content::PROCESS_TYPE_RENDERER: { |
| 392 ProcessMemoryInformation::RendererProcessType renderer_type = | 453 ProcessMemoryInformation::RendererProcessType renderer_type = |
| 393 browser.processes[index].renderer_type; | 454 browser.processes[index].renderer_type; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 460 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", | 521 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", |
| 461 RenderWidgetHost::BackingStoreMemorySize() / 1024); | 522 RenderWidgetHost::BackingStoreMemorySize() / 1024); |
| 462 #if defined(OS_CHROMEOS) | 523 #if defined(OS_CHROMEOS) |
| 463 // Chrome OS exposes system-wide graphics driver memory which has historically | 524 // Chrome OS exposes system-wide graphics driver memory which has historically |
| 464 // been a source of leak/bloat. | 525 // been a source of leak/bloat. |
| 465 base::SystemMemoryInfoKB meminfo; | 526 base::SystemMemoryInfoKB meminfo; |
| 466 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) | 527 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) |
| 467 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); | 528 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); |
| 468 #endif | 529 #endif |
| 469 | 530 |
| 531 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit); | |
| 470 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", | 532 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", |
| 471 static_cast<int>(browser.processes.size())); | 533 static_cast<int>(browser.processes.size())); |
| 472 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); | 534 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); |
| 473 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); | 535 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); |
| 474 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); | 536 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); |
| 475 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); | 537 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); |
| 476 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", | 538 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", |
| 477 pepper_plugin_count); | 539 pepper_plugin_count); |
| 478 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", | 540 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", |
| 479 pepper_plugin_broker_count); | 541 pepper_plugin_broker_count); |
| 480 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); | 542 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); |
| 481 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); | 543 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); |
| 482 // TODO(viettrungluu): Do we want separate counts for the other | 544 // TODO(viettrungluu): Do we want separate counts for the other |
| 483 // (platform-specific) process types? | 545 // (platform-specific) process types? |
| 484 | 546 |
| 485 int total_sample = static_cast<int>(aggregate_memory / 1000); | 547 int total_sample = static_cast<int>(aggregate_memory / 1000); |
| 486 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); | 548 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); |
| 549 | |
| 550 // Sum the number of sites and SiteInstances in each BrowserContext. | |
| 551 int num_sites = 0; | |
| 552 int num_https_sites = 0; | |
| 553 int num_browsing_instances = 0; | |
| 554 int num_isolated_site_instances = 0; | |
| 555 int num_isolated_https_site_instances = 0; | |
| 556 for (BrowserContextSiteDataMap::const_iterator i = browser.site_data.begin(); | |
| 557 i != browser.site_data.end(); ++i) { | |
| 558 num_sites += i->second.sites.size(); | |
| 559 num_https_sites += i->second.https_sites.size(); | |
| 560 num_browsing_instances += i->second.instance_site_map.size(); | |
| 561 for (BrowsingInstanceSiteMap::const_iterator iter = | |
| 562 i->second.instance_site_map.begin(); | |
| 563 iter != i->second.instance_site_map.end(); ++iter) { | |
| 564 num_isolated_site_instances += iter->second.size(); | |
| 565 } | |
| 566 for (BrowsingInstanceSiteMap::const_iterator iter = | |
| 567 i->second.instance_https_site_map.begin(); | |
| 568 iter != i->second.instance_https_site_map.end(); ++iter) { | |
| 569 num_isolated_https_site_instances += iter->second.size(); | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 // Predict the number of processes needed when isolating all sites and when | |
| 574 // isolating only HTTPS sites. | |
| 575 int process_count_lower_bound = num_sites; | |
| 576 int process_count_upper_bound = num_sites + process_limit - 1; | |
| 577 int process_count_estimate = std::min( | |
| 578 num_isolated_site_instances, process_count_upper_bound); | |
| 579 | |
| 580 int process_count_https_lower_bound = num_https_sites; | |
| 581 int process_count_https_upper_bound = num_https_sites + process_limit - 1; | |
| 582 int process_count_https_estimate = std::min( | |
| 583 num_isolated_https_site_instances, process_count_https_upper_bound); | |
| 584 | |
| 585 // Just renderer process count: | |
| 586 int all_renderer_count = renderer_count + chrome_count + extension_count; | |
| 587 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.CurrentRendererProcessCount", | |
| 588 all_renderer_count); | |
| 589 UMA_HISTOGRAM_COUNTS_100( | |
| 590 "SiteIsolation.BrowsingInstanceCount", | |
| 591 num_browsing_instances); | |
| 592 UMA_HISTOGRAM_COUNTS_100( | |
| 593 "SiteIsolation.IsolateAllSitesProcessCountNoLimit", | |
| 594 num_isolated_site_instances); | |
| 595 UMA_HISTOGRAM_COUNTS_100( | |
| 596 "SiteIsolation.IsolateAllSitesProcessCountLowerBound", | |
| 597 process_count_lower_bound); | |
| 598 UMA_HISTOGRAM_COUNTS_100( | |
| 599 "SiteIsolation.IsolateAllSitesProcessCountEstimate", | |
| 600 process_count_estimate); | |
| 601 UMA_HISTOGRAM_COUNTS_100( | |
| 602 "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit", | |
| 603 num_isolated_https_site_instances); | |
| 604 UMA_HISTOGRAM_COUNTS_100( | |
| 605 "SiteIsolation.IsolateHttpsSitesProcessCountLowerBound", | |
| 606 process_count_https_lower_bound); | |
| 607 UMA_HISTOGRAM_COUNTS_100( | |
| 608 "SiteIsolation.IsolateHttpsSitesProcessCountEstimate", | |
| 609 process_count_https_estimate); | |
| 610 | |
| 611 // Total process count: | |
| 612 int non_renderer_count = browser.processes.size() - all_renderer_count; | |
| 613 UMA_HISTOGRAM_COUNTS_100( | |
| 614 "SiteIsolation.IsolateAllSitesTotalProcessCountEstimate", | |
| 615 process_count_estimate + non_renderer_count); | |
| 616 UMA_HISTOGRAM_COUNTS_100( | |
| 617 "SiteIsolation.IsolateHttpsSitesTotalProcessCountEstimate", | |
| 618 process_count_https_estimate + non_renderer_count); | |
| 487 } | 619 } |
| OLD | NEW |