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) { | |
| 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) { | |
|
nasko
2013/06/11 20:16:37
nit: Shouldn't the increment part of the loop be o
Charlie Reis
2013/06/11 21:36:39
No, this looks like a common pattern. You only ne
| |
| 407 // Skip about:blank, since we won't usually give it its own process. | |
| 408 if (iter->is_empty()) | |
|
nasko
2013/06/11 20:16:37
Is "about:blank" an actual empty GURL? I thought w
Charlie Reis
2013/06/11 21:36:39
It comes from GetSiteForURL, which has the comment
| |
| 409 continue; | |
| 410 | |
| 411 // Make sure we don't overcount process-per-site sites, like the NTP. | |
| 412 if (RenderProcessHost::ShouldUseProcessPerSite(browser_context, *iter) && | |
| 413 site_data->sites.find(*iter) != site_data->sites.end()) { | |
| 414 continue; | |
| 415 } | |
| 416 | |
| 417 site_data->sites.insert(*iter); | |
| 418 site_data->instance_site_map[primary->GetId()].insert(*iter); | |
| 419 | |
| 420 // Also keep track of how things would look if we only isolated HTTPS sites. | |
| 421 // In this model, all HTTP sites are grouped into one "http://" site. HTTPS | |
| 422 // and other schemes (e.g., chrome:) are still isolated. | |
| 423 GURL https_site = iter->SchemeIs("http") ? GURL("http://") : *iter; | |
| 424 site_data->https_sites.insert(https_site); | |
| 425 site_data->instance_https_site_map[primary->GetId()].insert(https_site); | |
| 426 } | |
| 427 } | |
| 428 | |
| 370 void MemoryDetails::UpdateHistograms() { | 429 void MemoryDetails::UpdateHistograms() { |
| 371 // Reports a set of memory metrics to UMA. | 430 // Reports a set of memory metrics to UMA. |
| 372 // Memory is measured in KB. | 431 // Memory is measured in KB. |
| 373 | 432 |
| 374 const ProcessData& browser = *ChromeBrowser(); | 433 const ProcessData& browser = *ChromeBrowser(); |
| 375 size_t aggregate_memory = 0; | 434 size_t aggregate_memory = 0; |
| 376 int chrome_count = 0; | 435 int chrome_count = 0; |
| 377 int extension_count = 0; | 436 int extension_count = 0; |
| 378 int plugin_count = 0; | 437 int plugin_count = 0; |
| 379 int pepper_plugin_count = 0; | 438 int pepper_plugin_count = 0; |
| 380 int pepper_plugin_broker_count = 0; | 439 int pepper_plugin_broker_count = 0; |
| 381 int renderer_count = 0; | 440 int renderer_count = 0; |
| 382 int other_count = 0; | 441 int other_count = 0; |
| 383 int worker_count = 0; | 442 int worker_count = 0; |
| 443 int process_limit = RenderProcessHost::GetMaxRendererProcessCount(); | |
| 384 for (size_t index = 0; index < browser.processes.size(); index++) { | 444 for (size_t index = 0; index < browser.processes.size(); index++) { |
| 385 int sample = static_cast<int>(browser.processes[index].working_set.priv); | 445 int sample = static_cast<int>(browser.processes[index].working_set.priv); |
| 386 aggregate_memory += sample; | 446 aggregate_memory += sample; |
| 387 switch (browser.processes[index].process_type) { | 447 switch (browser.processes[index].process_type) { |
| 388 case content::PROCESS_TYPE_BROWSER: | 448 case content::PROCESS_TYPE_BROWSER: |
| 389 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); | 449 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); |
| 390 break; | 450 break; |
| 391 case content::PROCESS_TYPE_RENDERER: { | 451 case content::PROCESS_TYPE_RENDERER: { |
| 392 ProcessMemoryInformation::RendererProcessType renderer_type = | 452 ProcessMemoryInformation::RendererProcessType renderer_type = |
| 393 browser.processes[index].renderer_type; | 453 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", | 520 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore", |
| 461 RenderWidgetHost::BackingStoreMemorySize() / 1024); | 521 RenderWidgetHost::BackingStoreMemorySize() / 1024); |
| 462 #if defined(OS_CHROMEOS) | 522 #if defined(OS_CHROMEOS) |
| 463 // Chrome OS exposes system-wide graphics driver memory which has historically | 523 // Chrome OS exposes system-wide graphics driver memory which has historically |
| 464 // been a source of leak/bloat. | 524 // been a source of leak/bloat. |
| 465 base::SystemMemoryInfoKB meminfo; | 525 base::SystemMemoryInfoKB meminfo; |
| 466 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) | 526 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) |
| 467 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); | 527 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); |
| 468 #endif | 528 #endif |
| 469 | 529 |
| 530 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit); | |
| 470 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", | 531 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", |
| 471 static_cast<int>(browser.processes.size())); | 532 static_cast<int>(browser.processes.size())); |
| 472 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); | 533 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); |
| 473 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); | 534 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); |
| 474 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); | 535 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); |
| 475 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); | 536 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); |
| 476 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", | 537 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", |
| 477 pepper_plugin_count); | 538 pepper_plugin_count); |
| 478 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", | 539 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", |
| 479 pepper_plugin_broker_count); | 540 pepper_plugin_broker_count); |
| 480 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); | 541 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); |
| 481 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); | 542 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); |
| 482 // TODO(viettrungluu): Do we want separate counts for the other | 543 // TODO(viettrungluu): Do we want separate counts for the other |
| 483 // (platform-specific) process types? | 544 // (platform-specific) process types? |
| 484 | 545 |
| 485 int total_sample = static_cast<int>(aggregate_memory / 1000); | 546 int total_sample = static_cast<int>(aggregate_memory / 1000); |
| 486 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); | 547 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); |
| 548 | |
| 549 // Sum the number of sites and SiteInstances in each BrowserContext. | |
| 550 int num_sites = 0; | |
| 551 int num_https_sites = 0; | |
| 552 int num_browsing_instances = 0; | |
| 553 int num_isolated_site_instances = 0; | |
| 554 int num_isolated_https_site_instances = 0; | |
| 555 for (BrowserContextSiteDataMap::const_iterator i = browser.site_data.begin(); | |
| 556 i != browser.site_data.end(); ++i) { | |
| 557 num_sites += i->second.sites.size(); | |
| 558 num_https_sites += i->second.https_sites.size(); | |
| 559 num_browsing_instances += i->second.instance_site_map.size(); | |
| 560 for (BrowsingInstanceSiteMap::const_iterator iter = | |
| 561 i->second.instance_site_map.begin(); | |
| 562 iter != i->second.instance_site_map.end(); ++iter) { | |
| 563 num_isolated_site_instances += iter->second.size(); | |
| 564 } | |
| 565 for (BrowsingInstanceSiteMap::const_iterator iter = | |
| 566 i->second.instance_https_site_map.begin(); | |
| 567 iter != i->second.instance_https_site_map.end(); ++iter) { | |
| 568 num_isolated_https_site_instances += iter->second.size(); | |
| 569 } | |
| 570 } | |
| 571 | |
| 572 // Predict the number of processes needed when isolating all sites and when | |
| 573 // isolating only HTTPS sites. | |
| 574 int process_count_lower_bound = num_sites; | |
| 575 int process_count_upper_bound = num_sites + process_limit - 1; | |
| 576 int process_count_estimate = std::min( | |
| 577 num_isolated_site_instances, process_count_upper_bound); | |
| 578 | |
| 579 int process_count_https_lower_bound = num_https_sites; | |
| 580 int process_count_https_upper_bound = num_https_sites + process_limit - 1; | |
| 581 int process_count_https_estimate = std::min( | |
| 582 num_isolated_https_site_instances, process_count_https_upper_bound); | |
| 583 | |
| 584 // Just renderer process count: | |
| 585 int all_renderer_count = renderer_count + chrome_count + extension_count; | |
| 586 UMA_HISTOGRAM_COUNTS_100("SiteIsolation.CurrentRendererProcessCount", | |
| 587 all_renderer_count); | |
| 588 UMA_HISTOGRAM_COUNTS_100( | |
| 589 "SiteIsolation.BrowsingInstanceCount", | |
| 590 num_browsing_instances); | |
| 591 UMA_HISTOGRAM_COUNTS_100( | |
| 592 "SiteIsolation.IsolateAllSitesProcessCountNoLimit", | |
| 593 num_isolated_site_instances); | |
| 594 UMA_HISTOGRAM_COUNTS_100( | |
| 595 "SiteIsolation.IsolateAllSitesProcessCountLowerBound", | |
| 596 process_count_lower_bound); | |
| 597 UMA_HISTOGRAM_COUNTS_100( | |
| 598 "SiteIsolation.IsolateAllSitesProcessCountEstimate", | |
| 599 process_count_estimate); | |
| 600 UMA_HISTOGRAM_COUNTS_100( | |
| 601 "SiteIsolation.IsolateHttpsSitesProcessCountNoLimit", | |
| 602 num_isolated_https_site_instances); | |
| 603 UMA_HISTOGRAM_COUNTS_100( | |
| 604 "SiteIsolation.IsolateHttpsSitesProcessCountLowerBound", | |
| 605 process_count_https_lower_bound); | |
| 606 UMA_HISTOGRAM_COUNTS_100( | |
| 607 "SiteIsolation.IsolateHttpsSitesProcessCountEstimate", | |
| 608 process_count_https_estimate); | |
| 609 | |
| 610 // Total process count: | |
| 611 int non_renderer_count = browser.processes.size() - all_renderer_count; | |
| 612 UMA_HISTOGRAM_COUNTS_100( | |
| 613 "SiteIsolation.IsolateAllSitesTotalProcessCountEstimate", | |
| 614 process_count_estimate + non_renderer_count); | |
| 615 UMA_HISTOGRAM_COUNTS_100( | |
| 616 "SiteIsolation.IsolateHttpsSitesTotalProcessCountEstimate", | |
| 617 process_count_https_estimate + non_renderer_count); | |
| 487 } | 618 } |
| OLD | NEW |