1 // Copyright 2013 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 <limits> 6 7 #include "base/logging.h" 8 #include "base/metrics/histogram.h" 9 #include "base/process/process_metrics.h" 10 11 #include "chrome/browser/performance_monitor/constants.h" 12 #include "chrome/browser/performance_monitor/process_metrics_history.h" 13 #if defined(OS_MACOSX) 14 #include "content/public/browser/browser_child_process_host.h" 15 #endif 16 #include "content/public/common/process_type.h" 17 18 namespace performance_monitor { 19 20 ProcessMetricsHistory::ProcessMetricsHistory() 21 : process_handle_(0), 22 process_type_(content::PROCESS_TYPE_UNKNOWN), 23 last_update_sequence_(0) { 24 ResetCounters(); 25 } 26 27 ProcessMetricsHistory::~ProcessMetricsHistory() {} 28 29 void ProcessMetricsHistory::ResetCounters() { 30 min_cpu_usage_ = std::numeric_limits<double>::max(); 31 accumulated_cpu_usage_ = 0.0; 32 accumulated_private_bytes_ = 0; 33 accumulated_shared_bytes_ = 0; 34 sample_count_ = 0; 35 } 36 37 void ProcessMetricsHistory::Initialize(base::ProcessHandle process_handle, 38 int process_type, 39 int initial_update_sequence) { 40 DCHECK(process_handle_ == 0); 41 process_handle_ = process_handle; 42 process_type_ = process_type; 43 last_update_sequence_ = initial_update_sequence; 44 45 #if defined(OS_MACOSX) 46 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics( 47 process_handle_, content::BrowserChildProcessHost::GetPortProvider())); 48 #else 49 process_metrics_.reset( 50 base::ProcessMetrics::CreateProcessMetrics(process_handle_)); 51 #endif 52 } 53 54 void ProcessMetricsHistory::SampleMetrics() { 55 double cpu_usage = process_metrics_->GetPlatformIndependentCPUUsage(); 56 min_cpu_usage_ = std::min(min_cpu_usage_, cpu_usage); 57 accumulated_cpu_usage_ += cpu_usage; 58 59 size_t private_bytes = 0; 60 size_t shared_bytes = 0; 61 if (!process_metrics_->GetMemoryBytes(&private_bytes, &shared_bytes)) 62 LOG(WARNING) << "GetMemoryBytes returned NULL (platform-specific error)"; 63 64 accumulated_private_bytes_ += private_bytes; 65 accumulated_shared_bytes_ += shared_bytes; 66 67 sample_count_++; 68 } 69 70 void ProcessMetricsHistory::EndOfCycle() { 71 RunPerformanceTriggers(); 72 ResetCounters(); 73 } 74 75 void ProcessMetricsHistory::RunPerformanceTriggers() { 76 if (sample_count_ == 0) 77 return; 78 79 // We scale up to the equivalent of 64 CPU cores fully loaded. More than this 80 // doesn't really matter, as we're already in a terrible place. 81 const int kHistogramMin = 0; 82 const int kHistogramMax = 6400; 83 const int kHistogramBucketCount = 50; 84 85 const double average_cpu_usage = accumulated_cpu_usage_ / sample_count_; 86 87 // The histogram macros don't support variables as histogram names, 88 // hence the macro duplication for each process type. 89 switch (process_type_) { 90 case content::PROCESS_TYPE_BROWSER: 91 UMA_HISTOGRAM_CUSTOM_COUNTS( 92 "PerformanceMonitor.AverageCPU.BrowserProcess", average_cpu_usage, 93 kHistogramMin, kHistogramMax, kHistogramBucketCount); 94 // If CPU usage has consistently been above our threshold, 95 // we *may* have an issue. 96 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) { 97 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.BrowserProcess", 98 true); 99 } 100 break; 101 case content::PROCESS_TYPE_RENDERER: 102 UMA_HISTOGRAM_CUSTOM_COUNTS( 103 "PerformanceMonitor.AverageCPU.RendererProcess", average_cpu_usage, 104 kHistogramMin, kHistogramMax, kHistogramBucketCount); 105 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) { 106 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.RendererProcess", 107 true); 108 } 109 break; 110 case content::PROCESS_TYPE_PLUGIN: 111 UMA_HISTOGRAM_CUSTOM_COUNTS( 112 "PerformanceMonitor.AverageCPU.PluginProcess", average_cpu_usage, 113 kHistogramMin, kHistogramMax, kHistogramBucketCount); 114 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) 115 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PluginProcess", true); 116 break; 117 case content::PROCESS_TYPE_WORKER: 118 UMA_HISTOGRAM_CUSTOM_COUNTS( 119 "PerformanceMonitor.AverageCPU.WorkerProcess", average_cpu_usage, 120 kHistogramMin, kHistogramMax, kHistogramBucketCount); 121 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) 122 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.WorkerProcess", true); 123 break; 124 case content::PROCESS_TYPE_GPU: 125 UMA_HISTOGRAM_CUSTOM_COUNTS( 126 "PerformanceMonitor.AverageCPU.GPUProcess", average_cpu_usage, 127 kHistogramMin, kHistogramMax, kHistogramBucketCount); 128 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) 129 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.GPUProcess", true); 130 break; 131 case content::PROCESS_TYPE_PPAPI_PLUGIN: 132 UMA_HISTOGRAM_CUSTOM_COUNTS( 133 "PerformanceMonitor.AverageCPU.PPAPIProcess", average_cpu_usage, 134 kHistogramMin, kHistogramMax, kHistogramBucketCount); 135 if (min_cpu_usage_ > kHighCPUUtilizationThreshold) 136 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIProcess", true); 137 break; 138 default: 139 break; 140 } 141 } 142 143 } // namespace performance_monitor 144