Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: chrome/browser/performance_monitor/performance_monitor.cc

Issue 23825004: PerformanceMonitor: UMA alert for high browser CPU usage. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/performance_monitor/performance_monitor.h" 5 #include "chrome/browser/performance_monitor/performance_monitor.h"
6 6
7 #include <set> 7 #include <set>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
13 #include "base/process/process_iterator.h" 14 #include "base/process/process_iterator.h"
14 #include "base/stl_util.h" 15 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
16 #include "base/threading/worker_pool.h" 17 #include "base/threading/worker_pool.h"
17 #include "base/time/time.h" 18 #include "base/time/time.h"
18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/browser_shutdown.h" 20 #include "chrome/browser/browser_shutdown.h"
20 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/extensions/crx_installer.h" 22 #include "chrome/browser/extensions/crx_installer.h"
22 #include "chrome/browser/performance_monitor/constants.h" 23 #include "chrome/browser/performance_monitor/constants.h"
23 #include "chrome/browser/performance_monitor/performance_monitor_util.h" 24 #include "chrome/browser/performance_monitor/performance_monitor_util.h"
24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_manager.h" 26 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/ui/browser.h" 27 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_iterator.h" 28 #include "chrome/browser/ui/browser_iterator.h"
28 #include "chrome/common/chrome_switches.h" 29 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/chrome_version_info.h" 30 #include "chrome/common/chrome_version_info.h"
30 #include "chrome/common/extensions/extension.h" 31 #include "chrome/common/extensions/extension.h"
31 #include "chrome/common/extensions/extension_constants.h" 32 #include "chrome/common/extensions/extension_constants.h"
32 #include "chrome/test/base/chrome_process_util.h"
33 #include "content/public/browser/browser_child_process_host.h" 33 #include "content/public/browser/browser_child_process_host.h"
34 #include "content/public/browser/browser_child_process_host_iterator.h"
34 #include "content/public/browser/browser_thread.h" 35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/child_process_data.h"
35 #include "content/public/browser/load_notification_details.h" 37 #include "content/public/browser/load_notification_details.h"
36 #include "content/public/browser/notification_service.h" 38 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_types.h" 39 #include "content/public/browser/notification_types.h"
38 #include "content/public/browser/render_view_host.h" 40 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/render_widget_host.h" 41 #include "content/public/browser/render_widget_host.h"
40 #include "content/public/browser/render_widget_host_iterator.h" 42 #include "content/public/browser/render_widget_host_iterator.h"
41 #include "content/public/browser/web_contents.h" 43 #include "content/public/browser/web_contents.h"
42 #include "net/url_request/url_request.h" 44 #include "net/url_request/url_request.h"
43 45
44 using content::BrowserThread; 46 using content::BrowserThread;
45 using extensions::Extension; 47 using extensions::Extension;
46 48
47 namespace performance_monitor { 49 namespace performance_monitor {
48 50
49 namespace { 51 namespace {
50 52
51 const uint32 kAccessFlags = base::kProcessAccessDuplicateHandle | 53 const uint32 kAccessFlags = base::kProcessAccessDuplicateHandle |
52 base::kProcessAccessQueryInformation | 54 base::kProcessAccessQueryInformation |
53 base::kProcessAccessTerminate | 55 base::kProcessAccessTerminate |
54 base::kProcessAccessWaitForTermination; 56 base::kProcessAccessWaitForTermination;
55 57
56 bool g_started_initialization = false;
57
58 std::string TimeToString(base::Time time) { 58 std::string TimeToString(base::Time time) {
59 int64 time_int64 = time.ToInternalValue(); 59 int64 time_int64 = time.ToInternalValue();
60 return base::Int64ToString(time_int64); 60 return base::Int64ToString(time_int64);
61 } 61 }
62 62
63 bool StringToTime(std::string time, base::Time* output) { 63 bool StringToTime(std::string time, base::Time* output) {
64 int64 time_int64 = 0; 64 int64 time_int64 = 0;
65 if (!base::StringToInt64(time, &time_int64)) 65 if (!base::StringToInt64(time, &time_int64))
66 return false; 66 return false;
67 *output = base::Time::FromInternalValue(time_int64); 67 *output = base::Time::FromInternalValue(time_int64);
(...skipping 24 matching lines...) Expand all
92 } 92 }
93 93
94 } // namespace 94 } // namespace
95 95
96 bool PerformanceMonitor::initialized_ = false; 96 bool PerformanceMonitor::initialized_ = false;
97 97
98 PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread() 98 PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread()
99 : network_bytes_read(0) { 99 : network_bytes_read(0) {
100 } 100 }
101 101
102 PerformanceMonitor::PerformanceMonitor() : metrics_map_(new MetricsMap) {} 102 PerformanceMonitor::PerformanceMonitor()
103 : gather_interval_in_seconds_(kDefaultGatherIntervalInSeconds),
104 database_logging_enabled_(false),
105 timer_(FROM_HERE,
106 base::TimeDelta::FromSeconds(kSampleIntervalInSeconds),
107 this,
108 &PerformanceMonitor::DoTimedCollections),
109 disable_timer_autostart_for_testing_(false) {
110 }
103 111
104 PerformanceMonitor::~PerformanceMonitor() { 112 PerformanceMonitor::~PerformanceMonitor() {
105 BrowserThread::PostBlockingPoolSequencedTask( 113 BrowserThread::PostBlockingPoolSequencedTask(
106 Database::kDatabaseSequenceToken, 114 Database::kDatabaseSequenceToken,
107 FROM_HERE, 115 FROM_HERE,
108 base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release())); 116 base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release()));
109 } 117 }
110 118
111 bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) { 119 bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) {
112 if (!database_.get()) { 120 if (!database_.get()) {
113 database_path_ = path; 121 database_path_ = path;
114 return true; 122 return true;
115 } 123 }
116 124
117 // PerformanceMonitor already initialized with another path. 125 // PerformanceMonitor already initialized with another path.
118 return false; 126 return false;
119 } 127 }
120 128
121 // static 129 // static
122 PerformanceMonitor* PerformanceMonitor::GetInstance() { 130 PerformanceMonitor* PerformanceMonitor::GetInstance() {
123 return Singleton<PerformanceMonitor>::get(); 131 return Singleton<PerformanceMonitor>::get();
124 } 132 }
125 133
126 void PerformanceMonitor::Start() { 134 void PerformanceMonitor::Start() {
127 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 135 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128 136
129 // Avoid responding to multiple calls to Start(). 137 static bool has_initialized = false;
130 if (g_started_initialization) 138 if (has_initialized) {
139 NOTREACHED();
131 return; 140 return;
141 }
142 has_initialized = true;
132 143
133 g_started_initialization = true; 144 if (CommandLine::ForCurrentProcess()->HasSwitch(
145 switches::kPerformanceMonitorGathering)) {
146 database_logging_enabled_ = true;
147
148 std::string switch_value = CommandLine::ForCurrentProcess()->
149 GetSwitchValueASCII(switches::kPerformanceMonitorGathering);
150
151 if (!switch_value.empty()) {
152 int specified_interval = 0;
153 if (!base::StringToInt(switch_value, &specified_interval) ||
154 specified_interval <= 0) {
155 LOG(ERROR) << "Invalid value for switch: '"
156 << switches::kPerformanceMonitorGathering
157 << "'; please use an integer greater than 0.";
158 } else {
159 gather_interval_in_seconds_ = std::max(specified_interval,
160 kSampleIntervalInSeconds);
161 }
162 }
163 }
164
165 DCHECK(gather_interval_in_seconds_ >= kSampleIntervalInSeconds);
166
167 next_collection_time_ = base::Time::Now() +
168 base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
169
134 util::PostTaskToDatabaseThreadAndReply( 170 util::PostTaskToDatabaseThreadAndReply(
135 FROM_HERE, 171 FROM_HERE,
136 base::Bind(&PerformanceMonitor::InitOnBackgroundThread, 172 base::Bind(&PerformanceMonitor::InitOnBackgroundThread,
137 base::Unretained(this)), 173 base::Unretained(this)),
138 base::Bind(&PerformanceMonitor::FinishInit, 174 base::Bind(&PerformanceMonitor::FinishInit,
139 base::Unretained(this))); 175 base::Unretained(this)));
140 } 176 }
141 177
142 void PerformanceMonitor::InitOnBackgroundThread() { 178 void PerformanceMonitor::InitOnBackgroundThread() {
143 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 179 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
144 database_ = Database::Create(database_path_);
145 if (!database_) {
146 LOG(ERROR) << "Could not initialize database; aborting initialization.";
147 return;
148 }
149 180
150 // Initialize the io thread's performance data to the value in the database; 181 if (database_logging_enabled_) {
151 // if there isn't a recording in the database, the value stays at 0. 182 database_ = Database::Create(database_path_);
152 Metric metric; 183 if (!database_) {
153 if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ, 184 LOG(ERROR) << "Could not initialize database; aborting initialization.";
154 &metric)) { 185 database_logging_enabled_ = false;
155 performance_data_for_io_thread_.network_bytes_read = metric.value; 186 return;
187 }
188
189 // Initialize the io thread's performance data to the value in the database;
190 // if there isn't a recording in the database, the value stays at 0.
191 Metric metric;
192 if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ,
193 &metric)) {
194 performance_data_for_io_thread_.network_bytes_read = metric.value;
195 }
156 } 196 }
157 } 197 }
158 198
159 void PerformanceMonitor::FinishInit() { 199 void PerformanceMonitor::FinishInit() {
160 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 200 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161 // Short-circuit the initialization process if the database wasn't properly
162 // created. This will prevent PerformanceMonitor from performing any actions,
163 // including observing events.
164 if (!database_)
165 return;
166 201
167 RegisterForNotifications(); 202 // Events and notifications are only useful if we're logging to the database.
168 CheckForUncleanExits(); 203 if (database_logging_enabled_) {
169 BrowserThread::PostBlockingPoolSequencedTask( 204 RegisterForNotifications();
170 Database::kDatabaseSequenceToken, 205 CheckForUncleanExits();
171 FROM_HERE, 206 BrowserThread::PostBlockingPoolSequencedTask(
172 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, 207 Database::kDatabaseSequenceToken,
173 base::Unretained(this))); 208 FROM_HERE,
174 209 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread,
175 int gather_interval_in_seconds = kDefaultGatherIntervalInSeconds; 210 base::Unretained(this)));
176 if (CommandLine::ForCurrentProcess()->HasSwitch(
177 switches::kPerformanceMonitorGathering) &&
178 !CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
179 switches::kPerformanceMonitorGathering).empty()) {
180 int specified_interval = 0;
181 if (!base::StringToInt(
182 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
183 switches::kPerformanceMonitorGathering),
184 &specified_interval) || specified_interval <= 0) {
185 LOG(ERROR) << "Invalid value for switch: '"
186 << switches::kPerformanceMonitorGathering
187 << "'; please use an integer greater than 0.";
188 } else {
189 gather_interval_in_seconds = specified_interval;
190 }
191 } 211 }
192 212
193 timer_.Start(FROM_HERE, 213 // Start our periodic gathering of metrics.
194 base::TimeDelta::FromSeconds(gather_interval_in_seconds), 214 if (!disable_timer_autostart_for_testing_)
195 this, 215 timer_.Reset();
196 &PerformanceMonitor::DoTimedCollections);
197 216
198 // Post a task to the background thread to a function which does nothing. 217 // Post a task to the background thread to a function which does nothing.
199 // This will force any tasks the database is performing to finish prior to 218 // This will force any tasks the database is performing to finish prior to
200 // the reply being sent, since they use the same thread. 219 // the reply being sent, since they use the same thread.
201 // 220 //
202 // Important! Make sure that methods in FinishInit() only rely on posting 221 // Important! Make sure that methods in FinishInit() only rely on posting
203 // to the background thread, and do not rely upon a reply from the background 222 // to the background thread, and do not rely upon a reply from the background
204 // thread; this is necessary for this notification to be valid. 223 // thread; this is necessary for this notification to be valid.
205 util::PostTaskToDatabaseThreadAndReply( 224 util::PostTaskToDatabaseThreadAndReply(
206 FROM_HERE, 225 FROM_HERE,
207 base::Bind(&base::DoNothing), 226 base::Bind(&base::DoNothing),
208 base::Bind(&PerformanceMonitor::NotifyInitialized, 227 base::Bind(&PerformanceMonitor::NotifyInitialized,
209 base::Unretained(this))); 228 base::Unretained(this)));
210 } 229 }
211 230
212 void PerformanceMonitor::RegisterForNotifications() { 231 void PerformanceMonitor::RegisterForNotifications() {
232 DCHECK(database_logging_enabled_);
233
213 // Extensions 234 // Extensions
214 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 235 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
215 content::NotificationService::AllSources()); 236 content::NotificationService::AllSources());
216 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 237 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
217 content::NotificationService::AllSources()); 238 content::NotificationService::AllSources());
218 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 239 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
219 content::NotificationService::AllSources()); 240 content::NotificationService::AllSources());
220 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, 241 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
221 content::NotificationService::AllSources()); 242 content::NotificationService::AllSources());
222 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 243 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
(...skipping 11 matching lines...) Expand all
234 255
235 // Page load times 256 // Page load times
236 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 257 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
237 content::NotificationService::AllSources()); 258 content::NotificationService::AllSources());
238 } 259 }
239 260
240 // We check if profiles exited cleanly initialization time in case they were 261 // We check if profiles exited cleanly initialization time in case they were
241 // loaded prior to PerformanceMonitor's initialization. Later profiles will be 262 // loaded prior to PerformanceMonitor's initialization. Later profiles will be
242 // checked through the PROFILE_ADDED notification. 263 // checked through the PROFILE_ADDED notification.
243 void PerformanceMonitor::CheckForUncleanExits() { 264 void PerformanceMonitor::CheckForUncleanExits() {
265 DCHECK(database_logging_enabled_);
266
244 std::vector<Profile*> profiles = 267 std::vector<Profile*> profiles =
245 g_browser_process->profile_manager()->GetLoadedProfiles(); 268 g_browser_process->profile_manager()->GetLoadedProfiles();
246 269
247 for (std::vector<Profile*>::const_iterator iter = profiles.begin(); 270 for (std::vector<Profile*>::const_iterator iter = profiles.begin();
248 iter != profiles.end(); ++iter) { 271 iter != profiles.end(); ++iter) {
249 if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) { 272 if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) {
250 BrowserThread::PostBlockingPoolSequencedTask( 273 BrowserThread::PostBlockingPoolSequencedTask(
251 Database::kDatabaseSequenceToken, 274 Database::kDatabaseSequenceToken,
252 FROM_HERE, 275 FROM_HERE,
253 base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread, 276 base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread,
254 base::Unretained(this), 277 base::Unretained(this),
255 (*iter)->GetDebugName())); 278 (*iter)->GetDebugName()));
256 } 279 }
257 } 280 }
258 } 281 }
259 282
260 void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread( 283 void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread(
261 const std::string& profile_name) { 284 const std::string& profile_name) {
285 DCHECK(database_logging_enabled_);
262 std::string database_key = kStateProfilePrefix + profile_name; 286 std::string database_key = kStateProfilePrefix + profile_name;
263 std::string last_active_string = database_->GetStateValue(database_key); 287 std::string last_active_string = database_->GetStateValue(database_key);
264 288
265 // Check if there was no previous time; this should only happen if the profile 289 // Check if there was no previous time; this should only happen if the profile
266 // was last used prior to PerformanceMonitor's integration. Do nothing in this 290 // was last used prior to PerformanceMonitor's integration. Do nothing in this
267 // case, since the event was prior to the beginning of our recording. 291 // case, since the event was prior to the beginning of our recording.
268 if (last_active_string.empty()) 292 if (last_active_string.empty())
269 return; 293 return;
270 294
271 base::Time last_active_time; 295 base::Time last_active_time;
272 CHECK(StringToTime(last_active_string, &last_active_time)); 296 CHECK(StringToTime(last_active_string, &last_active_time));
273 297
274 scoped_ptr<Event> event = 298 scoped_ptr<Event> event =
275 util::CreateUncleanExitEvent(last_active_time, profile_name); 299 util::CreateUncleanExitEvent(last_active_time, profile_name);
276 300
277 database_->AddEvent(*event.get()); 301 database_->AddEvent(*event.get());
278 } 302 }
279 303
280 void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() { 304 void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() {
281 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 305 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
306 DCHECK(database_logging_enabled_);
282 307
283 chrome::VersionInfo version; 308 chrome::VersionInfo version;
284 DCHECK(version.is_valid()); 309 DCHECK(version.is_valid());
285 std::string current_version = version.Version(); 310 std::string current_version = version.Version();
286 311
287 std::string previous_version = database_->GetStateValue(kStateChromeVersion); 312 std::string previous_version = database_->GetStateValue(kStateChromeVersion);
288 313
289 // We should never have a current_version which is older than the 314 // We should never have a current_version which is older than the
290 // previous_version. 315 // previous_version.
291 DCHECK(current_version >= previous_version); 316 DCHECK(current_version >= previous_version);
292 317
293 // If this is the first run, there will not be a stored value for Chrome 318 // If this is the first run, there will not be a stored value for Chrome
294 // version; we insert the current version and will insert an event for the 319 // version; we insert the current version and will insert an event for the
295 // next update of Chrome. If the previous version is older than the current 320 // next update of Chrome. If the previous version is older than the current
296 // version, update the state in the database and insert an event. 321 // version, update the state in the database and insert an event.
297 if (current_version > previous_version) { 322 if (current_version > previous_version) {
298 database_->AddStateValue(kStateChromeVersion, current_version); 323 database_->AddStateValue(kStateChromeVersion, current_version);
299 if (!previous_version.empty()) { 324 if (!previous_version.empty()) {
300 scoped_ptr<Event> event = util::CreateChromeUpdateEvent( 325 scoped_ptr<Event> event = util::CreateChromeUpdateEvent(
301 base::Time::Now(), previous_version, current_version); 326 base::Time::Now(), previous_version, current_version);
302 database_->AddEvent(*event.get()); 327 database_->AddEvent(*event.get());
303 } 328 }
304 } 329 }
305 } 330 }
306 331
307 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) { 332 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) {
333 DCHECK(database_logging_enabled_);
334
308 BrowserThread::PostBlockingPoolSequencedTask( 335 BrowserThread::PostBlockingPoolSequencedTask(
309 Database::kDatabaseSequenceToken, 336 Database::kDatabaseSequenceToken,
310 FROM_HERE, 337 FROM_HERE,
311 base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread, 338 base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread,
312 base::Unretained(this), 339 base::Unretained(this),
313 base::Passed(&event))); 340 base::Passed(&event)));
314 } 341 }
315 342
316 void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) { 343 void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) {
317 database_->AddEvent(*event.get()); 344 database_->AddEvent(*event.get());
318 } 345 }
319 346
320 void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) { 347 void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) {
321 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 348 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
349 DCHECK(database_logging_enabled_);
350
322 database_->AddMetric(metric); 351 database_->AddMetric(metric);
323 } 352 }
324 353
325 void PerformanceMonitor::NotifyInitialized() { 354 void PerformanceMonitor::NotifyInitialized() {
326 content::NotificationService::current()->Notify( 355 content::NotificationService::current()->Notify(
327 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, 356 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
328 content::Source<PerformanceMonitor>(this), 357 content::Source<PerformanceMonitor>(this),
329 content::NotificationService::NoDetails()); 358 content::NotificationService::NoDetails());
330 359
331 initialized_ = true; 360 initialized_ = true;
332 } 361 }
333 362
334 void PerformanceMonitor::GatherStatisticsOnBackgroundThread() { 363 void PerformanceMonitor::DoTimedCollections() {
335 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 364 #if !defined(OS_ANDROID)
365 // The profile list is only useful for the logged events.
366 if (database_logging_enabled_)
367 UpdateLiveProfiles();
368 #endif
336 369
337 // Because the CPU usage is gathered as an average since the last time the 370 GatherMetricsMapOnUIThread();
338 // function was called, while the memory usage is gathered as an instantaneous
339 // usage, the CPU usage is gathered before the metrics map is wiped.
340 GatherCPUUsageOnBackgroundThread();
341 UpdateMetricsMapOnBackgroundThread();
342 GatherMemoryUsageOnBackgroundThread();
343 } 371 }
344 372
345 void PerformanceMonitor::GatherCPUUsageOnBackgroundThread() { 373 void PerformanceMonitor::GatherMetricsMapOnUIThread() {
346 if (metrics_map_->size()) { 374 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
347 double cpu_usage = 0; 375 static int current_update_sequence = 0;
348 for (MetricsMap::const_iterator iter = metrics_map_->begin(); 376 // Even in the "somewhat" unlikely event this wraps around,
349 iter != metrics_map_->end(); ++iter) { 377 // it doesn't matter. We just check it for inequality.
350 cpu_usage += iter->second->GetCPUUsage(); 378 current_update_sequence++;
351 }
352 379
353 database_->AddMetric(Metric(METRIC_CPU_USAGE, 380 // Find all render child processes; has to be done on the UI thread.
354 base::Time::Now(), 381 for (content::RenderProcessHost::iterator rph_iter =
355 cpu_usage)); 382 content::RenderProcessHost::AllHostsIterator();
383 !rph_iter.IsAtEnd(); rph_iter.Advance()) {
384 base::ProcessHandle handle = rph_iter.GetCurrentValue()->GetHandle();
385 MarkProcessAsAlive(handle, content::PROCESS_TYPE_RENDERER,
386 current_update_sequence);
387 }
388
389 BrowserThread::PostTask(
390 BrowserThread::IO,
391 FROM_HERE,
392 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread,
393 base::Unretained(this),
394 current_update_sequence));
395 }
396
397 void PerformanceMonitor::MarkProcessAsAlive(const base::ProcessHandle& handle,
398 int process_type,
399 int current_update_sequence) {
400
401 if (handle == 0) {
402 // Process may not be valid yet.
403 return;
404 }
405
406 MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
407 if (process_metrics_iter == metrics_map_.end()) {
408 // If we're not already watching the process, let's initialize it.
409 metrics_map_[handle]
410 .Initialize(handle, process_type, current_update_sequence);
411 } else {
412 // If we are watching the process, touch it to keep it alive.
413 ProcessMetricsHistory& process_metrics = process_metrics_iter->second;
414 process_metrics.set_last_update_sequence(current_update_sequence);
356 } 415 }
357 } 416 }
358 417
359 void PerformanceMonitor::GatherMemoryUsageOnBackgroundThread() { 418 #if !defined(OS_ANDROID)
360 size_t private_memory_sum = 0;
361 size_t shared_memory_sum = 0;
362 for (MetricsMap::const_iterator iter = metrics_map_->begin();
363 iter != metrics_map_->end(); ++iter) {
364 size_t private_memory = 0;
365 size_t shared_memory = 0;
366 if (iter->second->GetMemoryBytes(&private_memory, &shared_memory)) {
367 private_memory_sum += private_memory;
368 shared_memory_sum += shared_memory;
369 } else {
370 LOG(WARNING) << "GetMemoryBytes returned NULL (platform-specific error)";
371 }
372 }
373
374 database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
375 base::Time::Now(),
376 static_cast<double>(private_memory_sum)));
377 database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
378 base::Time::Now(),
379 static_cast<double>(shared_memory_sum)));
380 }
381
382 void PerformanceMonitor::UpdateMetricsMapOnBackgroundThread() {
383 MetricsMap* new_map = new MetricsMap;
384
385 base::ProcessId browser_pid = base::GetCurrentProcId();
386 ChromeProcessList chrome_processes(GetRunningChromeProcesses(browser_pid));
387 for (ChromeProcessList::const_iterator pid_iter = chrome_processes.begin();
388 pid_iter != chrome_processes.end(); ++pid_iter) {
389 base::ProcessHandle handle;
390 if (base::OpenProcessHandleWithAccess(*pid_iter, kAccessFlags, &handle)) {
391 // If we were already watching this process, transfer it to the new map.
392 if (ContainsKey(*metrics_map_, handle)) {
393 (*new_map)[handle] = (*metrics_map_)[handle];
394 continue;
395 }
396
397 // Otherwise, gather information and prime the CPU usage to be gathered.
398 #if defined (OS_MACOSX)
399 linked_ptr<base::ProcessMetrics> process_metrics(
400 base::ProcessMetrics::CreateProcessMetrics(
401 handle, content::BrowserChildProcessHost::GetPortProvider()));
402 #else
403 linked_ptr<base::ProcessMetrics> process_metrics(
404 base::ProcessMetrics::CreateProcessMetrics(handle));
405 #endif
406
407 process_metrics->GetCPUUsage();
408
409 (*new_map)[handle] = process_metrics;
410 }
411 }
412
413 metrics_map_.reset(new_map);
414 }
415
416 void PerformanceMonitor::UpdateLiveProfiles() { 419 void PerformanceMonitor::UpdateLiveProfiles() {
417 std::string time = TimeToString(base::Time::Now()); 420 std::string time = TimeToString(base::Time::Now());
418 scoped_ptr<std::set<std::string> > active_profiles( 421 scoped_ptr<std::set<std::string> > active_profiles(
419 new std::set<std::string>()); 422 new std::set<std::string>());
420 423
421 for (chrome::BrowserIterator it; !it.done(); it.Next()) 424 for (chrome::BrowserIterator it; !it.done(); it.Next())
422 active_profiles->insert(it->profile()->GetDebugName()); 425 active_profiles->insert(it->profile()->GetDebugName());
423 426
424 BrowserThread::PostBlockingPoolSequencedTask( 427 BrowserThread::PostBlockingPoolSequencedTask(
425 Database::kDatabaseSequenceToken, 428 Database::kDatabaseSequenceToken,
426 FROM_HERE, 429 FROM_HERE,
427 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper, 430 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper,
428 base::Unretained(this), 431 base::Unretained(this),
429 base::Passed(&active_profiles), 432 base::Passed(&active_profiles),
430 time)); 433 time));
431 } 434 }
432 435
433 void PerformanceMonitor::UpdateLiveProfilesHelper( 436 void PerformanceMonitor::UpdateLiveProfilesHelper(
434 scoped_ptr<std::set<std::string> > active_profiles, 437 scoped_ptr<std::set<std::string> > active_profiles,
435 std::string time) { 438 std::string time) {
436 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 439 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
440 DCHECK(database_logging_enabled_);
437 441
438 for (std::set<std::string>::const_iterator iter = active_profiles->begin(); 442 for (std::set<std::string>::const_iterator iter = active_profiles->begin();
439 iter != active_profiles->end(); ++iter) { 443 iter != active_profiles->end(); ++iter) {
440 database_->AddStateValue(kStateProfilePrefix + *iter, time); 444 database_->AddStateValue(kStateProfilePrefix + *iter, time);
441 } 445 }
442 } 446 }
447 #endif
443 448
444 void PerformanceMonitor::DoTimedCollections() { 449 void PerformanceMonitor::GatherMetricsMapOnIOThread(
445 UpdateLiveProfiles(); 450 int current_update_sequence) {
451 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
452
453 // Find all child processes (does not include renderers), which has to be
454 // done on the IO thread.
455 for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
456 const content::ChildProcessData& child_process_data = iter.GetData();
457 base::ProcessHandle handle = child_process_data.handle;
458 MarkProcessAsAlive(handle, child_process_data.process_type,
459 current_update_sequence);
460 }
461
462 // Add the current (browser) process.
463 MarkProcessAsAlive(base::GetCurrentProcessHandle(),
464 content::PROCESS_TYPE_BROWSER, current_update_sequence);
446 465
447 BrowserThread::PostBlockingPoolSequencedTask( 466 BrowserThread::PostBlockingPoolSequencedTask(
448 Database::kDatabaseSequenceToken, 467 Database::kDatabaseSequenceToken,
449 FROM_HERE, 468 FROM_HERE,
450 base::Bind(&PerformanceMonitor::GatherStatisticsOnBackgroundThread, 469 base::Bind(&PerformanceMonitor::StoreMetricsOnBackgroundThread,
451 base::Unretained(this))); 470 base::Unretained(this), current_update_sequence,
471 performance_data_for_io_thread_));
472 }
473
474 void PerformanceMonitor::StoreMetricsOnBackgroundThread(
475 int current_update_sequence,
476 const PerformanceDataForIOThread& performance_data_for_io_thread) {
477 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
478
479 base::Time time_now = base::Time::Now();
480
481 // The timing can be off by kSampleIntervalInSeconds during any one particular
482 // run, but will be correct over time.
483 bool end_of_cycle = time_now >= next_collection_time_;
484 if (end_of_cycle) {
485 next_collection_time_ +=
486 base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
487 }
488
489 double cpu_usage = 0.0;
490 size_t private_memory_sum = 0;
491 size_t shared_memory_sum = 0;
492
493 // Update metrics for all watched processes; remove dead entries from the map.
494 MetricsMap::iterator iter = metrics_map_.begin();
495 while (iter != metrics_map_.end()) {
496 ProcessMetricsHistory& process_metrics = iter->second;
497 if (process_metrics.last_update_sequence() != current_update_sequence) {
498 // Not touched this iteration; let's get rid of it.
499 metrics_map_.erase(iter++);
500 } else {
501 process_metrics.SampleMetrics();
502
503 if (end_of_cycle) {
504 // Gather averages of previously sampled metrics.
505 cpu_usage += process_metrics.GetAverageCPUUsage();
506
507 size_t private_memory = 0;
508 size_t shared_memory = 0;
509 process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory);
510 private_memory_sum += private_memory;
511 shared_memory_sum += shared_memory;
512
513 process_metrics.EndOfCycle();
514 }
515
516 ++iter;
517 }
518 }
519
520 // Store previously-sampled metrics.
521 if (end_of_cycle && database_logging_enabled_) {
522 if (!metrics_map_.empty()) {
523 database_->AddMetric(Metric(METRIC_CPU_USAGE, time_now, cpu_usage));
524 database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
525 time_now,
526 static_cast<double>(private_memory_sum)));
527 database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
528 time_now,
529 static_cast<double>(shared_memory_sum)));
530 }
531
532 database_->AddMetric(
533 Metric(METRIC_NETWORK_BYTES_READ,
534 time_now,
535 static_cast<double>(
536 performance_data_for_io_thread.network_bytes_read)));
537 }
452 538
453 BrowserThread::PostTask( 539 BrowserThread::PostTask(
454 BrowserThread::IO, 540 BrowserThread::UI,
455 FROM_HERE, 541 FROM_HERE,
456 base::Bind(&PerformanceMonitor::CallInsertIOData, 542 base::Bind(&PerformanceMonitor::ResetMetricsTimerOnUIThread,
457 base::Unretained(this))); 543 base::Unretained(this)));
458 } 544 }
459 545
460 void PerformanceMonitor::CallInsertIOData() { 546 void PerformanceMonitor::ResetMetricsTimerOnUIThread() {
461 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 547 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
462 548
463 BrowserThread::PostBlockingPoolSequencedTask( 549 // Start up the timer again; we avoid the use of a repeating timer
464 Database::kDatabaseSequenceToken, 550 // to not have concurrent metrics gathering running.
465 FROM_HERE, 551 if (!disable_timer_autostart_for_testing_)
466 base::Bind(&PerformanceMonitor::InsertIOData, 552 timer_.Reset();
467 base::Unretained(this),
468 performance_data_for_io_thread_));
469 }
470
471 void PerformanceMonitor::InsertIOData(
472 const PerformanceDataForIOThread& performance_data_for_io_thread) {
473 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
474 database_->AddMetric(
475 Metric(METRIC_NETWORK_BYTES_READ,
476 base::Time::Now(),
477 static_cast<double>(
478 performance_data_for_io_thread.network_bytes_read)));
479 } 553 }
480 554
481 void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request, 555 void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request,
482 const int bytes_read) { 556 const int bytes_read) {
483 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 557 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
484 558
485 if (initialized_ && !request.url().SchemeIsFile()) 559 if (initialized_ && !request.url().SchemeIsFile())
486 performance_data_for_io_thread_.network_bytes_read += bytes_read; 560 performance_data_for_io_thread_.network_bytes_read += bytes_read;
487 } 561 }
488 562
489 void PerformanceMonitor::Observe(int type, 563 void PerformanceMonitor::Observe(int type,
490 const content::NotificationSource& source, 564 const content::NotificationSource& source,
491 const content::NotificationDetails& details) { 565 const content::NotificationDetails& details) {
566 DCHECK(database_logging_enabled_);
567
492 switch (type) { 568 switch (type) {
493 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 569 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
494 AddExtensionEvent( 570 AddExtensionEvent(
495 EVENT_EXTENSION_INSTALL, 571 EVENT_EXTENSION_INSTALL,
496 content::Details<const extensions::InstalledExtensionInfo>(details)-> 572 content::Details<const extensions::InstalledExtensionInfo>(details)->
497 extension); 573 extension);
498 break; 574 break;
499 } 575 }
500 case chrome::NOTIFICATION_EXTENSION_ENABLED: { 576 case chrome::NOTIFICATION_EXTENSION_ENABLED: {
501 AddExtensionEvent(EVENT_EXTENSION_ENABLE, 577 AddExtensionEvent(EVENT_EXTENSION_ENABLE,
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 if (!url_list.empty()) 715 if (!url_list.empty())
640 url_list += ", "; 716 url_list += ", ";
641 717
642 url_list += url; 718 url_list += url;
643 } 719 }
644 720
645 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list)); 721 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list));
646 } 722 }
647 723
648 } // namespace performance_monitor 724 } // namespace performance_monitor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698