1 // Copyright (c) 2012 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/performance_monitor.h"
7 #include "base/memory/singleton.h"
8 #include "base/process/process_iterator.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "content/public/browser/browser_child_process_host.h"
12 #include "content/public/browser/browser_child_process_host_iterator.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/child_process_data.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/common/content_constants.h"
18 #if defined(ENABLE_EXTENSIONS)
19 #include "extensions/browser/extension_host.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/manifest_handlers/background_info.h"
24 using content::BrowserThread
;
28 // The default interval at which PerformanceMonitor performs its timed
30 const int kGatherIntervalInSeconds
= 120;
34 namespace performance_monitor
{
36 PerformanceMonitor::PerformanceMonitor() {
39 PerformanceMonitor::~PerformanceMonitor() {
43 PerformanceMonitor
* PerformanceMonitor::GetInstance() {
44 return base::Singleton
<PerformanceMonitor
>::get();
47 void PerformanceMonitor::StartGatherCycle() {
48 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
49 repeating_timer_
.Start(FROM_HERE
,
50 base::TimeDelta::FromSeconds(kGatherIntervalInSeconds
),
51 this, &PerformanceMonitor::GatherMetricsMapOnUIThread
);
56 void GatherMetricsForRenderProcess(content::RenderProcessHost
* host
,
57 ProcessMetricsMetadata
& data
) {
58 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
59 #if defined(ENABLE_EXTENSIONS)
60 content::BrowserContext
* browser_context
= host
->GetBrowserContext();
61 extensions::ProcessMap
* extension_process_map
=
62 extensions::ProcessMap::Get(browser_context
);
64 std::set
<std::string
> extension_ids
=
65 extension_process_map
->GetExtensionsInProcess(host
->GetID());
67 // We only collect more granular metrics when there's only one extension
68 // running in a given renderer, to reduce noise.
69 if (extension_ids
.size() != 1)
72 extensions::ExtensionRegistry
* extension_registry
=
73 extensions::ExtensionRegistry::Get(browser_context
);
75 const extensions::Extension
* extension
=
76 extension_registry
->enabled_extensions().GetByID(*extension_ids
.begin());
81 if (extensions::BackgroundInfo::HasPersistentBackgroundPage(extension
)) {
82 data
.process_subtype
= kProcessSubtypeExtensionPersistent
;
84 data
.process_subtype
= kProcessSubtypeExtensionEvent
;
91 void PerformanceMonitor::GatherMetricsMapOnUIThread() {
92 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
94 static int current_update_sequence
= 0;
95 // Even in the "somewhat" unlikely event this wraps around,
96 // it doesn't matter. We just check it for inequality.
97 current_update_sequence
++;
99 // Find all render child processes; has to be done on the UI thread.
100 for (content::RenderProcessHost::iterator rph_iter
=
101 content::RenderProcessHost::AllHostsIterator();
102 !rph_iter
.IsAtEnd(); rph_iter
.Advance()) {
103 content::RenderProcessHost
* host
= rph_iter
.GetCurrentValue();
104 ProcessMetricsMetadata data
;
105 data
.process_type
= content::PROCESS_TYPE_RENDERER
;
106 data
.handle
= host
->GetHandle();
108 GatherMetricsForRenderProcess(host
, data
);
109 MarkProcessAsAlive(data
, current_update_sequence
);
112 BrowserThread::PostTask(
113 BrowserThread::IO
, FROM_HERE
,
114 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread
,
115 base::Unretained(this), current_update_sequence
));
118 void PerformanceMonitor::MarkProcessAsAlive(
119 const ProcessMetricsMetadata
& process_data
,
120 int current_update_sequence
) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
123 const base::ProcessHandle
& handle
= process_data
.handle
;
124 if (handle
== base::kNullProcessHandle
) {
125 // Process may not be valid yet.
129 MetricsMap::iterator process_metrics_iter
= metrics_map_
.find(handle
);
130 if (process_metrics_iter
== metrics_map_
.end()) {
131 // If we're not already watching the process, let's initialize it.
132 metrics_map_
[handle
].Initialize(process_data
, current_update_sequence
);
134 // If we are watching the process, touch it to keep it alive.
135 ProcessMetricsHistory
& process_metrics
= process_metrics_iter
->second
;
136 process_metrics
.set_last_update_sequence(current_update_sequence
);
140 void PerformanceMonitor::GatherMetricsMapOnIOThread(
141 int current_update_sequence
) {
142 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
144 scoped_ptr
<std::vector
<ProcessMetricsMetadata
>> process_data_list(
145 new std::vector
<ProcessMetricsMetadata
>());
147 // Find all child processes (does not include renderers), which has to be
148 // done on the IO thread.
149 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
150 ProcessMetricsMetadata child_process_data
;
151 child_process_data
.handle
= iter
.GetData().handle
;
152 child_process_data
.process_type
= iter
.GetData().process_type
;
154 if (iter
.GetData().name
== base::ASCIIToUTF16(content::kFlashPluginName
)) {
155 child_process_data
.process_subtype
= kProcessSubtypePPAPIFlash
;
158 process_data_list
->push_back(child_process_data
);
161 // Add the current (browser) process.
162 ProcessMetricsMetadata browser_process_data
;
163 browser_process_data
.process_type
= content::PROCESS_TYPE_BROWSER
;
164 browser_process_data
.handle
= base::GetCurrentProcessHandle();
165 process_data_list
->push_back(browser_process_data
);
167 BrowserThread::PostTask(
168 BrowserThread::UI
, FROM_HERE
,
169 base::Bind(&PerformanceMonitor::MarkProcessesAsAliveOnUIThread
,
170 base::Unretained(this), base::Passed(process_data_list
.Pass()),
171 current_update_sequence
));
174 void PerformanceMonitor::MarkProcessesAsAliveOnUIThread(
175 scoped_ptr
<std::vector
<ProcessMetricsMetadata
>> process_data_list
,
176 int current_update_sequence
) {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
178 for (size_t i
= 0; i
< process_data_list
->size(); ++i
) {
179 MarkProcessAsAlive((*process_data_list
)[i
], current_update_sequence
);
182 BrowserThread::PostTask(
183 BrowserThread::IO
, FROM_HERE
,
184 base::Bind(&PerformanceMonitor::UpdateMetricsOnIOThread
,
185 base::Unretained(this), current_update_sequence
));
188 void PerformanceMonitor::UpdateMetricsOnIOThread(int current_update_sequence
) {
189 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
190 // Update metrics for all watched processes; remove dead entries from the map.
191 MetricsMap::iterator iter
= metrics_map_
.begin();
192 while (iter
!= metrics_map_
.end()) {
193 ProcessMetricsHistory
& process_metrics
= iter
->second
;
194 if (process_metrics
.last_update_sequence() != current_update_sequence
) {
195 // Not touched this iteration; let's get rid of it.
196 metrics_map_
.erase(iter
++);
198 process_metrics
.SampleMetrics();
203 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
204 base::Bind(&PerformanceMonitor::RunTriggersUIThread
,
205 base::Unretained(this)));
208 void PerformanceMonitor::RunTriggersUIThread() {
209 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
210 for (auto it
= metrics_map_
.begin(); it
!= metrics_map_
.end(); ++it
) {
211 it
->second
.RunPerformanceTriggers();
217 } // namespace performance_monitor