• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ProcessMetricsHistory()20 ProcessMetricsHistory::ProcessMetricsHistory()
21     : process_handle_(0),
22       process_type_(content::PROCESS_TYPE_UNKNOWN),
23       last_update_sequence_(0) {
24   ResetCounters();
25 }
26 
~ProcessMetricsHistory()27 ProcessMetricsHistory::~ProcessMetricsHistory() {}
28 
ResetCounters()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 
Initialize(base::ProcessHandle process_handle,int process_type,int initial_update_sequence)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 
SampleMetrics()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 
EndOfCycle()70 void ProcessMetricsHistory::EndOfCycle() {
71   RunPerformanceTriggers();
72   ResetCounters();
73 }
74 
RunPerformanceTriggers()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