process_metrics_history.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
18namespace performance_monitor {
19
20ProcessMetricsHistory::ProcessMetricsHistory()
21    : process_handle_(0),
22      process_type_(content::PROCESS_TYPE_UNKNOWN),
23      last_update_sequence_(0) {
24  ResetCounters();
25}
26
27ProcessMetricsHistory::~ProcessMetricsHistory() {}
28
29void 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
37void 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
54void 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
70void ProcessMetricsHistory::EndOfCycle() {
71  RunPerformanceTriggers();
72  ResetCounters();
73}
74
75void 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