OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/metrics/metrics_memory_details.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/metrics/histogram_macros.h" |
| 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "components/nacl/common/nacl_process_type.h" |
| 13 #include "content/public/browser/render_process_host.h" |
| 14 #include "content/public/common/content_constants.h" |
| 15 #include "content/public/common/process_type.h" |
| 16 |
| 17 MemoryGrowthTracker::MemoryGrowthTracker() { |
| 18 } |
| 19 |
| 20 MemoryGrowthTracker::~MemoryGrowthTracker() { |
| 21 } |
| 22 |
| 23 bool MemoryGrowthTracker::UpdateSample(base::ProcessId pid, |
| 24 int sample, |
| 25 int* diff) { |
| 26 // |sample| is memory usage in kB. |
| 27 const base::TimeTicks current_time = base::TimeTicks::Now(); |
| 28 std::map<base::ProcessId, int>::iterator found_size = memory_sizes_.find(pid); |
| 29 if (found_size != memory_sizes_.end()) { |
| 30 const int last_size = found_size->second; |
| 31 std::map<base::ProcessId, base::TimeTicks>::iterator found_time = |
| 32 times_.find(pid); |
| 33 const base::TimeTicks last_time = found_time->second; |
| 34 if (last_time < (current_time - base::TimeDelta::FromMinutes(30))) { |
| 35 // Note that it is undefined how division of a negative integer gets |
| 36 // rounded. |*diff| may have a difference of 1 from the correct number |
| 37 // if |sample| < |last_size|. We ignore it as 1 is small enough. |
| 38 *diff = |
| 39 ((sample - last_size) * 30 / (current_time - last_time).InMinutes()); |
| 40 found_size->second = sample; |
| 41 found_time->second = current_time; |
| 42 return true; |
| 43 } |
| 44 // Skip if a last record is found less than 30 minutes ago. |
| 45 } else { |
| 46 // Not reporting if it's the first record for |pid|. |
| 47 times_[pid] = current_time; |
| 48 memory_sizes_[pid] = sample; |
| 49 } |
| 50 return false; |
| 51 } |
| 52 |
| 53 MetricsMemoryDetails::MetricsMemoryDetails( |
| 54 const base::Closure& callback, |
| 55 MemoryGrowthTracker* memory_growth_tracker) |
| 56 : callback_(callback), memory_growth_tracker_(memory_growth_tracker) { |
| 57 memory_growth_tracker_ = memory_growth_tracker; |
| 58 } |
| 59 |
| 60 MetricsMemoryDetails::~MetricsMemoryDetails() { |
| 61 } |
| 62 |
| 63 void MetricsMemoryDetails::OnDetailsAvailable() { |
| 64 UpdateHistograms(); |
| 65 base::MessageLoop::current()->PostTask(FROM_HERE, callback_); |
| 66 } |
| 67 |
| 68 void MetricsMemoryDetails::UpdateHistograms() { |
| 69 // Reports a set of memory metrics to UMA. |
| 70 // Memory is measured in KB. |
| 71 |
| 72 const ProcessData& browser = *ChromeBrowser(); |
| 73 size_t aggregate_memory = 0; |
| 74 int chrome_count = 0; |
| 75 int extension_count = 0; |
| 76 int plugin_count = 0; |
| 77 int pepper_plugin_count = 0; |
| 78 int pepper_plugin_broker_count = 0; |
| 79 int renderer_count = 0; |
| 80 int other_count = 0; |
| 81 int worker_count = 0; |
| 82 int process_limit = content::RenderProcessHost::GetMaxRendererProcessCount(); |
| 83 for (size_t index = 0; index < browser.processes.size(); index++) { |
| 84 int sample = static_cast<int>(browser.processes[index].working_set.priv); |
| 85 aggregate_memory += sample; |
| 86 switch (browser.processes[index].process_type) { |
| 87 case content::PROCESS_TYPE_BROWSER: |
| 88 UMA_HISTOGRAM_MEMORY_KB("Memory.Browser", sample); |
| 89 continue; |
| 90 case content::PROCESS_TYPE_RENDERER: { |
| 91 ProcessMemoryInformation::RendererProcessType renderer_type = |
| 92 browser.processes[index].renderer_type; |
| 93 switch (renderer_type) { |
| 94 case ProcessMemoryInformation::RENDERER_EXTENSION: |
| 95 UMA_HISTOGRAM_MEMORY_KB("Memory.Extension", sample); |
| 96 extension_count++; |
| 97 continue; |
| 98 case ProcessMemoryInformation::RENDERER_CHROME: |
| 99 UMA_HISTOGRAM_MEMORY_KB("Memory.Chrome", sample); |
| 100 chrome_count++; |
| 101 continue; |
| 102 case ProcessMemoryInformation::RENDERER_UNKNOWN: |
| 103 NOTREACHED() << "Unknown renderer process type."; |
| 104 continue; |
| 105 case ProcessMemoryInformation::RENDERER_NORMAL: |
| 106 default: |
| 107 // TODO(erikkay): Should we bother splitting out the other subtypes? |
| 108 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer", sample); |
| 109 int diff; |
| 110 if (memory_growth_tracker_ && |
| 111 memory_growth_tracker_->UpdateSample( |
| 112 browser.processes[index].pid, sample, &diff)) { |
| 113 if (diff < 0) |
| 114 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererShrinkIn30Min", -diff); |
| 115 else |
| 116 UMA_HISTOGRAM_MEMORY_KB("Memory.RendererGrowthIn30Min", diff); |
| 117 } |
| 118 renderer_count++; |
| 119 continue; |
| 120 } |
| 121 } |
| 122 case content::PROCESS_TYPE_PLUGIN: |
| 123 UMA_HISTOGRAM_MEMORY_KB("Memory.Plugin", sample); |
| 124 plugin_count++; |
| 125 continue; |
| 126 case content::PROCESS_TYPE_UTILITY: |
| 127 UMA_HISTOGRAM_MEMORY_KB("Memory.Utility", sample); |
| 128 other_count++; |
| 129 continue; |
| 130 case content::PROCESS_TYPE_ZYGOTE: |
| 131 UMA_HISTOGRAM_MEMORY_KB("Memory.Zygote", sample); |
| 132 other_count++; |
| 133 continue; |
| 134 case content::PROCESS_TYPE_SANDBOX_HELPER: |
| 135 UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); |
| 136 other_count++; |
| 137 continue; |
| 138 case content::PROCESS_TYPE_GPU: |
| 139 UMA_HISTOGRAM_MEMORY_KB("Memory.Gpu", sample); |
| 140 other_count++; |
| 141 continue; |
| 142 #if defined(ENABLE_PLUGINS) |
| 143 case content::PROCESS_TYPE_PPAPI_PLUGIN: { |
| 144 const std::vector<base::string16>& titles = |
| 145 browser.processes[index].titles; |
| 146 if (titles.size() == 1 && |
| 147 titles[0] == base::ASCIIToUTF16(content::kFlashPluginName)) { |
| 148 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperFlashPlugin", sample); |
| 149 } |
| 150 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPlugin", sample); |
| 151 pepper_plugin_count++; |
| 152 continue; |
| 153 } |
| 154 case content::PROCESS_TYPE_PPAPI_BROKER: |
| 155 UMA_HISTOGRAM_MEMORY_KB("Memory.PepperPluginBroker", sample); |
| 156 pepper_plugin_broker_count++; |
| 157 continue; |
| 158 #endif |
| 159 case PROCESS_TYPE_NACL_LOADER: |
| 160 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); |
| 161 other_count++; |
| 162 continue; |
| 163 case PROCESS_TYPE_NACL_BROKER: |
| 164 UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClientBroker", sample); |
| 165 other_count++; |
| 166 continue; |
| 167 default: |
| 168 NOTREACHED(); |
| 169 continue; |
| 170 } |
| 171 } |
| 172 #if defined(OS_CHROMEOS) |
| 173 // Chrome OS exposes system-wide graphics driver memory which has historically |
| 174 // been a source of leak/bloat. |
| 175 base::SystemMemoryInfoKB meminfo; |
| 176 if (base::GetSystemMemoryInfo(&meminfo) && meminfo.gem_size != -1) |
| 177 UMA_HISTOGRAM_MEMORY_MB("Memory.Graphics", meminfo.gem_size / 1024 / 1024); |
| 178 #endif |
| 179 |
| 180 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessLimit", process_limit); |
| 181 UMA_HISTOGRAM_COUNTS_100("Memory.ProcessCount", |
| 182 static_cast<int>(browser.processes.size())); |
| 183 UMA_HISTOGRAM_COUNTS_100("Memory.ChromeProcessCount", chrome_count); |
| 184 UMA_HISTOGRAM_COUNTS_100("Memory.ExtensionProcessCount", extension_count); |
| 185 UMA_HISTOGRAM_COUNTS_100("Memory.OtherProcessCount", other_count); |
| 186 UMA_HISTOGRAM_COUNTS_100("Memory.PluginProcessCount", plugin_count); |
| 187 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginProcessCount", |
| 188 pepper_plugin_count); |
| 189 UMA_HISTOGRAM_COUNTS_100("Memory.PepperPluginBrokerProcessCount", |
| 190 pepper_plugin_broker_count); |
| 191 UMA_HISTOGRAM_COUNTS_100("Memory.RendererProcessCount", renderer_count); |
| 192 UMA_HISTOGRAM_COUNTS_100("Memory.WorkerProcessCount", worker_count); |
| 193 // TODO(viettrungluu): Do we want separate counts for the other |
| 194 // (platform-specific) process types? |
| 195 |
| 196 int total_sample = static_cast<int>(aggregate_memory / 1000); |
| 197 UMA_HISTOGRAM_MEMORY_MB("Memory.Total", total_sample); |
| 198 |
| 199 #if defined(OS_CHROMEOS) |
| 200 UpdateSwapHistograms(); |
| 201 #endif |
| 202 } |
| 203 |
| 204 #if defined(OS_CHROMEOS) |
| 205 void MetricsMemoryDetails::UpdateSwapHistograms() { |
| 206 UMA_HISTOGRAM_BOOLEAN("Memory.Swap.HaveSwapped", swap_info().num_writes > 0); |
| 207 if (swap_info().num_writes == 0) |
| 208 return; |
| 209 |
| 210 // Only record swap info when any swaps have happened, to give us more |
| 211 // detail in the histograms. |
| 212 const ProcessData& browser = *ChromeBrowser(); |
| 213 size_t aggregate_memory = 0; |
| 214 for (size_t index = 0; index < browser.processes.size(); index++) { |
| 215 int sample = static_cast<int>(browser.processes[index].working_set.swapped); |
| 216 aggregate_memory += sample; |
| 217 switch (browser.processes[index].process_type) { |
| 218 case content::PROCESS_TYPE_BROWSER: |
| 219 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Browser", sample); |
| 220 continue; |
| 221 case content::PROCESS_TYPE_RENDERER: { |
| 222 ProcessMemoryInformation::RendererProcessType renderer_type = |
| 223 browser.processes[index].renderer_type; |
| 224 switch (renderer_type) { |
| 225 case ProcessMemoryInformation::RENDERER_EXTENSION: |
| 226 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Extension", sample); |
| 227 continue; |
| 228 case ProcessMemoryInformation::RENDERER_CHROME: |
| 229 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Chrome", sample); |
| 230 continue; |
| 231 case ProcessMemoryInformation::RENDERER_UNKNOWN: |
| 232 NOTREACHED() << "Unknown renderer process type."; |
| 233 continue; |
| 234 case ProcessMemoryInformation::RENDERER_NORMAL: |
| 235 default: |
| 236 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Renderer", sample); |
| 237 continue; |
| 238 } |
| 239 } |
| 240 case content::PROCESS_TYPE_PLUGIN: |
| 241 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Plugin", sample); |
| 242 continue; |
| 243 case content::PROCESS_TYPE_UTILITY: |
| 244 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Utility", sample); |
| 245 continue; |
| 246 case content::PROCESS_TYPE_ZYGOTE: |
| 247 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Zygote", sample); |
| 248 continue; |
| 249 case content::PROCESS_TYPE_SANDBOX_HELPER: |
| 250 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.SandboxHelper", sample); |
| 251 continue; |
| 252 case content::PROCESS_TYPE_GPU: |
| 253 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.Gpu", sample); |
| 254 continue; |
| 255 case content::PROCESS_TYPE_PPAPI_PLUGIN: |
| 256 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPlugin", sample); |
| 257 continue; |
| 258 case content::PROCESS_TYPE_PPAPI_BROKER: |
| 259 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.PepperPluginBroker", sample); |
| 260 continue; |
| 261 case PROCESS_TYPE_NACL_LOADER: |
| 262 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClient", sample); |
| 263 continue; |
| 264 case PROCESS_TYPE_NACL_BROKER: |
| 265 UMA_HISTOGRAM_MEMORY_KB("Memory.Swap.NativeClientBroker", sample); |
| 266 continue; |
| 267 default: |
| 268 NOTREACHED(); |
| 269 continue; |
| 270 } |
| 271 } |
| 272 |
| 273 int total_sample = static_cast<int>(aggregate_memory / 1000); |
| 274 UMA_HISTOGRAM_MEMORY_MB("Memory.Swap.Total", total_sample); |
| 275 |
| 276 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.CompressedDataSize", |
| 277 swap_info().compr_data_size / (1024 * 1024), 1, |
| 278 4096, 50); |
| 279 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.OriginalDataSize", |
| 280 swap_info().orig_data_size / (1024 * 1024), 1, |
| 281 4096, 50); |
| 282 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.MemUsedTotal", |
| 283 swap_info().mem_used_total / (1024 * 1024), 1, |
| 284 4096, 50); |
| 285 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumReads", swap_info().num_reads, 1, |
| 286 100000000, 100); |
| 287 UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Swap.NumWrites", swap_info().num_writes, |
| 288 1, 100000000, 100); |
| 289 |
| 290 if (swap_info().orig_data_size > 0 && swap_info().compr_data_size > 0) { |
| 291 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 292 "Memory.Swap.CompressionRatio", |
| 293 swap_info().orig_data_size / swap_info().compr_data_size, 1, 20, 20); |
| 294 } |
| 295 } |
| 296 #endif // defined(OS_CHROMEOS) |
OLD | NEW |