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