Remove the dependency of PasswordStore on BrowserContextKeyedService
[chromium-blink-merge.git] / chrome / browser / memory_details.cc
blob2976d651c5525d275ff6fe97fbe9600c09f448cf
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.
5 #include "chrome/browser/memory_details.h"
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/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/url_constants.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 "extensions/browser/process_manager.h"
28 #include "extensions/browser/process_map.h"
29 #include "extensions/browser/view_type_utils.h"
30 #include "extensions/common/extension.h"
31 #include "grit/chromium_strings.h"
32 #include "grit/generated_resources.h"
33 #include "ui/base/l10n/l10n_util.h"
35 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
36 #include "content/public/browser/zygote_host_linux.h"
37 #endif
39 using base::StringPrintf;
40 using content::BrowserChildProcessHostIterator;
41 using content::BrowserThread;
42 using content::NavigationEntry;
43 using content::RenderViewHost;
44 using content::RenderWidgetHost;
45 using content::WebContents;
46 using extensions::Extension;
48 // static
49 std::string ProcessMemoryInformation::GetRendererTypeNameInEnglish(
50 RendererProcessType type) {
51 switch (type) {
52 case RENDERER_NORMAL:
53 return "Tab";
54 case RENDERER_CHROME:
55 return "Tab (Chrome)";
56 case RENDERER_EXTENSION:
57 return "Extension";
58 case RENDERER_DEVTOOLS:
59 return "Devtools";
60 case RENDERER_INTERSTITIAL:
61 return "Interstitial";
62 case RENDERER_NOTIFICATION:
63 return "Notification";
64 case RENDERER_BACKGROUND_APP:
65 return "Background App";
66 case RENDERER_UNKNOWN:
67 default:
68 NOTREACHED() << "Unknown renderer process type!";
69 return "Unknown";
73 // static
74 std::string ProcessMemoryInformation::GetFullTypeNameInEnglish(
75 int process_type,
76 RendererProcessType rtype) {
77 if (process_type == content::PROCESS_TYPE_RENDERER)
78 return GetRendererTypeNameInEnglish(rtype);
79 return content::GetProcessTypeNameInEnglish(process_type);
82 ProcessMemoryInformation::ProcessMemoryInformation()
83 : pid(0),
84 num_processes(0),
85 is_diagnostics(false),
86 process_type(content::PROCESS_TYPE_UNKNOWN),
87 renderer_type(RENDERER_UNKNOWN) {
90 ProcessMemoryInformation::~ProcessMemoryInformation() {}
92 bool ProcessMemoryInformation::operator<(
93 const ProcessMemoryInformation& rhs) const {
94 return working_set.priv < rhs.working_set.priv;
97 ProcessData::ProcessData() {}
99 ProcessData::ProcessData(const ProcessData& rhs)
100 : name(rhs.name),
101 process_name(rhs.process_name),
102 processes(rhs.processes) {
105 ProcessData::~ProcessData() {}
107 ProcessData& ProcessData::operator=(const ProcessData& rhs) {
108 name = rhs.name;
109 process_name = rhs.process_name;
110 processes = rhs.processes;
111 return *this;
114 // About threading:
116 // This operation will hit no fewer than 3 threads.
118 // The BrowserChildProcessHostIterator can only be accessed from the IO thread.
120 // The RenderProcessHostIterator can only be accessed from the UI thread.
122 // This operation can take 30-100ms to complete. We never want to have
123 // one task run for that long on the UI or IO threads. So, we run the
124 // expensive parts of this operation over on the file thread.
126 void MemoryDetails::StartFetch(UserMetricsMode user_metrics_mode) {
127 // This might get called from the UI or FILE threads, but should not be
128 // getting called from the IO thread.
129 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
130 user_metrics_mode_ = user_metrics_mode;
132 // In order to process this request, we need to use the plugin information.
133 // However, plugin process information is only available from the IO thread.
134 BrowserThread::PostTask(
135 BrowserThread::IO, FROM_HERE,
136 base::Bind(&MemoryDetails::CollectChildInfoOnIOThread, this));
139 MemoryDetails::~MemoryDetails() {}
141 std::string MemoryDetails::ToLogString() {
142 std::string log;
143 log.reserve(4096);
144 ProcessMemoryInformationList processes = ChromeBrowser()->processes;
145 // Sort by memory consumption, low to high.
146 std::sort(processes.begin(), processes.end());
147 // Print from high to low.
148 for (ProcessMemoryInformationList::reverse_iterator iter1 =
149 processes.rbegin();
150 iter1 != processes.rend();
151 ++iter1) {
152 log += ProcessMemoryInformation::GetFullTypeNameInEnglish(
153 iter1->process_type, iter1->renderer_type);
154 if (!iter1->titles.empty()) {
155 log += " [";
156 for (std::vector<base::string16>::const_iterator iter2 =
157 iter1->titles.begin();
158 iter2 != iter1->titles.end(); ++iter2) {
159 if (iter2 != iter1->titles.begin())
160 log += "|";
161 log += base::UTF16ToUTF8(*iter2);
163 log += "]";
165 log += StringPrintf(" %d MB private, %d MB shared",
166 static_cast<int>(iter1->working_set.priv) / 1024,
167 static_cast<int>(iter1->working_set.shared) / 1024);
168 #if defined(OS_CHROMEOS)
169 log += StringPrintf(", %d MB swapped",
170 static_cast<int>(iter1->working_set.swapped) / 1024);
171 #endif
172 log += "\n";
174 return log;
177 void MemoryDetails::CollectChildInfoOnIOThread() {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
180 std::vector<ProcessMemoryInformation> child_info;
182 // Collect the list of child processes. A 0 |handle| means that
183 // the process is being launched, so we skip it.
184 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
185 ProcessMemoryInformation info;
186 if (!iter.GetData().handle)
187 continue;
188 info.pid = base::GetProcId(iter.GetData().handle);
189 if (!info.pid)
190 continue;
192 info.process_type = iter.GetData().process_type;
193 info.renderer_type = ProcessMemoryInformation::RENDERER_UNKNOWN;
194 info.titles.push_back(iter.GetData().name);
195 child_info.push_back(info);
198 // Now go do expensive memory lookups from the file thread.
199 BrowserThread::PostTask(
200 BrowserThread::FILE, FROM_HERE,
201 base::Bind(&MemoryDetails::CollectProcessData, this, child_info));
204 void MemoryDetails::CollectChildInfoOnUIThread() {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
208 const pid_t zygote_pid = content::ZygoteHost::GetInstance()->GetPid();
209 const pid_t sandbox_helper_pid =
210 content::ZygoteHost::GetInstance()->GetSandboxHelperPid();
211 #endif
213 ProcessData* const chrome_browser = ChromeBrowser();
214 // Get more information about the process.
215 for (size_t index = 0; index < chrome_browser->processes.size();
216 index++) {
217 // Check if it's a renderer, if so get the list of page titles in it and
218 // check if it's a diagnostics-related process. We skip about:memory pages.
219 // Iterate the RenderProcessHosts to find the tab contents.
220 ProcessMemoryInformation& process =
221 chrome_browser->processes[index];
223 scoped_ptr<content::RenderWidgetHostIterator> widgets(
224 RenderWidgetHost::GetRenderWidgetHosts());
225 while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
226 content::RenderProcessHost* render_process_host =
227 widget->GetProcess();
228 DCHECK(render_process_host);
229 // Ignore processes that don't have a connection, such as crashed tabs.
230 if (!render_process_host->HasConnection() ||
231 process.pid != base::GetProcId(render_process_host->GetHandle())) {
232 continue;
234 process.process_type = content::PROCESS_TYPE_RENDERER;
235 Profile* profile =
236 Profile::FromBrowserContext(
237 render_process_host->GetBrowserContext());
238 ExtensionService* extension_service = profile->GetExtensionService();
239 extensions::ProcessMap* extension_process_map = NULL;
240 // No extensions on Android. So extension_service can be NULL.
241 if (extension_service)
242 extension_process_map = extensions::ProcessMap::Get(profile);
244 // The RenderProcessHost may host multiple WebContentses. Any
245 // of them which contain diagnostics information make the whole
246 // process be considered a diagnostics process.
247 if (!widget->IsRenderView())
248 continue;
250 RenderViewHost* host = RenderViewHost::From(widget);
251 WebContents* contents = WebContents::FromRenderViewHost(host);
252 GURL url;
253 if (contents) {
254 url = contents->GetURL();
255 SiteData* site_data =
256 &chrome_browser->site_data[contents->GetBrowserContext()];
257 SiteDetails::CollectSiteInfo(contents, site_data);
259 extensions::ViewType type = extensions::GetViewType(contents);
260 if (host->GetEnabledBindings() & content::BINDINGS_POLICY_WEB_UI) {
261 process.renderer_type = ProcessMemoryInformation::RENDERER_CHROME;
262 } else if (extension_process_map &&
263 extension_process_map->Contains(host->GetProcess()->GetID())) {
264 // For our purposes, don't count processes containing only hosted apps
265 // as extension processes. See also: crbug.com/102533.
266 std::set<std::string> extension_ids =
267 extension_process_map->GetExtensionsInProcess(
268 host->GetProcess()->GetID());
269 for (std::set<std::string>::iterator iter = extension_ids.begin();
270 iter != extension_ids.end(); ++iter) {
271 const Extension* extension =
272 extension_service->GetExtensionById(*iter, false);
273 if (extension && !extension->is_hosted_app()) {
274 process.renderer_type =
275 ProcessMemoryInformation::RENDERER_EXTENSION;
276 break;
280 if (extension_process_map &&
281 extension_process_map->Contains(host->GetProcess()->GetID())) {
282 const Extension* extension =
283 extension_service->extensions()->GetByID(url.host());
284 if (extension) {
285 base::string16 title = base::UTF8ToUTF16(extension->name());
286 process.titles.push_back(title);
287 process.renderer_type =
288 ProcessMemoryInformation::RENDERER_EXTENSION;
289 continue;
293 if (!contents) {
294 process.renderer_type =
295 ProcessMemoryInformation::RENDERER_INTERSTITIAL;
296 continue;
299 if (type == extensions::VIEW_TYPE_BACKGROUND_CONTENTS) {
300 process.titles.push_back(base::UTF8ToUTF16(url.spec()));
301 process.renderer_type =
302 ProcessMemoryInformation::RENDERER_BACKGROUND_APP;
303 continue;
306 if (type == extensions::VIEW_TYPE_NOTIFICATION) {
307 process.titles.push_back(base::UTF8ToUTF16(url.spec()));
308 process.renderer_type =
309 ProcessMemoryInformation::RENDERER_NOTIFICATION;
310 continue;
313 // Since we have a WebContents and and the renderer type hasn't been
314 // set yet, it must be a normal tabbed renderer.
315 if (process.renderer_type == ProcessMemoryInformation::RENDERER_UNKNOWN)
316 process.renderer_type = ProcessMemoryInformation::RENDERER_NORMAL;
318 base::string16 title = contents->GetTitle();
319 if (!title.length())
320 title = l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE);
321 process.titles.push_back(title);
323 // We need to check the pending entry as well as the virtual_url to
324 // see if it's a chrome://memory URL (we don't want to count these in
325 // the total memory usage of the browser).
327 // When we reach here, chrome://memory will be the pending entry since
328 // we haven't responded with any data such that it would be committed.
329 // If you have another chrome://memory tab open (which would be
330 // committed), we don't want to count it either, so we also check the
331 // last committed entry.
333 // Either the pending or last committed entries can be NULL.
334 const NavigationEntry* pending_entry =
335 contents->GetController().GetPendingEntry();
336 const NavigationEntry* last_committed_entry =
337 contents->GetController().GetLastCommittedEntry();
338 if ((last_committed_entry &&
339 LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(),
340 chrome::kChromeUIMemoryURL)) ||
341 (pending_entry &&
342 LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(),
343 chrome::kChromeUIMemoryURL))) {
344 process.is_diagnostics = true;
348 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
349 if (process.pid == zygote_pid) {
350 process.process_type = content::PROCESS_TYPE_ZYGOTE;
351 } else if (process.pid == sandbox_helper_pid) {
352 process.process_type = content::PROCESS_TYPE_SANDBOX_HELPER;
354 #endif
357 // Get rid of other Chrome processes that are from a different profile.
358 for (size_t index = 0; index < chrome_browser->processes.size();
359 index++) {
360 if (chrome_browser->processes[index].process_type ==
361 content::PROCESS_TYPE_UNKNOWN) {
362 chrome_browser->processes.erase(
363 chrome_browser->processes.begin() + index);
364 index--;
368 if (user_metrics_mode_ == UPDATE_USER_METRICS)
369 UpdateHistograms();
371 OnDetailsAvailable();
374 void MemoryDetails::UpdateHistograms() {
375 // Reports a set of memory metrics to UMA.
376 // Memory is measured in KB.
378 const ProcessData& browser = *ChromeBrowser();
379 size_t aggregate_memory = 0;
380 int chrome_count = 0;
381 int extension_count = 0;
382 int plugin_count = 0;
383 int pepper_plugin_count = 0;
384 int pepper_plugin_broker_count = 0;
385 int renderer_count = 0;
386 int other_count = 0;
387 int worker_count = 0;
388 int process_limit = content::RenderProcessHost::GetMaxRendererProcessCount();
389 for (size_t index = 0; index < browser.processes.size(); index++) {
390 int sample = static_cast<int>(browser.processes[index].working_set.priv);
391 aggregate_memory += sample;
392 switch (browser.processes[index].process_type) {
393 case content::PROCESS_TYPE_BROWSER:
394 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample);
395 continue;
396 case content::PROCESS_TYPE_RENDERER: {
397 ProcessMemoryInformation::RendererProcessType renderer_type =
398 browser.processes[index].renderer_type;
399 switch (renderer_type) {
400 case ProcessMemoryInformation::RENDERER_EXTENSION:
401 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample);
402 extension_count++;
403 continue;
404 case ProcessMemoryInformation::RENDERER_CHROME:
405 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample);
406 chrome_count++;
407 continue;
408 case ProcessMemoryInformation::RENDERER_UNKNOWN:
409 NOTREACHED() << "Unknown renderer process type.";
410 continue;
411 case ProcessMemoryInformation::RENDERER_NORMAL:
412 default:
413 // TODO(erikkay): Should we bother splitting out the other subtypes?
414 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample);
415 renderer_count++;
416 continue;
419 case content::PROCESS_TYPE_PLUGIN:
420 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample);
421 plugin_count++;
422 continue;
423 case content::PROCESS_TYPE_WORKER:
424 UMA_HISTOGRAM_MEMORY_KB("Memory.Worker", sample);
425 worker_count++;
426 continue;
427 case content::PROCESS_TYPE_UTILITY:
428 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample);
429 other_count++;
430 continue;
431 case content::PROCESS_TYPE_ZYGOTE:
432 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample);
433 other_count++;
434 continue;
435 case content::PROCESS_TYPE_SANDBOX_HELPER:
436 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample);
437 other_count++;
438 continue;
439 case content::PROCESS_TYPE_GPU:
440 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample);
441 other_count++;
442 continue;
443 case content::PROCESS_TYPE_PPAPI_PLUGIN:
444 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample);
445 pepper_plugin_count++;
446 continue;
447 case content::PROCESS_TYPE_PPAPI_BROKER:
448 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample);
449 pepper_plugin_broker_count++;
450 continue;
451 case PROCESS_TYPE_NACL_LOADER:
452 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample);
453 other_count++;
454 continue;
455 case PROCESS_TYPE_NACL_BROKER:
456 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample);
457 other_count++;
458 continue;
459 default:
460 NOTREACHED();
461 continue;
464 UMA_HISTOGRAM_MEMORY_KB("Memory.BackingStore",
465 RenderWidgetHost::BackingStoreMemorySize() / 1024);
466 #if defined(OS_CHROMEOS)
467 // Chrome OS exposes system-wide graphics driver memory which has historically
468 // been a source of leak/bloat.
469 base::SystemMemoryInfoKB meminfo;
470 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1)
471 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024);
472 #endif
474 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit);
475 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
476 static_cast<int>(browser.processes.size()));
477 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count);
478 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count);
479 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count);
480 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count);
481 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount",
482 pepper_plugin_count);
483 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount",
484 pepper_plugin_broker_count);
485 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count);
486 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count);
487 // TODO(viettrungluu): Do we want separate counts for the other
488 // (platform-specific) process types?
490 int total_sample = static_cast<int>(aggregate_memory / 1000);
491 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample);
493 #if defined(OS_CHROMEOS)
494 UpdateSwapHistograms();
495 #endif
499 #if defined(OS_CHROMEOS)
500 void MemoryDetails::UpdateSwapHistograms() {
501 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info_.num_writes > 0);
502 if (swap_info_.num_writes == 0)
503 return;
505 // Only record swap info when any swaps have happened, to give us more
506 // detail in the histograms.
507 const ProcessData& browser = *ChromeBrowser();
508 size_t aggregate_memory = 0;
509 for (size_t index = 0; index < browser.processes.size(); index++) {
510 int sample = static_cast<int>(browser.processes[index].working_set.swapped);
511 aggregate_memory += sample;
512 switch (browser.processes[index].process_type) {
513 case content::PROCESS_TYPE_BROWSER:
514 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample);
515 continue;
516 case content::PROCESS_TYPE_RENDERER: {
517 ProcessMemoryInformation::RendererProcessType renderer_type =
518 browser.processes[index].renderer_type;
519 switch (renderer_type) {
520 case ProcessMemoryInformation::RENDERER_EXTENSION:
521 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample);
522 continue;
523 case ProcessMemoryInformation::RENDERER_CHROME:
524 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample);
525 continue;
526 case ProcessMemoryInformation::RENDERER_UNKNOWN:
527 NOTREACHED() << "Unknown renderer process type.";
528 continue;
529 case ProcessMemoryInformation::RENDERER_NORMAL:
530 default:
531 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample);
532 continue;
535 case content::PROCESS_TYPE_PLUGIN:
536 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample);
537 continue;
538 case content::PROCESS_TYPE_WORKER:
539 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Worker", sample);
540 continue;
541 case content::PROCESS_TYPE_UTILITY:
542 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample);
543 continue;
544 case content::PROCESS_TYPE_ZYGOTE:
545 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample);
546 continue;
547 case content::PROCESS_TYPE_SANDBOX_HELPER:
548 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample);
549 continue;
550 case content::PROCESS_TYPE_GPU:
551 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample);
552 continue;
553 case content::PROCESS_TYPE_PPAPI_PLUGIN:
554 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample);
555 continue;
556 case content::PROCESS_TYPE_PPAPI_BROKER:
557 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample);
558 continue;
559 case PROCESS_TYPE_NACL_LOADER:
560 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample);
561 continue;
562 case PROCESS_TYPE_NACL_BROKER:
563 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample);
564 continue;
565 default:
566 NOTREACHED();
567 continue;
571 int total_sample = static_cast<int>(aggregate_memory / 1000);
572 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample);
574 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
575 swap_info_.compr_data_size / (1024 * 1024),
576 1, 4096, 50);
577 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
578 swap_info_.orig_data_size / (1024 * 1024),
579 1, 4096, 50);
580 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
581 swap_info_.mem_used_total / (1024 * 1024),
582 1, 4096, 50);
583 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads",
584 swap_info_.num_reads,
585 1, 100000000, 100);
586 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites",
587 swap_info_.num_writes,
588 1, 100000000, 100);
590 if (swap_info_.orig_data_size > 0 && swap_info_.compr_data_size > 0) {
591 UMA_HISTOGRAM_CUSTOM_COUNTS(
592 "Memory.Swap.CompressionRatio",
593 swap_info_.orig_data_size / swap_info_.compr_data_size,
594 1, 20, 20);
598 #endif