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 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 const base::ProcessHandle
& handle
= process_data
.handle
;
122 if (handle
== base::kNullProcessHandle
) {
123 // Process may not be valid yet.
127 MetricsMap::iterator process_metrics_iter
= metrics_map_
.find(handle
);
128 if (process_metrics_iter
== metrics_map_
.end()) {
129 // If we're not already watching the process, let's initialize it.
130 metrics_map_
[handle
].Initialize(process_data
, current_update_sequence
);
132 // If we are watching the process, touch it to keep it alive.
133 ProcessMetricsHistory
& process_metrics
= process_metrics_iter
->second
;
134 process_metrics
.set_last_update_sequence(current_update_sequence
);
138 void PerformanceMonitor::GatherMetricsMapOnIOThread(
139 int current_update_sequence
) {
140 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
142 // Find all child processes (does not include renderers), which has to be
143 // done on the IO thread.
144 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
145 ProcessMetricsMetadata child_process_data
;
146 child_process_data
.handle
= iter
.GetData().handle
;
147 child_process_data
.process_type
= iter
.GetData().process_type
;
149 if (iter
.GetData().name
== base::ASCIIToUTF16(content::kFlashPluginName
)) {
150 child_process_data
.process_subtype
= kProcessSubtypePPAPIFlash
;
153 MarkProcessAsAlive(child_process_data
, current_update_sequence
);
156 // Add the current (browser) process.
157 ProcessMetricsMetadata browser_process_data
;
158 browser_process_data
.process_type
= content::PROCESS_TYPE_BROWSER
;
159 browser_process_data
.handle
= base::GetCurrentProcessHandle();
160 MarkProcessAsAlive(browser_process_data
, current_update_sequence
);
162 // Update metrics for all watched processes; remove dead entries from the map.
163 MetricsMap::iterator iter
= metrics_map_
.begin();
164 while (iter
!= metrics_map_
.end()) {
165 ProcessMetricsHistory
& process_metrics
= iter
->second
;
166 if (process_metrics
.last_update_sequence() != current_update_sequence
) {
167 // Not touched this iteration; let's get rid of it.
168 metrics_map_
.erase(iter
++);
170 process_metrics
.SampleMetrics();
176 } // namespace performance_monitor