Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / memory_details.cc
blob7d8c3c98c85968c3684e8102b07fc20f3f48f609
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/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"
29 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
30 #include "content/public/browser/zygote_host_linux.h"
31 #endif
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
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;
51 #endif
53 // static
54 std::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";
76 // static
77 std::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);
85 ProcessMemoryInformation::ProcessMemoryInformation()
86 : pid(0),
87 num_processes(0),
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)
103 : name(rhs.name),
104 process_name(rhs.process_name),
105 processes(rhs.processes) {
108 ProcessData::~ProcessData() {}
110 ProcessData& ProcessData::operator=(const ProcessData& rhs) {
111 name = rhs.name;
112 process_name = rhs.process_name;
113 processes = rhs.processes;
114 return *this;
117 MemoryGrowthTracker::MemoryGrowthTracker() {}
119 MemoryGrowthTracker::~MemoryGrowthTracker() {}
121 bool 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;
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;
149 return false;
152 // About threading:
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() {
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);
201 log += "]";
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";
212 return log;
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)
230 continue;
231 info.pid = base::GetProcId(iter.GetData().handle);
232 if (!info.pid)
233 continue;
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();
252 #endif
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];
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;
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;
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
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);
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;
326 #endif
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;
340 #endif
342 if (!contents) {
343 process.renderer_type =
344 ProcessMemoryInformation::RENDERER_INTERSTITIAL;
345 continue;
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;
355 #endif
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();
363 if (!title.length())
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)) ||
385 (pending_entry &&
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;
396 #endif
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--;
410 if (user_metrics_mode_ == UPDATE_USER_METRICS)
411 UpdateHistograms();
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;
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);
466 renderer_count++;
467 continue;
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;
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
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?
535 int total_sample = static_cast<int>(aggregate_memory / 1000);
536 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample);
538 #if defined(OS_CHROMEOS)
539 UpdateSwapHistograms();
540 #endif
543 #if defined(OS_CHROMEOS)
544 void MemoryDetails::UpdateSwapHistograms() {
545 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info_.num_writes > 0);
546 if (swap_info_.num_writes == 0)
547 return;
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;
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;
612 int total_sample = static_cast<int>(aggregate_memory / 1000);
613 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample);
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);
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);
639 #endif