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"
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 "content/public/common/content_constants.h"
28 #include "ui/base/l10n/l10n_util.h"
30 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
31 #include "content/public/browser/zygote_host_linux.h"
34 #if defined(ENABLE_EXTENSIONS)
35 #include "extensions/browser/extension_registry.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"
42 using base::StringPrintf
;
43 using content::BrowserChildProcessHostIterator
;
44 using content::BrowserThread
;
45 using content::NavigationEntry
;
46 using content::RenderViewHost
;
47 using content::RenderWidgetHost
;
48 using content::WebContents
;
49 #if defined(ENABLE_EXTENSIONS)
50 using extensions::Extension
;
54 std::string
ProcessMemoryInformation::GetRendererTypeNameInEnglish(
55 RendererProcessType type
) {
60 return "Tab (Chrome)";
61 case RENDERER_EXTENSION
:
63 case RENDERER_DEVTOOLS
:
65 case RENDERER_INTERSTITIAL
:
66 return "Interstitial";
67 case RENDERER_BACKGROUND_APP
:
68 return "Background App";
69 case RENDERER_UNKNOWN
:
71 NOTREACHED() << "Unknown renderer process type!";
77 std::string
ProcessMemoryInformation::GetFullTypeNameInEnglish(
79 RendererProcessType rtype
) {
80 if (process_type
== content::PROCESS_TYPE_RENDERER
)
81 return GetRendererTypeNameInEnglish(rtype
);
82 return content::GetProcessTypeNameInEnglish(process_type
);
85 ProcessMemoryInformation::ProcessMemoryInformation()
88 is_diagnostics(false),
89 process_type(content::PROCESS_TYPE_UNKNOWN
),
90 renderer_type(RENDERER_UNKNOWN
) {
93 ProcessMemoryInformation::~ProcessMemoryInformation() {}
95 bool ProcessMemoryInformation::operator<(
96 const ProcessMemoryInformation
& rhs
) const {
97 return working_set
.priv
< rhs
.working_set
.priv
;
100 ProcessData::ProcessData() {}
102 ProcessData::ProcessData(const ProcessData
& rhs
)
104 process_name(rhs
.process_name
),
105 processes(rhs
.processes
) {
108 ProcessData::~ProcessData() {}
110 ProcessData
& ProcessData::operator=(const ProcessData
& rhs
) {
112 process_name
= rhs
.process_name
;
113 processes
= rhs
.processes
;
117 MemoryGrowthTracker::MemoryGrowthTracker() {}
119 MemoryGrowthTracker::~MemoryGrowthTracker() {}
121 bool MemoryGrowthTracker::UpdateSample(
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
=
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
;
143 // Skip if a last record is found less than 30 minutes ago.
145 // Not reporting if it's the first record for |pid|.
146 times_
[pid
] = current_time
;
147 memory_sizes_
[pid
] = sample
;
154 // This operation will hit no fewer than 3 threads.
156 // The BrowserChildProcessHostIterator can only be accessed from the IO thread.
158 // The RenderProcessHostIterator can only be accessed from the UI thread.
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.
164 void 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
;
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));
177 MemoryDetails::~MemoryDetails() {}
179 std::string
MemoryDetails::ToLogString() {
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
=
188 iter1
!= processes
.rend();
190 log
+= ProcessMemoryInformation::GetFullTypeNameInEnglish(
191 iter1
->process_type
, iter1
->renderer_type
);
192 if (!iter1
->titles
.empty()) {
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())
199 log
+= base::UTF16ToUTF8(*iter2
);
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);
215 void MemoryDetails::SetMemoryGrowthTracker(
216 MemoryGrowthTracker
* memory_growth_tracker
) {
217 memory_growth_tracker_
= memory_growth_tracker
;
220 void MemoryDetails::CollectChildInfoOnIOThread() {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
223 std::vector
<ProcessMemoryInformation
> child_info
;
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
)
231 info
.pid
= base::GetProcId(iter
.GetData().handle
);
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
);
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
));
247 void MemoryDetails::CollectChildInfoOnUIThread() {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
250 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
251 const pid_t zygote_pid
= content::ZygoteHost::GetInstance()->GetPid();
254 ProcessData
* const chrome_browser
= ChromeBrowser();
255 // Get more information about the process.
256 for (size_t index
= 0; index
< chrome_browser
->processes
.size();
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
];
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())) {
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())
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 extensions::ExtensionRegistry
* extension_registry
=
289 extensions::ExtensionRegistry::Get(context
);
290 extensions::ProcessMap
* extension_process_map
=
291 extensions::ProcessMap::Get(context
);
292 is_extension
= extension_process_map
->Contains(
293 host
->GetProcess()->GetID());
296 WebContents
* contents
= WebContents::FromRenderViewHost(host
);
299 url
= contents
->GetURL();
300 SiteData
* site_data
=
301 &chrome_browser
->site_data
[contents
->GetBrowserContext()];
302 SiteDetails::CollectSiteInfo(contents
, site_data
);
304 #if defined(ENABLE_EXTENSIONS)
305 extensions::ViewType type
= extensions::GetViewType(contents
);
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_registry
->enabled_extensions().GetByID(*iter
);
320 if (extension
&& !extension
->is_hosted_app()) {
321 process
.renderer_type
=
322 ProcessMemoryInformation::RENDERER_EXTENSION
;
328 #if defined(ENABLE_EXTENSIONS)
330 const Extension
* extension
=
331 extension_registry
->enabled_extensions().GetByID(url
.host());
333 base::string16 title
= base::UTF8ToUTF16(extension
->name());
334 process
.titles
.push_back(title
);
335 process
.renderer_type
=
336 ProcessMemoryInformation::RENDERER_EXTENSION
;
343 process
.renderer_type
=
344 ProcessMemoryInformation::RENDERER_INTERSTITIAL
;
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
;
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
;
362 base::string16 title
= contents
->GetTitle();
364 title
= l10n_util::GetStringUTF16(IDS_DEFAULT_TAB_TITLE
);
365 process
.titles
.push_back(title
);
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).
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.
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
)) ||
386 LowerCaseEqualsASCII(pending_entry
->GetVirtualURL().spec(),
387 chrome::kChromeUIMemoryURL
))) {
388 process
.is_diagnostics
= true;
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
;
399 // Get rid of other Chrome processes that are from a different profile.
400 for (size_t index
= 0; index
< chrome_browser
->processes
.size();
402 if (chrome_browser
->processes
[index
].process_type
==
403 content::PROCESS_TYPE_UNKNOWN
) {
404 chrome_browser
->processes
.erase(
405 chrome_browser
->processes
.begin() + index
);
410 if (user_metrics_mode_
== UPDATE_USER_METRICS
)
413 OnDetailsAvailable();
416 void MemoryDetails::UpdateHistograms() {
417 // Reports a set of memory metrics to UMA.
418 // Memory is measured in KB.
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;
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
);
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
);
446 case ProcessMemoryInformation::RENDERER_CHROME
:
447 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample
);
450 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
451 NOTREACHED() << "Unknown renderer process type.";
453 case ProcessMemoryInformation::RENDERER_NORMAL
:
455 // TODO(erikkay): Should we bother splitting out the other subtypes?
456 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample
);
458 if (memory_growth_tracker_
&&
459 memory_growth_tracker_
->UpdateSample(
460 browser
.processes
[index
].pid
, sample
, &diff
)) {
462 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff
);
464 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff
);
470 case content::PROCESS_TYPE_PLUGIN
:
471 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample
);
474 case content::PROCESS_TYPE_UTILITY
:
475 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample
);
478 case content::PROCESS_TYPE_ZYGOTE
:
479 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample
);
482 case content::PROCESS_TYPE_SANDBOX_HELPER
:
483 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample
);
486 case content::PROCESS_TYPE_GPU
:
487 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample
);
490 #if defined(ENABLE_PLUGINS)
491 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
493 const std::vector
<base::string16
>& titles
=
494 browser
.processes
[index
].titles
;
495 if (titles
.size() == 1 &&
496 titles
[0] == base::ASCIIToUTF16(content::kFlashPluginName
)) {
497 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperFlashPlugin", sample
);
500 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample
);
501 pepper_plugin_count
++;
503 case content::PROCESS_TYPE_PPAPI_BROKER
:
504 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample
);
505 pepper_plugin_broker_count
++;
508 case PROCESS_TYPE_NACL_LOADER
:
509 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample
);
512 case PROCESS_TYPE_NACL_BROKER
:
513 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample
);
521 #if defined(OS_CHROMEOS)
522 // Chrome OS exposes system-wide graphics driver memory which has historically
523 // been a source of leak/bloat.
524 base::SystemMemoryInfoKB meminfo
;
525 if (base::GetSystemMemoryInfo(&meminfo
) && meminfo
.gem_size
!= -1)
526 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo
.gem_size
/ 1024 / 1024);
529 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit
);
530 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount",
531 static_cast<int>(browser
.processes
.size()));
532 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count
);
533 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count
);
534 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count
);
535 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count
);
536 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount",
537 pepper_plugin_count
);
538 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount",
539 pepper_plugin_broker_count
);
540 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count
);
541 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count
);
542 // TODO(viettrungluu): Do we want separate counts for the other
543 // (platform-specific) process types?
545 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
546 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample
);
548 #if defined(OS_CHROMEOS)
549 UpdateSwapHistograms();
553 #if defined(OS_CHROMEOS)
554 void MemoryDetails::UpdateSwapHistograms() {
555 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info_
.num_writes
> 0);
556 if (swap_info_
.num_writes
== 0)
559 // Only record swap info when any swaps have happened, to give us more
560 // detail in the histograms.
561 const ProcessData
& browser
= *ChromeBrowser();
562 size_t aggregate_memory
= 0;
563 for (size_t index
= 0; index
< browser
.processes
.size(); index
++) {
564 int sample
= static_cast<int>(browser
.processes
[index
].working_set
.swapped
);
565 aggregate_memory
+= sample
;
566 switch (browser
.processes
[index
].process_type
) {
567 case content::PROCESS_TYPE_BROWSER
:
568 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample
);
570 case content::PROCESS_TYPE_RENDERER
: {
571 ProcessMemoryInformation::RendererProcessType renderer_type
=
572 browser
.processes
[index
].renderer_type
;
573 switch (renderer_type
) {
574 case ProcessMemoryInformation::RENDERER_EXTENSION
:
575 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample
);
577 case ProcessMemoryInformation::RENDERER_CHROME
:
578 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample
);
580 case ProcessMemoryInformation::RENDERER_UNKNOWN
:
581 NOTREACHED() << "Unknown renderer process type.";
583 case ProcessMemoryInformation::RENDERER_NORMAL
:
585 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample
);
589 case content::PROCESS_TYPE_PLUGIN
:
590 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample
);
592 case content::PROCESS_TYPE_UTILITY
:
593 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample
);
595 case content::PROCESS_TYPE_ZYGOTE
:
596 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample
);
598 case content::PROCESS_TYPE_SANDBOX_HELPER
:
599 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample
);
601 case content::PROCESS_TYPE_GPU
:
602 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample
);
604 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
605 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample
);
607 case content::PROCESS_TYPE_PPAPI_BROKER
:
608 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample
);
610 case PROCESS_TYPE_NACL_LOADER
:
611 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample
);
613 case PROCESS_TYPE_NACL_BROKER
:
614 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample
);
622 int total_sample
= static_cast<int>(aggregate_memory
/ 1000);
623 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample
);
625 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
626 swap_info_
.compr_data_size
/ (1024 * 1024),
628 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
629 swap_info_
.orig_data_size
/ (1024 * 1024),
631 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
632 swap_info_
.mem_used_total
/ (1024 * 1024),
634 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads",
635 swap_info_
.num_reads
,
637 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites",
638 swap_info_
.num_writes
,
641 if (swap_info_
.orig_data_size
> 0 && swap_info_
.compr_data_size
> 0) {
642 UMA_HISTOGRAM_CUSTOM_COUNTS(
643 "Memory.Swap.CompressionRatio",
644 swap_info_
.orig_data_size
/ swap_info_
.compr_data_size
,
649 #endif // defined(OS_CHROMEOS)