Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: chrome/browser/memory_details.cc

Issue 823533004: Move memory histograms generation to MetricsMemoryDetails. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: clang-format Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/memory_details.h" 5 #include "chrome/browser/memory_details.h"
6 6
7 #include <algorithm>
8 #include <set>
Ilya Sherman 2015/01/16 04:57:36 nit: Are these just fixing pre-existing IWYU viola
Alexei Svitkine (slow) 2015/01/16 16:07:49 Yep, as suggested by git cl lint.
9
7 #include "base/bind.h" 10 #include "base/bind.h"
8 #include "base/file_version_info.h" 11 #include "base/file_version_info.h"
9 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/url_constants.h" 17 #include "chrome/common/url_constants.h"
15 #include "chrome/grit/generated_resources.h" 18 #include "chrome/grit/generated_resources.h"
16 #include "components/nacl/common/nacl_process_type.h" 19 #include "components/nacl/common/nacl_process_type.h"
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 110
108 ProcessData::~ProcessData() {} 111 ProcessData::~ProcessData() {}
109 112
110 ProcessData& ProcessData::operator=(const ProcessData& rhs) { 113 ProcessData& ProcessData::operator=(const ProcessData& rhs) {
111 name = rhs.name; 114 name = rhs.name;
112 process_name = rhs.process_name; 115 process_name = rhs.process_name;
113 processes = rhs.processes; 116 processes = rhs.processes;
114 return *this; 117 return *this;
115 } 118 }
116 119
117 MemoryGrowthTracker::MemoryGrowthTracker() {}
118
119 MemoryGrowthTracker::~MemoryGrowthTracker() {}
120
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;
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: 120 // About threading:
153 // 121 //
154 // This operation will hit no fewer than 3 threads. 122 // This operation will hit no fewer than 3 threads.
155 // 123 //
156 // The BrowserChildProcessHostIterator can only be accessed from the IO thread. 124 // The BrowserChildProcessHostIterator can only be accessed from the IO thread.
157 // 125 //
158 // The RenderProcessHostIterator can only be accessed from the UI thread. 126 // The RenderProcessHostIterator can only be accessed from the UI thread.
159 // 127 //
160 // This operation can take 30-100ms to complete. We never want to have 128 // 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 129 // 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. 130 // expensive parts of this operation over on the file thread.
163 // 131 //
164 void MemoryDetails::StartFetch(UserMetricsMode user_metrics_mode) { 132 void MemoryDetails::StartFetch() {
165 // This might get called from the UI or FILE threads, but should not be 133 // This might get called from the UI or FILE threads, but should not be
166 // getting called from the IO thread. 134 // getting called from the IO thread.
167 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 135 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
168 user_metrics_mode_ = user_metrics_mode;
169 136
170 // In order to process this request, we need to use the plugin information. 137 // 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. 138 // However, plugin process information is only available from the IO thread.
172 BrowserThread::PostTask( 139 BrowserThread::PostTask(
173 BrowserThread::IO, FROM_HERE, 140 BrowserThread::IO, FROM_HERE,
174 base::Bind(&MemoryDetails::CollectChildInfoOnIOThread, this)); 141 base::Bind(&MemoryDetails::CollectChildInfoOnIOThread, this));
175 } 142 }
176 143
177 MemoryDetails::~MemoryDetails() {} 144 MemoryDetails::~MemoryDetails() {}
178 145
(...skipping 26 matching lines...) Expand all
205 static_cast<int>(iter1->working_set.shared) / 1024); 172 static_cast<int>(iter1->working_set.shared) / 1024);
206 #if defined(OS_CHROMEOS) 173 #if defined(OS_CHROMEOS)
207 log += StringPrintf(", %d MB swapped", 174 log += StringPrintf(", %d MB swapped",
208 static_cast<int>(iter1->working_set.swapped) / 1024); 175 static_cast<int>(iter1->working_set.swapped) / 1024);
209 #endif 176 #endif
210 log += "\n"; 177 log += "\n";
211 } 178 }
212 return log; 179 return log;
213 } 180 }
214 181
215 void MemoryDetails::SetMemoryGrowthTracker(
216 MemoryGrowthTracker* memory_growth_tracker) {
217 memory_growth_tracker_ = memory_growth_tracker;
218 }
219
220 void MemoryDetails::CollectChildInfoOnIOThread() { 182 void MemoryDetails::CollectChildInfoOnIOThread() {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 184
223 std::vector<ProcessMemoryInformation> child_info; 185 std::vector<ProcessMemoryInformation> child_info;
224 186
225 // Collect the list of child processes. A 0 |handle| means that 187 // Collect the list of child processes. A 0 |handle| means that
226 // the process is being launched, so we skip it. 188 // the process is being launched, so we skip it.
227 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { 189 for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
228 ProcessMemoryInformation info; 190 ProcessMemoryInformation info;
229 if (!iter.GetData().handle) 191 if (!iter.GetData().handle)
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 for (size_t index = 0; index < chrome_browser->processes.size(); 362 for (size_t index = 0; index < chrome_browser->processes.size();
401 index++) { 363 index++) {
402 if (chrome_browser->processes[index].process_type == 364 if (chrome_browser->processes[index].process_type ==
403 content::PROCESS_TYPE_UNKNOWN) { 365 content::PROCESS_TYPE_UNKNOWN) {
404 chrome_browser->processes.erase( 366 chrome_browser->processes.erase(
405 chrome_browser->processes.begin() + index); 367 chrome_browser->processes.begin() + index);
406 index--; 368 index--;
407 } 369 }
408 } 370 }
409 371
410 if (user_metrics_mode_ == UPDATE_USER_METRICS)
411 UpdateHistograms();
412
413 OnDetailsAvailable(); 372 OnDetailsAvailable();
414 } 373 }
415
416 void 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 #if defined(ENABLE_PLUGINS)
491 case content::PROCESS_TYPE_PPAPI_PLUGIN:
492 {
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);
498 }
499 }
500 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample);
501 pepper_plugin_count++;
502 continue;
503 case content::PROCESS_TYPE_PPAPI_BROKER:
504 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample);
505 pepper_plugin_broker_count++;
506 continue;
507 #endif
508 case PROCESS_TYPE_NACL_LOADER:
509 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample);
510 other_count++;
511 continue;
512 case PROCESS_TYPE_NACL_BROKER:
513 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample);
514 other_count++;
515 continue;
516 default:
517 NOTREACHED();
518 continue;
519 }
520 }
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);
527 #endif
528
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?
544
545 int total_sample = static_cast<int>(aggregate_memory / 1000);
546 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample);
547
548 #if defined(OS_CHROMEOS)
549 UpdateSwapHistograms();
550 #endif
551 }
552
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)
557 return;
558
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);
569 continue;
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);
576 continue;
577 case ProcessMemoryInformation::RENDERER_CHROME:
578 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample);
579 continue;
580 case ProcessMemoryInformation::RENDERER_UNKNOWN:
581 NOTREACHED() << "Unknown renderer process type.";
582 continue;
583 case ProcessMemoryInformation::RENDERER_NORMAL:
584 default:
585 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample);
586 continue;
587 }
588 }
589 case content::PROCESS_TYPE_PLUGIN:
590 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample);
591 continue;
592 case content::PROCESS_TYPE_UTILITY:
593 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample);
594 continue;
595 case content::PROCESS_TYPE_ZYGOTE:
596 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample);
597 continue;
598 case content::PROCESS_TYPE_SANDBOX_HELPER:
599 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample);
600 continue;
601 case content::PROCESS_TYPE_GPU:
602 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample);
603 continue;
604 case content::PROCESS_TYPE_PPAPI_PLUGIN:
605 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample);
606 continue;
607 case content::PROCESS_TYPE_PPAPI_BROKER:
608 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample);
609 continue;
610 case PROCESS_TYPE_NACL_LOADER:
611 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample);
612 continue;
613 case PROCESS_TYPE_NACL_BROKER:
614 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample);
615 continue;
616 default:
617 NOTREACHED();
618 continue;
619 }
620 }
621
622 int total_sample = static_cast<int>(aggregate_memory / 1000);
623 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample);
624
625 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize",
626 swap_info_.compr_data_size / (1024 * 1024),
627 1, 4096, 50);
628 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize",
629 swap_info_.orig_data_size / (1024 * 1024),
630 1, 4096, 50);
631 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal",
632 swap_info_.mem_used_total / (1024 * 1024),
633 1, 4096, 50);
634 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads",
635 swap_info_.num_reads,
636 1, 100000000, 100);
637 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites",
638 swap_info_.num_writes,
639 1, 100000000, 100);
640
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,
645 1, 20, 20);
646 }
647 }
648
649 #endif // defined(OS_CHROMEOS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698