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 3// found in the LICENSE file. 4 5#include "chrome/browser/memory_details.h" 6 7#include "base/bind.h" 8#include "base/file_version_info.h" 9#include "base/metrics/histogram.h" 10#include "base/strings/string_util.h" 11#include "base/strings/stringprintf.h" 12#include "base/strings/utf_string_conversions.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/common/url_constants.h" 15#include "chrome/grit/generated_resources.h" 16#include "components/nacl/common/nacl_process_type.h" 17#include "content/public/browser/browser_child_process_host_iterator.h" 18#include "content/public/browser/browser_thread.h" 19#include "content/public/browser/child_process_data.h" 20#include "content/public/browser/navigation_controller.h" 21#include "content/public/browser/navigation_entry.h" 22#include "content/public/browser/render_process_host.h" 23#include "content/public/browser/render_view_host.h" 24#include "content/public/browser/render_widget_host_iterator.h" 25#include "content/public/browser/web_contents.h" 26#include "content/public/common/bindings_policy.h" 27#include "ui/base/l10n/l10n_util.h" 28 29#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 30#include "content/public/browser/zygote_host_linux.h" 31#endif 32 33#if defined(ENABLE_EXTENSIONS) 34#include "chrome/browser/extensions/extension_service.h" 35#include "extensions/browser/extension_system.h" 36#include "extensions/browser/process_manager.h" 37#include "extensions/browser/process_map.h" 38#include "extensions/browser/view_type_utils.h" 39#include "extensions/common/extension.h" 40#endif 41 42using base::StringPrintf; 43using content::BrowserChildProcessHostIterator; 44using content::BrowserThread; 45using content::NavigationEntry; 46using content::RenderViewHost; 47using content::RenderWidgetHost; 48using content::WebContents; 49#if defined(ENABLE_EXTENSIONS) 50using extensions::Extension; 51#endif 52 53// static 54std::string ProcessMemoryInformation::GetRendererTypeNameInEnglish( 55 RendererProcessType type) { 56 switch (type) { 57 case RENDERER_NORMAL: 58 return "Tab"; 59 case RENDERER_CHROME: 60 return "Tab (Chrome)"; 61 case RENDERER_EXTENSION: 62 return "Extension"; 63 case RENDERER_DEVTOOLS: 64 return "Devtools"; 65 case RENDERER_INTERSTITIAL: 66 return "Interstitial"; 67 case RENDERER_BACKGROUND_APP: 68 return "Background App"; 69 case RENDERER_UNKNOWN: 70 default: 71 NOTREACHED() << "Unknown renderer process type!"; 72 return "Unknown"; 73 } 74} 75 76// static 77std::string ProcessMemoryInformation::GetFullTypeNameInEnglish( 78 int process_type, 79 RendererProcessType rtype) { 80 if (process_type == content::PROCESS_TYPE_RENDERER) 81 return GetRendererTypeNameInEnglish(rtype); 82 return content::GetProcessTypeNameInEnglish(process_type); 83} 84 85ProcessMemoryInformation::ProcessMemoryInformation() 86 : pid(0), 87 num_processes(0), 88 is_diagnostics(false), 89 process_type(content::PROCESS_TYPE_UNKNOWN), 90 renderer_type(RENDERER_UNKNOWN) { 91} 92 93ProcessMemoryInformation::~ProcessMemoryInformation() {} 94 95bool ProcessMemoryInformation::operator<( 96 const ProcessMemoryInformation& rhs) const { 97 return working_set.priv < rhs.working_set.priv; 98} 99 100ProcessData::ProcessData() {} 101 102ProcessData::ProcessData(const ProcessData& rhs) 103 : name(rhs.name), 104 process_name(rhs.process_name), 105 processes(rhs.processes) { 106} 107 108ProcessData::~ProcessData() {} 109 110ProcessData& ProcessData::operator=(const ProcessData& rhs) { 111 name = rhs.name; 112 process_name = rhs.process_name; 113 processes = rhs.processes; 114 return *this; 115} 116 117MemoryGrowthTracker::MemoryGrowthTracker() {} 118 119MemoryGrowthTracker::~MemoryGrowthTracker() {} 120 121bool MemoryGrowthTracker::UpdateSample( 122 base::ProcessId pid, 123 int sample, 124 int* diff) { 125 // |sample| is memory usage in kB. 126 const base::TimeTicks current_time = base::TimeTicks::Now(); 127 std::map<base::ProcessId, int>::iterator found_size = memory_sizes_.find(pid); 128 if (found_size != memory_sizes_.end()) { 129 const int last_size = found_size->second; 130 std::map<base::ProcessId, base::TimeTicks>::iterator found_time = 131 times_.find(pid); 132 const base::TimeTicks last_time = found_time->second; 133 if (last_time < (current_time - base::TimeDelta::FromMinutes(30))) { 134 // Note that it is undefined how division of a negative integer gets 135 // rounded. |*diff| may have a difference of 1 from the correct number 136 // if |sample| < |last_size|. We ignore it as 1 is small enough. 137 *diff = ((sample - last_size) * 30 / 138 (current_time - last_time).InMinutes()); 139 found_size->second = sample; 140 found_time->second = current_time; 141 return true; 142 } 143 // Skip if a last record is found less than 30 minutes ago. 144 } else { 145 // Not reporting if it's the first record for |pid|. 146 times_[pid] = current_time; 147 memory_sizes_[pid] = sample; 148 } 149 return false; 150} 151 152// About threading: 153// 154// This operation will hit no fewer than 3 threads. 155// 156// The BrowserChildProcessHostIterator can only be accessed from the IO thread. 157// 158// The RenderProcessHostIterator can only be accessed from the UI thread. 159// 160// This operation can take 30-100ms to complete. We never want to have 161// one task run for that long on the UI or IO threads. So, we run the 162// expensive parts of this operation over on the file thread. 163// 164void MemoryDetails::StartFetch(UserMetricsMode user_metrics_mode) { 165 // This might get called from the UI or FILE threads, but should not be 166 // getting called from the IO thread. 167 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 168 user_metrics_mode_ = user_metrics_mode; 169 170 // In order to process this request, we need to use the plugin information. 171 // However, plugin process information is only available from the IO thread. 172 BrowserThread::PostTask( 173 BrowserThread::IO, FROM_HERE, 174 base::Bind(&MemoryDetails::CollectChildInfoOnIOThread, this)); 175} 176 177MemoryDetails::~MemoryDetails() {} 178 179std::string MemoryDetails::ToLogString() { 180 std::string log; 181 log.reserve(4096); 182 ProcessMemoryInformationList processes = ChromeBrowser()->processes; 183 // Sort by memory consumption, low to high. 184 std::sort(processes.begin(), processes.end()); 185 // Print from high to low. 186 for (ProcessMemoryInformationList::reverse_iterator iter1 = 187 processes.rbegin(); 188 iter1 != processes.rend(); 189 ++iter1) { 190 log += ProcessMemoryInformation::GetFullTypeNameInEnglish( 191 iter1->process_type, iter1->renderer_type); 192 if (!iter1->titles.empty()) { 193 log += " ["; 194 for (std::vector<base::string16>::const_iterator iter2 = 195 iter1->titles.begin(); 196 iter2 != iter1->titles.end(); ++iter2) { 197 if (iter2 != iter1->titles.begin()) 198 log += "|"; 199 log += base::UTF16ToUTF8(*iter2); 200 } 201 log += "]"; 202 } 203 log += StringPrintf(" %d MB private, %d MB shared", 204 static_cast<int>(iter1->working_set.priv) / 1024, 205 static_cast<int>(iter1->working_set.shared) / 1024); 206#if defined(OS_CHROMEOS) 207 log += StringPrintf(", %d MB swapped", 208 static_cast<int>(iter1->working_set.swapped) / 1024); 209#endif 210 log += "\n"; 211 } 212 return log; 213} 214 215void MemoryDetails::SetMemoryGrowthTracker( 216 MemoryGrowthTracker* memory_growth_tracker) { 217 memory_growth_tracker_ = memory_growth_tracker; 218} 219 220void MemoryDetails::CollectChildInfoOnIOThread() { 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 222 223 std::vector<ProcessMemoryInformation> child_info; 224 225 // Collect the list of child processes. A 0 |handle| means that 226 // the process is being launched, so we skip it. 227 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { 228 ProcessMemoryInformation info; 229 if (!iter.GetData().handle) 230 continue; 231 info.pid = base::GetProcId(iter.GetData().handle); 232 if (!info.pid) 233 continue; 234 235 info.process_type = iter.GetData().process_type; 236 info.renderer_type = ProcessMemoryInformation::RENDERER_UNKNOWN; 237 info.titles.push_back(iter.GetData().name); 238 child_info.push_back(info); 239 } 240 241 // Now go do expensive memory lookups from the file thread. 242 BrowserThread::PostTask( 243 BrowserThread::FILE, FROM_HERE, 244 base::Bind(&MemoryDetails::CollectProcessData, this, child_info)); 245} 246 247void MemoryDetails::CollectChildInfoOnUIThread() { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 250#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 251 const pid_t zygote_pid = content::ZygoteHost::GetInstance()->GetPid(); 252#endif 253 254 ProcessData* const chrome_browser = ChromeBrowser(); 255 // Get more information about the process. 256 for (size_t index = 0; index < chrome_browser->processes.size(); 257 index++) { 258 // Check if it's a renderer, if so get the list of page titles in it and 259 // check if it's a diagnostics-related process. We skip about:memory pages. 260 // Iterate the RenderProcessHosts to find the tab contents. 261 ProcessMemoryInformation& process = 262 chrome_browser->processes[index]; 263 264 scoped_ptr<content::RenderWidgetHostIterator> widgets( 265 RenderWidgetHost::GetRenderWidgetHosts()); 266 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { 267 content::RenderProcessHost* render_process_host = 268 widget->GetProcess(); 269 DCHECK(render_process_host); 270 // Ignore processes that don't have a connection, such as crashed tabs. 271 if (!render_process_host->HasConnection() || 272 process.pid != base::GetProcId(render_process_host->GetHandle())) { 273 continue; 274 } 275 276 // The RenderProcessHost may host multiple WebContentses. Any 277 // of them which contain diagnostics information make the whole 278 // process be considered a diagnostics process. 279 if (!widget->IsRenderView()) 280 continue; 281 282 process.process_type = content::PROCESS_TYPE_RENDERER; 283 bool is_extension = false; 284 RenderViewHost* host = RenderViewHost::From(widget); 285#if defined(ENABLE_EXTENSIONS) 286 content::BrowserContext* context = 287 render_process_host->GetBrowserContext(); 288 ExtensionService* extension_service = 289 extensions::ExtensionSystem::Get(context)->extension_service(); 290 extensions::ProcessMap* extension_process_map = 291 extensions::ProcessMap::Get(context); 292 is_extension = extension_process_map->Contains( 293 host->GetProcess()->GetID()); 294#endif 295 296 WebContents* contents = WebContents::FromRenderViewHost(host); 297 GURL url; 298 if (contents) { 299 url = contents->GetURL(); 300 SiteData* site_data = 301 &chrome_browser->site_data[contents->GetBrowserContext()]; 302 SiteDetails::CollectSiteInfo(contents, site_data); 303 } 304#if defined(ENABLE_EXTENSIONS) 305 extensions::ViewType type = extensions::GetViewType(contents); 306#endif 307 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) { 308 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME; 309 } else if (is_extension) { 310#if defined(ENABLE_EXTENSIONS) 311 // For our purposes, don't count processes containing only hosted apps 312 // as extension processes. See also: crbug.com/102533. 313 std::set<std::string> extension_ids = 314 extension_process_map->GetExtensionsInProcess( 315 host->GetProcess()->GetID()); 316 for (std::set<std::string>::iterator iter = extension_ids.begin(); 317 iter != extension_ids.end(); ++iter) { 318 const Extension* extension = 319 extension_service->GetExtensionById(*iter, false); 320 if (extension && !extension->is_hosted_app()) { 321 process.renderer_type = 322 ProcessMemoryInformation::RENDERER_EXTENSION; 323 break; 324 } 325 } 326#endif 327 } 328#if defined(ENABLE_EXTENSIONS) 329 if (is_extension) { 330 const Extension* extension = 331 extension_service->extensions()->GetByID(url.host()); 332 if (extension) { 333 base::string16 title = base::UTF8ToUTF16(extension->name()); 334 process.titles.push_back(title); 335 process.renderer_type = 336 ProcessMemoryInformation::RENDERER_EXTENSION; 337 continue; 338 } 339 } 340#endif 341 342 if (!contents) { 343 process.renderer_type = 344 ProcessMemoryInformation::RENDERER_INTERSTITIAL; 345 continue; 346 } 347 348#if defined(ENABLE_EXTENSIONS) 349 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) { 350 process.titles.push_back(base::UTF8ToUTF16(url.spec())); 351 process.renderer_type = 352 ProcessMemoryInformation::RENDERER_BACKGROUND_APP; 353 continue; 354 } 355#endif 356 357 // Since we have a WebContents and and the renderer type hasn't been 358 // set yet, it must be a normal tabbed renderer. 359 if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN) 360 process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL; 361 362 base::string16 title = contents->GetTitle(); 363 if (!title.length()) 364 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE); 365 process.titles.push_back(title); 366 367 // We need to check the pending entry as well as the virtual_url to 368 // see if it's a chrome://memory URL (we don't want to count these in 369 // the total memory usage of the browser). 370 // 371 // When we reach here, chrome://memory will be the pending entry since 372 // we haven't responded with any data such that it would be committed. 373 // If you have another chrome://memory tab open (which would be 374 // committed), we don't want to count it either, so we also check the 375 // last committed entry. 376 // 377 // Either the pending or last committed entries can be NULL. 378 const NavigationEntry* pending_entry = 379 contents->GetController().GetPendingEntry(); 380 const NavigationEntry* last_committed_entry = 381 contents->GetController().GetLastCommittedEntry(); 382 if ((last_committed_entry && 383 LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(), 384 chrome::kChromeUIMemoryURL)) || 385 (pending_entry && 386 LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(), 387 chrome::kChromeUIMemoryURL))) { 388 process.is_diagnostics = true; 389 } 390 } 391 392#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 393 if (process.pid == zygote_pid) { 394 process.process_type = content::PROCESS_TYPE_ZYGOTE; 395 } 396#endif 397 } 398 399 // Get rid of other Chrome processes that are from a different profile. 400 for (size_t index = 0; index < chrome_browser->processes.size(); 401 index++) { 402 if (chrome_browser->processes[index].process_type == 403 content::PROCESS_TYPE_UNKNOWN) { 404 chrome_browser->processes.erase( 405 chrome_browser->processes.begin() + index); 406 index--; 407 } 408 } 409 410 if (user_metrics_mode_ == UPDATE_USER_METRICS) 411 UpdateHistograms(); 412 413 OnDetailsAvailable(); 414} 415 416void MemoryDetails::UpdateHistograms() { 417 // Reports a set of memory metrics to UMA. 418 // Memory is measured in KB. 419 420 const ProcessData& browser = *ChromeBrowser(); 421 size_t aggregate_memory = 0; 422 int chrome_count = 0; 423 int extension_count = 0; 424 int plugin_count = 0; 425 int pepper_plugin_count = 0; 426 int pepper_plugin_broker_count = 0; 427 int renderer_count = 0; 428 int other_count = 0; 429 int worker_count = 0; 430 int process_limit = content::RenderProcessHost::GetMaxRendererProcessCount(); 431 for (size_t index = 0; index < browser.processes.size(); index++) { 432 int sample = static_cast<int>(browser.processes[index].working_set.priv); 433 aggregate_memory += sample; 434 switch (browser.processes[index].process_type) { 435 case content::PROCESS_TYPE_BROWSER: 436 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); 437 continue; 438 case content::PROCESS_TYPE_RENDERER: { 439 ProcessMemoryInformation::RendererProcessType renderer_type = 440 browser.processes[index].renderer_type; 441 switch (renderer_type) { 442 case ProcessMemoryInformation::RENDERER_EXTENSION: 443 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample); 444 extension_count++; 445 continue; 446 case ProcessMemoryInformation::RENDERER_CHROME: 447 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); 448 chrome_count++; 449 continue; 450 case ProcessMemoryInformation::RENDERER_UNKNOWN: 451 NOTREACHED() << "Unknown renderer process type."; 452 continue; 453 case ProcessMemoryInformation::RENDERER_NORMAL: 454 default: 455 // TODO(erikkay): Should we bother splitting out the other subtypes? 456 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); 457 int diff; 458 if (memory_growth_tracker_ && 459 memory_growth_tracker_->UpdateSample( 460 browser.processes[index].pid, sample, &diff)) { 461 if (diff < 0) 462 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff); 463 else 464 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff); 465 } 466 renderer_count++; 467 continue; 468 } 469 } 470 case content::PROCESS_TYPE_PLUGIN: 471 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); 472 plugin_count++; 473 continue; 474 case content::PROCESS_TYPE_UTILITY: 475 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); 476 other_count++; 477 continue; 478 case content::PROCESS_TYPE_ZYGOTE: 479 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); 480 other_count++; 481 continue; 482 case content::PROCESS_TYPE_SANDBOX_HELPER: 483 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); 484 other_count++; 485 continue; 486 case content::PROCESS_TYPE_GPU: 487 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); 488 other_count++; 489 continue; 490 case content::PROCESS_TYPE_PPAPI_PLUGIN: 491 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample); 492 pepper_plugin_count++; 493 continue; 494 case content::PROCESS_TYPE_PPAPI_BROKER: 495 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample); 496 pepper_plugin_broker_count++; 497 continue; 498 case PROCESS_TYPE_NACL_LOADER: 499 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); 500 other_count++; 501 continue; 502 case PROCESS_TYPE_NACL_BROKER: 503 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); 504 other_count++; 505 continue; 506 default: 507 NOTREACHED(); 508 continue; 509 } 510 } 511#if defined(OS_CHROMEOS) 512 // Chrome OS exposes system-wide graphics driver memory which has historically 513 // been a source of leak/bloat. 514 base::SystemMemoryInfoKB meminfo; 515 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) 516 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); 517#endif 518 519 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit); 520 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", 521 static_cast<int>(browser.processes.size())); 522 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); 523 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); 524 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); 525 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); 526 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", 527 pepper_plugin_count); 528 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", 529 pepper_plugin_broker_count); 530 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); 531 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); 532 // TODO(viettrungluu): Do we want separate counts for the other 533 // (platform-specific) process types? 534 535 int total_sample = static_cast<int>(aggregate_memory / 1000); 536 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); 537 538#if defined(OS_CHROMEOS) 539 UpdateSwapHistograms(); 540#endif 541} 542 543#if defined(OS_CHROMEOS) 544void MemoryDetails::UpdateSwapHistograms() { 545 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info_.num_writes > 0); 546 if (swap_info_.num_writes == 0) 547 return; 548 549 // Only record swap info when any swaps have happened, to give us more 550 // detail in the histograms. 551 const ProcessData& browser = *ChromeBrowser(); 552 size_t aggregate_memory = 0; 553 for (size_t index = 0; index < browser.processes.size(); index++) { 554 int sample = static_cast<int>(browser.processes[index].working_set.swapped); 555 aggregate_memory += sample; 556 switch (browser.processes[index].process_type) { 557 case content::PROCESS_TYPE_BROWSER: 558 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample); 559 continue; 560 case content::PROCESS_TYPE_RENDERER: { 561 ProcessMemoryInformation::RendererProcessType renderer_type = 562 browser.processes[index].renderer_type; 563 switch (renderer_type) { 564 case ProcessMemoryInformation::RENDERER_EXTENSION: 565 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample); 566 continue; 567 case ProcessMemoryInformation::RENDERER_CHROME: 568 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample); 569 continue; 570 case ProcessMemoryInformation::RENDERER_UNKNOWN: 571 NOTREACHED() << "Unknown renderer process type."; 572 continue; 573 case ProcessMemoryInformation::RENDERER_NORMAL: 574 default: 575 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample); 576 continue; 577 } 578 } 579 case content::PROCESS_TYPE_PLUGIN: 580 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample); 581 continue; 582 case content::PROCESS_TYPE_UTILITY: 583 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample); 584 continue; 585 case content::PROCESS_TYPE_ZYGOTE: 586 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample); 587 continue; 588 case content::PROCESS_TYPE_SANDBOX_HELPER: 589 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample); 590 continue; 591 case content::PROCESS_TYPE_GPU: 592 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample); 593 continue; 594 case content::PROCESS_TYPE_PPAPI_PLUGIN: 595 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample); 596 continue; 597 case content::PROCESS_TYPE_PPAPI_BROKER: 598 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample); 599 continue; 600 case PROCESS_TYPE_NACL_LOADER: 601 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample); 602 continue; 603 case PROCESS_TYPE_NACL_BROKER: 604 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample); 605 continue; 606 default: 607 NOTREACHED(); 608 continue; 609 } 610 } 611 612 int total_sample = static_cast<int>(aggregate_memory / 1000); 613 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample); 614 615 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize", 616 swap_info_.compr_data_size / (1024 * 1024), 617 1, 4096, 50); 618 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize", 619 swap_info_.orig_data_size / (1024 * 1024), 620 1, 4096, 50); 621 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal", 622 swap_info_.mem_used_total / (1024 * 1024), 623 1, 4096, 50); 624 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads", 625 swap_info_.num_reads, 626 1, 100000000, 100); 627 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites", 628 swap_info_.num_writes, 629 1, 100000000, 100); 630 631 if (swap_info_.orig_data_size > 0 && swap_info_.compr_data_size > 0) { 632 UMA_HISTOGRAM_CUSTOM_COUNTS( 633 "Memory.Swap.CompressionRatio", 634 swap_info_.orig_data_size / swap_info_.compr_data_size, 635 1, 20, 20); 636 } 637} 638 639#endif 640