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.
5 #include "chrome/browser/performance_monitor/process_metrics_history.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/process/process_metrics.h"
12 #include "content/public/common/process_type.h"
14 #if defined(OS_MACOSX)
15 #include "content/public/browser/browser_child_process_host.h"
18 namespace performance_monitor
{
22 const char kBrowserProcessTrigger
[] =
23 "ProcessMetricsHistory.BrowserProcess.HighCPU";
24 const char kGPUProcessTrigger
[] = "ProcessMetricsHistory.GPUProcess.HighCPU";
25 const char kExtensionPersistentProcessTrigger
[] =
26 "ProcessMetricsHistory.ExtensionPersistentProcess.HighCPU";
30 // If a process is consistently above this CPU utilization percentage over time,
31 // we consider it as high and may take action.
32 const float kHighCPUUtilizationThreshold
= 90.0f
;
34 ProcessMetricsHistory::ProcessMetricsHistory()
35 : last_update_sequence_(0), cpu_usage_(0.0), trace_trigger_handle_(-1) {
38 ProcessMetricsHistory::~ProcessMetricsHistory() {
41 void ProcessMetricsHistory::Initialize(
42 const ProcessMetricsMetadata
& process_data
,
43 int initial_update_sequence
) {
44 DCHECK_EQ(base::kNullProcessHandle
, process_data_
.handle
);
45 process_data_
= process_data
;
46 last_update_sequence_
= initial_update_sequence
;
48 #if defined(OS_MACOSX)
49 process_metrics_
.reset(base::ProcessMetrics::CreateProcessMetrics(
51 content::BrowserChildProcessHost::GetPortProvider()));
53 process_metrics_
.reset(
54 base::ProcessMetrics::CreateProcessMetrics(process_data_
.handle
));
57 const char* trigger_name
= NULL
;
58 switch (process_data_
.process_type
) {
59 case content::PROCESS_TYPE_BROWSER
:
60 trigger_name
= kBrowserProcessTrigger
;
62 case content::PROCESS_TYPE_GPU
:
63 trigger_name
= kGPUProcessTrigger
;
66 switch (process_data_
.process_subtype
) {
67 case kProcessSubtypeExtensionPersistent
:
68 trigger_name
= kExtensionPersistentProcessTrigger
;
74 trace_trigger_handle_
=
75 content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
80 void ProcessMetricsHistory::SampleMetrics() {
81 cpu_usage_
= process_metrics_
->GetPlatformIndependentCPUUsage();
84 void ProcessMetricsHistory::RunPerformanceTriggers() {
85 // We scale up to the equivalent of 64 CPU cores fully loaded. More than this
86 // doesn't really matter, as we're already in a terrible place.
87 const int kHistogramMin
= 0;
88 const int kHistogramMax
= 6400;
89 const int kHistogramBucketCount
= 50;
91 // The histogram macros don't support variables as histogram names,
92 // hence the macro duplication for each process type.
93 switch (process_data_
.process_type
) {
94 case content::PROCESS_TYPE_BROWSER
:
95 UMA_HISTOGRAM_CUSTOM_COUNTS(
96 "PerformanceMonitor.AverageCPU.BrowserProcess", cpu_usage_
,
97 kHistogramMin
, kHistogramMax
, kHistogramBucketCount
);
98 // If CPU usage has consistently been above our threshold,
99 // we *may* have an issue.
100 if (cpu_usage_
> kHighCPUUtilizationThreshold
) {
101 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.BrowserProcess",
105 case content::PROCESS_TYPE_RENDERER
:
106 UMA_HISTOGRAM_CUSTOM_COUNTS(
107 "PerformanceMonitor.AverageCPU.RendererProcess", cpu_usage_
,
108 kHistogramMin
, kHistogramMax
, kHistogramBucketCount
);
109 if (cpu_usage_
> kHighCPUUtilizationThreshold
) {
110 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.RendererProcess",
114 case content::PROCESS_TYPE_PLUGIN
:
115 UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.PluginProcess",
116 cpu_usage_
, kHistogramMin
, kHistogramMax
,
117 kHistogramBucketCount
);
118 if (cpu_usage_
> kHighCPUUtilizationThreshold
)
119 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PluginProcess", true);
121 case content::PROCESS_TYPE_GPU
:
122 UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.GPUProcess",
123 cpu_usage_
, kHistogramMin
, kHistogramMax
,
124 kHistogramBucketCount
);
125 if (cpu_usage_
> kHighCPUUtilizationThreshold
)
126 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.GPUProcess", true);
128 case content::PROCESS_TYPE_PPAPI_PLUGIN
:
129 UMA_HISTOGRAM_CUSTOM_COUNTS("PerformanceMonitor.AverageCPU.PPAPIProcess",
130 cpu_usage_
, kHistogramMin
, kHistogramMax
,
131 kHistogramBucketCount
);
132 if (cpu_usage_
> kHighCPUUtilizationThreshold
)
133 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIProcess", true);
139 switch (process_data_
.process_subtype
) {
140 case kProcessSubtypeUnknown
:
142 case kProcessSubtypePPAPIFlash
:
143 UMA_HISTOGRAM_CUSTOM_COUNTS(
144 "PerformanceMonitor.AverageCPU.PPAPIFlashProcess", cpu_usage_
,
145 kHistogramMin
, kHistogramMax
, kHistogramBucketCount
);
146 if (cpu_usage_
> kHighCPUUtilizationThreshold
) {
147 UMA_HISTOGRAM_BOOLEAN("PerformanceMonitor.HighCPU.PPAPIFlashProcess",
151 case kProcessSubtypeExtensionPersistent
:
152 UMA_HISTOGRAM_CUSTOM_COUNTS(
153 "PerformanceMonitor.AverageCPU.RendererExtensionPersistentProcess",
154 cpu_usage_
, kHistogramMin
, kHistogramMax
, kHistogramBucketCount
);
155 if (cpu_usage_
> kHighCPUUtilizationThreshold
) {
156 UMA_HISTOGRAM_BOOLEAN(
157 "PerformanceMonitor.HighCPU.RendererExtensionPersistentProcess",
161 case kProcessSubtypeExtensionEvent
:
162 UMA_HISTOGRAM_CUSTOM_COUNTS(
163 "PerformanceMonitor.AverageCPU.RendererExtensionEventProcess",
164 cpu_usage_
, kHistogramMin
, kHistogramMax
, kHistogramBucketCount
);
165 if (cpu_usage_
> kHighCPUUtilizationThreshold
) {
166 UMA_HISTOGRAM_BOOLEAN(
167 "PerformanceMonitor.HighCPU.RendererExtensionEventProcess", true);
172 if (cpu_usage_
> kHighCPUUtilizationThreshold
&&
173 trace_trigger_handle_
!= -1) {
174 content::BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
175 trace_trigger_handle_
,
176 content::BackgroundTracingManager::StartedFinalizingCallback());
180 } // namespace performance_monitor