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

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: Fixed dependencies. Created 7 years, 3 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/web_contents.h" 42 #include "content/public/browser/web_contents.h"
41 #include "net/url_request/url_request.h" 43 #include "net/url_request/url_request.h"
42 44
43 using content::BrowserThread; 45 using content::BrowserThread;
44 using extensions::Extension; 46 using extensions::Extension;
45 47
46 namespace performance_monitor { 48 namespace performance_monitor {
47 49
48 namespace { 50 namespace {
49 51
50 const uint32 kAccessFlags = base::kProcessAccessDuplicateHandle | 52 const uint32 kAccessFlags = base::kProcessAccessDuplicateHandle |
51 base::kProcessAccessQueryInformation | 53 base::kProcessAccessQueryInformation |
52 base::kProcessAccessTerminate | 54 base::kProcessAccessTerminate |
53 base::kProcessAccessWaitForTermination; 55 base::kProcessAccessWaitForTermination;
54 56
55 bool g_started_initialization = false;
56
57 std::string TimeToString(base::Time time) { 57 std::string TimeToString(base::Time time) {
58 int64 time_int64 = time.ToInternalValue(); 58 int64 time_int64 = time.ToInternalValue();
59 return base::Int64ToString(time_int64); 59 return base::Int64ToString(time_int64);
60 } 60 }
61 61
62 bool StringToTime(std::string time, base::Time* output) { 62 bool StringToTime(std::string time, base::Time* output) {
63 int64 time_int64 = 0; 63 int64 time_int64 = 0;
64 if (!base::StringToInt64(time, &time_int64)) 64 if (!base::StringToInt64(time, &time_int64))
65 return false; 65 return false;
66 *output = base::Time::FromInternalValue(time_int64); 66 *output = base::Time::FromInternalValue(time_int64);
(...skipping 24 matching lines...) Expand all
91 } 91 }
92 92
93 } // namespace 93 } // namespace
94 94
95 bool PerformanceMonitor::initialized_ = false; 95 bool PerformanceMonitor::initialized_ = false;
96 96
97 PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread() 97 PerformanceMonitor::PerformanceDataForIOThread::PerformanceDataForIOThread()
98 : network_bytes_read(0) { 98 : network_bytes_read(0) {
99 } 99 }
100 100
101 PerformanceMonitor::PerformanceMonitor() : metrics_map_(new MetricsMap) {} 101 PerformanceMonitor::PerformanceMonitor()
102 : gather_interval_in_seconds_(kDefaultGatherIntervalInSeconds),
103 database_logging_enabled_(false),
104 timer_(FROM_HERE,
105 base::TimeDelta::FromSeconds(kSampleInterval),
106 this,
107 &PerformanceMonitor::DoTimedCollections),
108 disable_timer_autostart_(false) {}
Devlin 2013/09/12 00:44:47 nit: please place { and } on separate lines, e.g.
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
102 109
103 PerformanceMonitor::~PerformanceMonitor() { 110 PerformanceMonitor::~PerformanceMonitor() {
104 BrowserThread::PostBlockingPoolSequencedTask( 111 BrowserThread::PostBlockingPoolSequencedTask(
105 Database::kDatabaseSequenceToken, 112 Database::kDatabaseSequenceToken,
106 FROM_HERE, 113 FROM_HERE,
107 base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release())); 114 base::Bind(&DeleteDatabaseOnBackgroundThread, database_.release()));
108 } 115 }
109 116
110 bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) { 117 bool PerformanceMonitor::SetDatabasePath(const base::FilePath& path) {
111 if (!database_.get()) { 118 if (!database_.get()) {
112 database_path_ = path; 119 database_path_ = path;
113 return true; 120 return true;
114 } 121 }
115 122
116 // PerformanceMonitor already initialized with another path. 123 // PerformanceMonitor already initialized with another path.
117 return false; 124 return false;
118 } 125 }
119 126
120 // static 127 // static
121 PerformanceMonitor* PerformanceMonitor::GetInstance() { 128 PerformanceMonitor* PerformanceMonitor::GetInstance() {
122 return Singleton<PerformanceMonitor>::get(); 129 return Singleton<PerformanceMonitor>::get();
123 } 130 }
124 131
125 void PerformanceMonitor::Start() { 132 void PerformanceMonitor::Start() {
126 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 133 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
127 134
128 // Avoid responding to multiple calls to Start(). 135 static bool has_initialized = false;
129 if (g_started_initialization) 136 DCHECK(!has_initialized);
130 return; 137 has_initialized = true;
131 138
132 g_started_initialization = true; 139 if (CommandLine::ForCurrentProcess()->HasSwitch(
140 switches::kPerformanceMonitorGathering)) {
141 database_logging_enabled_ = true;
142
143 if (!CommandLine::ForCurrentProcess()
144 ->GetSwitchValueASCII(switches::kPerformanceMonitorGathering)
Devlin 2013/09/12 00:44:47 nit: though arbitrary, I've always seen -> on the
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
145 .empty()) {
146 int specified_interval = 0;
147 if (!base::StringToInt(
148 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
Devlin 2013/09/12 00:44:47 nit: operator ! does not count as a separate scope
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
149 switches::kPerformanceMonitorGathering),
150 &specified_interval) ||
151 specified_interval <= 0) {
152 LOG(ERROR) << "Invalid value for switch: '"
153 << switches::kPerformanceMonitorGathering
154 << "'; please use an integer greater than 0.";
155 } else {
156 gather_interval_in_seconds_ = specified_interval;
157 }
158 }
159 }
160
161 gather_interval_in_seconds_ =
162 std::max(gather_interval_in_seconds_, kSampleInterval);
163
164 next_collection_time_ = base::Time::Now() + base::TimeDelta::FromSeconds(
Devlin 2013/09/12 00:44:47 nit: To me, this just looks odd (though I understa
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
165 gather_interval_in_seconds_);
166
133 util::PostTaskToDatabaseThreadAndReply( 167 util::PostTaskToDatabaseThreadAndReply(
134 FROM_HERE, 168 FROM_HERE,
135 base::Bind(&PerformanceMonitor::InitOnBackgroundThread, 169 base::Bind(&PerformanceMonitor::InitOnBackgroundThread,
136 base::Unretained(this)), 170 base::Unretained(this)),
137 base::Bind(&PerformanceMonitor::FinishInit, 171 base::Bind(&PerformanceMonitor::FinishInit,
138 base::Unretained(this))); 172 base::Unretained(this)));
139 } 173 }
140 174
141 void PerformanceMonitor::InitOnBackgroundThread() { 175 void PerformanceMonitor::InitOnBackgroundThread() {
142 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 176 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
143 database_ = Database::Create(database_path_);
144 if (!database_) {
145 LOG(ERROR) << "Could not initialize database; aborting initialization.";
146 return;
147 }
148 177
149 // Initialize the io thread's performance data to the value in the database; 178 if (database_logging_enabled_) {
150 // if there isn't a recording in the database, the value stays at 0. 179 database_ = Database::Create(database_path_);
151 Metric metric; 180 if (!database_) {
152 if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ, 181 LOG(ERROR) << "Could not initialize database; aborting initialization.";
153 &metric)) { 182 database_logging_enabled_ = false;
154 performance_data_for_io_thread_.network_bytes_read = metric.value; 183 return;
184 }
185
186 // Initialize the io thread's performance data to the value in the database;
187 // if there isn't a recording in the database, the value stays at 0.
188 Metric metric;
189 if (database_->GetRecentStatsForActivityAndMetric(METRIC_NETWORK_BYTES_READ,
190 &metric)) {
191 performance_data_for_io_thread_.network_bytes_read = metric.value;
192 }
155 } 193 }
156 } 194 }
157 195
158 void PerformanceMonitor::FinishInit() { 196 void PerformanceMonitor::FinishInit() {
159 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 197 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 // Short-circuit the initialization process if the database wasn't properly
161 // created. This will prevent PerformanceMonitor from performing any actions,
162 // including observing events.
163 if (!database_)
164 return;
165 198
166 RegisterForNotifications(); 199 // Events and notifications are only useful if we're
Devlin 2013/09/12 00:44:47 line wrapping is off.
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
167 CheckForUncleanExits(); 200 // logging to the database.
168 BrowserThread::PostBlockingPoolSequencedTask( 201 if (database_logging_enabled_) {
169 Database::kDatabaseSequenceToken, 202 RegisterForNotifications();
170 FROM_HERE, 203 CheckForUncleanExits();
171 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread, 204 BrowserThread::PostBlockingPoolSequencedTask(
172 base::Unretained(this))); 205 Database::kDatabaseSequenceToken,
173 206 FROM_HERE,
174 int gather_interval_in_seconds = kDefaultGatherIntervalInSeconds; 207 base::Bind(&PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread,
175 if (CommandLine::ForCurrentProcess()->HasSwitch( 208 base::Unretained(this)));
176 switches::kPerformanceMonitorGathering) &&
177 !CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
178 switches::kPerformanceMonitorGathering).empty()) {
179 int specified_interval = 0;
180 if (!base::StringToInt(
181 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
182 switches::kPerformanceMonitorGathering),
183 &specified_interval) || specified_interval <= 0) {
184 LOG(ERROR) << "Invalid value for switch: '"
185 << switches::kPerformanceMonitorGathering
186 << "'; please use an integer greater than 0.";
187 } else {
188 gather_interval_in_seconds = specified_interval;
189 }
190 } 209 }
191 210
192 timer_.Start(FROM_HERE, 211 // Start our periodic gathering of metrics.
193 base::TimeDelta::FromSeconds(gather_interval_in_seconds), 212 if (!disable_timer_autostart_) {
Devlin 2013/09/12 00:44:47 nit: for single-line if-statements, prefer no brac
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
194 this, 213 timer_.Reset();
195 &PerformanceMonitor::DoTimedCollections); 214 }
196 215
197 // Post a task to the background thread to a function which does nothing. 216 // Post a task to the background thread to a function which does nothing.
198 // This will force any tasks the database is performing to finish prior to 217 // This will force any tasks the database is performing to finish prior to
199 // the reply being sent, since they use the same thread. 218 // the reply being sent, since they use the same thread.
200 // 219 //
201 // Important! Make sure that methods in FinishInit() only rely on posting 220 // Important! Make sure that methods in FinishInit() only rely on posting
202 // to the background thread, and do not rely upon a reply from the background 221 // to the background thread, and do not rely upon a reply from the background
203 // thread; this is necessary for this notification to be valid. 222 // thread; this is necessary for this notification to be valid.
204 util::PostTaskToDatabaseThreadAndReply( 223 util::PostTaskToDatabaseThreadAndReply(
205 FROM_HERE, 224 FROM_HERE,
206 base::Bind(&base::DoNothing), 225 base::Bind(&base::DoNothing),
207 base::Bind(&PerformanceMonitor::NotifyInitialized, 226 base::Bind(&PerformanceMonitor::NotifyInitialized,
208 base::Unretained(this))); 227 base::Unretained(this)));
209 } 228 }
210 229
211 void PerformanceMonitor::RegisterForNotifications() { 230 void PerformanceMonitor::RegisterForNotifications() {
231 DCHECK(database_logging_enabled_);
Devlin 2013/09/12 00:44:47 given that this is a private method called from on
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Safe with the current code paths sure, but why rem
232
212 // Extensions 233 // Extensions
213 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 234 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
214 content::NotificationService::AllSources()); 235 content::NotificationService::AllSources());
215 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED, 236 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
216 content::NotificationService::AllSources()); 237 content::NotificationService::AllSources());
217 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 238 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
218 content::NotificationService::AllSources()); 239 content::NotificationService::AllSources());
219 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE, 240 registrar_.Add(this, chrome::NOTIFICATION_CRX_INSTALLER_DONE,
220 content::NotificationService::AllSources()); 241 content::NotificationService::AllSources());
221 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 242 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
(...skipping 11 matching lines...) Expand all
233 254
234 // Page load times 255 // Page load times
235 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 256 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
236 content::NotificationService::AllSources()); 257 content::NotificationService::AllSources());
237 } 258 }
238 259
239 // We check if profiles exited cleanly initialization time in case they were 260 // We check if profiles exited cleanly initialization time in case they were
240 // loaded prior to PerformanceMonitor's initialization. Later profiles will be 261 // loaded prior to PerformanceMonitor's initialization. Later profiles will be
241 // checked through the PROFILE_ADDED notification. 262 // checked through the PROFILE_ADDED notification.
242 void PerformanceMonitor::CheckForUncleanExits() { 263 void PerformanceMonitor::CheckForUncleanExits() {
264 DCHECK(database_logging_enabled_);
Devlin 2013/09/12 00:44:47 same as above; probably safe to remove.
265
243 std::vector<Profile*> profiles = 266 std::vector<Profile*> profiles =
244 g_browser_process->profile_manager()->GetLoadedProfiles(); 267 g_browser_process->profile_manager()->GetLoadedProfiles();
245 268
246 for (std::vector<Profile*>::const_iterator iter = profiles.begin(); 269 for (std::vector<Profile*>::const_iterator iter = profiles.begin();
247 iter != profiles.end(); ++iter) { 270 iter != profiles.end(); ++iter) {
248 if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) { 271 if ((*iter)->GetLastSessionExitType() == Profile::EXIT_CRASHED) {
249 BrowserThread::PostBlockingPoolSequencedTask( 272 BrowserThread::PostBlockingPoolSequencedTask(
250 Database::kDatabaseSequenceToken, 273 Database::kDatabaseSequenceToken,
251 FROM_HERE, 274 FROM_HERE,
252 base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread, 275 base::Bind(&PerformanceMonitor::AddUncleanExitEventOnBackgroundThread,
253 base::Unretained(this), 276 base::Unretained(this),
254 (*iter)->GetDebugName())); 277 (*iter)->GetDebugName()));
255 } 278 }
256 } 279 }
257 } 280 }
258 281
259 void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread( 282 void PerformanceMonitor::AddUncleanExitEventOnBackgroundThread(
260 const std::string& profile_name) { 283 const std::string& profile_name) {
284
285 DCHECK(database_logging_enabled_);
Devlin 2013/09/12 00:44:47 If you want to have a check for database logging,
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Reorganizing release code to account for debug-onl
261 std::string database_key = kStateProfilePrefix + profile_name; 286 std::string database_key = kStateProfilePrefix + profile_name;
262 std::string last_active_string = database_->GetStateValue(database_key); 287 std::string last_active_string = database_->GetStateValue(database_key);
263 288
264 // 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
265 // 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
266 // 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.
267 if (last_active_string.empty()) 292 if (last_active_string.empty())
268 return; 293 return;
269 294
270 base::Time last_active_time; 295 base::Time last_active_time;
271 CHECK(StringToTime(last_active_string, &last_active_time)); 296 CHECK(StringToTime(last_active_string, &last_active_time));
272 297
273 scoped_ptr<Event> event = 298 scoped_ptr<Event> event =
274 util::CreateUncleanExitEvent(last_active_time, profile_name); 299 util::CreateUncleanExitEvent(last_active_time, profile_name);
275 300
276 database_->AddEvent(*event.get()); 301 database_->AddEvent(*event.get());
277 } 302 }
278 303
279 void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() { 304 void PerformanceMonitor::CheckForVersionUpdateOnBackgroundThread() {
280 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 305 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
306 DCHECK(database_logging_enabled_);
281 307
282 chrome::VersionInfo version; 308 chrome::VersionInfo version;
283 DCHECK(version.is_valid()); 309 DCHECK(version.is_valid());
284 std::string current_version = version.Version(); 310 std::string current_version = version.Version();
285 311
286 std::string previous_version = database_->GetStateValue(kStateChromeVersion); 312 std::string previous_version = database_->GetStateValue(kStateChromeVersion);
287 313
288 // 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
289 // previous_version. 315 // previous_version.
290 DCHECK(current_version >= previous_version); 316 DCHECK(current_version >= previous_version);
291 317
292 // 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
293 // 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
294 // 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
295 // version, update the state in the database and insert an event. 321 // version, update the state in the database and insert an event.
296 if (current_version > previous_version) { 322 if (current_version > previous_version) {
297 database_->AddStateValue(kStateChromeVersion, current_version); 323 database_->AddStateValue(kStateChromeVersion, current_version);
298 if (!previous_version.empty()) { 324 if (!previous_version.empty()) {
299 scoped_ptr<Event> event = util::CreateChromeUpdateEvent( 325 scoped_ptr<Event> event = util::CreateChromeUpdateEvent(
300 base::Time::Now(), previous_version, current_version); 326 base::Time::Now(), previous_version, current_version);
301 database_->AddEvent(*event.get()); 327 database_->AddEvent(*event.get());
302 } 328 }
303 } 329 }
304 } 330 }
305 331
306 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) { 332 void PerformanceMonitor::AddEvent(scoped_ptr<Event> event) {
333 DCHECK(database_logging_enabled_);
334
307 BrowserThread::PostBlockingPoolSequencedTask( 335 BrowserThread::PostBlockingPoolSequencedTask(
308 Database::kDatabaseSequenceToken, 336 Database::kDatabaseSequenceToken,
309 FROM_HERE, 337 FROM_HERE,
310 base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread, 338 base::Bind(&PerformanceMonitor::AddEventOnBackgroundThread,
311 base::Unretained(this), 339 base::Unretained(this),
312 base::Passed(&event))); 340 base::Passed(&event)));
313 } 341 }
314 342
315 void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) { 343 void PerformanceMonitor::AddEventOnBackgroundThread(scoped_ptr<Event> event) {
316 database_->AddEvent(*event.get()); 344 database_->AddEvent(*event.get());
317 } 345 }
318 346
319 void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) { 347 void PerformanceMonitor::AddMetricOnBackgroundThread(const Metric& metric) {
320 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 348 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
349 DCHECK(database_logging_enabled_);
350
321 database_->AddMetric(metric); 351 database_->AddMetric(metric);
322 } 352 }
323 353
324 void PerformanceMonitor::NotifyInitialized() { 354 void PerformanceMonitor::NotifyInitialized() {
325 content::NotificationService::current()->Notify( 355 content::NotificationService::current()->Notify(
326 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, 356 chrome::NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
327 content::Source<PerformanceMonitor>(this), 357 content::Source<PerformanceMonitor>(this),
328 content::NotificationService::NoDetails()); 358 content::NotificationService::NoDetails());
329 359
330 initialized_ = true; 360 initialized_ = true;
331 } 361 }
332 362
333 void PerformanceMonitor::GatherStatisticsOnBackgroundThread() { 363 void PerformanceMonitor::DoTimedCollections() {
334 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_) {
Devlin 2013/09/12 00:44:47 nit: no brackets.
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Sure, though out of curiosity: Is this an actual C
367 UpdateLiveProfiles();
368 }
369 #endif
335 370
336 // Because the CPU usage is gathered as an average since the last time the 371 GatherMetricsMapOnUIThread();
337 // function was called, while the memory usage is gathered as an instantaneous
338 // usage, the CPU usage is gathered before the metrics map is wiped.
339 GatherCPUUsageOnBackgroundThread();
340 UpdateMetricsMapOnBackgroundThread();
341 GatherMemoryUsageOnBackgroundThread();
342 } 372 }
343 373
344 void PerformanceMonitor::GatherCPUUsageOnBackgroundThread() { 374 void PerformanceMonitor::GatherMetricsMapOnUIThread() {
Devlin 2013/09/12 00:44:47 here, a DCHECK (or even CHECK) for On UI Thread wo
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
345 if (metrics_map_->size()) { 375 static int current_update_sequence = 0;
346 double cpu_usage = 0; 376 // Even in the "somewhat" unlikely event this wraps around,
347 for (MetricsMap::const_iterator iter = metrics_map_->begin(); 377 // it doesn't matter. We just check it for inequality.
348 iter != metrics_map_->end(); ++iter) { 378 current_update_sequence++;
349 cpu_usage += iter->second->GetCPUUsage();
350 }
351 379
352 database_->AddMetric(Metric(METRIC_CPU_USAGE, 380 // Find all render child processes; has to be done on the UI thread.
353 base::Time::Now(), 381 for (content::RenderProcessHost::iterator i =
Devlin 2013/09/12 00:44:47 i is very nondescriptive for a non-standard iterat
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
354 cpu_usage)); 382 content::RenderProcessHost::AllHostsIterator();
383 !i.IsAtEnd();
384 i.Advance()) {
Devlin 2013/09/12 00:44:47 nit: put this on the previous line.
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
385
386 base::ProcessHandle handle = i.GetCurrentValue()->GetHandle();
387 ProcessIsAlive(
388 handle, content::PROCESS_TYPE_RENDERER, current_update_sequence);
389 }
390
391 BrowserThread::PostTask(
392 BrowserThread::IO,
393 FROM_HERE,
394 base::Bind(&PerformanceMonitor::GatherMetricsMapOnIOThread,
395 base::Unretained(this),
396 current_update_sequence));
397 }
398
399 void PerformanceMonitor::ProcessIsAlive(const base::ProcessHandle& handle,
400 int process_type,
401 int current_update_sequence) {
402
403 if (handle == 0) {
404 // Process may not be valid yet.
405 return;
406 }
407
408 MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
409 if (process_metrics_iter == metrics_map_.end()) {
410 // If we're not already watching the process, let's initialize it.
411 metrics_map_[handle]
412 .Initialize(handle, process_type, current_update_sequence);
413 } else {
414 // If we are watching the process, touch it to keep it alive.
415 ProcessMetricsHistory& process_metrics = process_metrics_iter->second;
Devlin 2013/09/12 00:44:47 We don't typically use non-const references if we
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Demoting the reference to a pointer loses importan
Devlin 2013/09/12 18:20:42 I don't feel real strongly about it, but I'm not s
oystein (OOO til 10th of July) 2013/09/12 19:03:24 What's lost is the constraint that the variable ca
416 process_metrics.SetLastUpdateSequence(current_update_sequence);
355 } 417 }
356 } 418 }
357 419
358 void PerformanceMonitor::GatherMemoryUsageOnBackgroundThread() { 420 #if !defined(OS_ANDROID)
359 size_t private_memory_sum = 0;
360 size_t shared_memory_sum = 0;
361 for (MetricsMap::const_iterator iter = metrics_map_->begin();
362 iter != metrics_map_->end(); ++iter) {
363 size_t private_memory = 0;
364 size_t shared_memory = 0;
365 if (iter->second->GetMemoryBytes(&private_memory, &shared_memory)) {
366 private_memory_sum += private_memory;
367 shared_memory_sum += shared_memory;
368 } else {
369 LOG(WARNING) << "GetMemoryBytes returned NULL (platform-specific error)";
370 }
371 }
372
373 database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
374 base::Time::Now(),
375 static_cast<double>(private_memory_sum)));
376 database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
377 base::Time::Now(),
378 static_cast<double>(shared_memory_sum)));
379 }
380
381 void PerformanceMonitor::UpdateMetricsMapOnBackgroundThread() {
382 MetricsMap* new_map = new MetricsMap;
383
384 base::ProcessId browser_pid = base::GetCurrentProcId();
385 ChromeProcessList chrome_processes(GetRunningChromeProcesses(browser_pid));
386 for (ChromeProcessList::const_iterator pid_iter = chrome_processes.begin();
387 pid_iter != chrome_processes.end(); ++pid_iter) {
388 base::ProcessHandle handle;
389 if (base::OpenProcessHandleWithAccess(*pid_iter, kAccessFlags, &handle)) {
390 // If we were already watching this process, transfer it to the new map.
391 if (ContainsKey(*metrics_map_, handle)) {
392 (*new_map)[handle] = (*metrics_map_)[handle];
393 continue;
394 }
395
396 // Otherwise, gather information and prime the CPU usage to be gathered.
397 #if defined (OS_MACOSX)
398 linked_ptr<base::ProcessMetrics> process_metrics(
399 base::ProcessMetrics::CreateProcessMetrics(
400 handle, content::BrowserChildProcessHost::GetPortProvider()));
401 #else
402 linked_ptr<base::ProcessMetrics> process_metrics(
403 base::ProcessMetrics::CreateProcessMetrics(handle));
404 #endif
405
406 process_metrics->GetCPUUsage();
407
408 (*new_map)[handle] = process_metrics;
409 }
410 }
411
412 metrics_map_.reset(new_map);
413 }
414
415 void PerformanceMonitor::UpdateLiveProfiles() { 421 void PerformanceMonitor::UpdateLiveProfiles() {
416 std::string time = TimeToString(base::Time::Now()); 422 std::string time = TimeToString(base::Time::Now());
417 scoped_ptr<std::set<std::string> > active_profiles( 423 scoped_ptr<std::set<std::string> > active_profiles(
418 new std::set<std::string>()); 424 new std::set<std::string>());
419 425
420 for (chrome::BrowserIterator it; !it.done(); it.Next()) 426 for (chrome::BrowserIterator it; !it.done(); it.Next())
421 active_profiles->insert(it->profile()->GetDebugName()); 427 active_profiles->insert(it->profile()->GetDebugName());
422 428
423 BrowserThread::PostBlockingPoolSequencedTask( 429 BrowserThread::PostBlockingPoolSequencedTask(
424 Database::kDatabaseSequenceToken, 430 Database::kDatabaseSequenceToken,
425 FROM_HERE, 431 FROM_HERE,
426 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper, 432 base::Bind(&PerformanceMonitor::UpdateLiveProfilesHelper,
427 base::Unretained(this), 433 base::Unretained(this),
428 base::Passed(&active_profiles), 434 base::Passed(&active_profiles),
429 time)); 435 time));
430 } 436 }
431 437
432 void PerformanceMonitor::UpdateLiveProfilesHelper( 438 void PerformanceMonitor::UpdateLiveProfilesHelper(
433 scoped_ptr<std::set<std::string> > active_profiles, 439 scoped_ptr<std::set<std::string> > active_profiles,
434 std::string time) { 440 std::string time) {
435 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 441 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
442 DCHECK(database_logging_enabled_);
436 443
437 for (std::set<std::string>::const_iterator iter = active_profiles->begin(); 444 for (std::set<std::string>::const_iterator iter = active_profiles->begin();
438 iter != active_profiles->end(); ++iter) { 445 iter != active_profiles->end(); ++iter) {
439 database_->AddStateValue(kStateProfilePrefix + *iter, time); 446 database_->AddStateValue(kStateProfilePrefix + *iter, time);
440 } 447 }
441 } 448 }
449 #endif
442 450
443 void PerformanceMonitor::DoTimedCollections() { 451 void PerformanceMonitor::GatherMetricsMapOnIOThread(
444 UpdateLiveProfiles(); 452 int current_update_sequence) {
453 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
454
455 // Find all child processes (does not include renderers),
Devlin 2013/09/12 00:44:47 nit: line wrapping.
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Not sure what you mean here :). The comment can't
Devlin 2013/09/12 18:20:42 If a comment doesn't fit on one line, it should li
oystein (OOO til 10th of July) 2013/09/12 19:03:24 Done.
456 // which has to be done on the IO thread.
457 for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
458 const content::ChildProcessData& child_process_data = iter.GetData();
459 base::ProcessHandle handle = child_process_data.handle;
460 ProcessIsAlive(
461 handle, child_process_data.process_type, current_update_sequence);
462 }
463
464 // Add the current (browser) process.
465 ProcessIsAlive(base::GetCurrentProcessHandle(),
466 content::PROCESS_TYPE_BROWSER,
467 current_update_sequence);
445 468
446 BrowserThread::PostBlockingPoolSequencedTask( 469 BrowserThread::PostBlockingPoolSequencedTask(
447 Database::kDatabaseSequenceToken, 470 Database::kDatabaseSequenceToken,
448 FROM_HERE, 471 FROM_HERE,
449 base::Bind(&PerformanceMonitor::GatherStatisticsOnBackgroundThread, 472 base::Bind(&PerformanceMonitor::StoreMetricsOnBackgroundThread,
450 base::Unretained(this))); 473 base::Unretained(this),
474 current_update_sequence,
475 performance_data_for_io_thread_));
476 }
477
478 void PerformanceMonitor::StoreMetricsOnBackgroundThread(
479 int current_update_sequence,
480 const PerformanceDataForIOThread& performance_data_for_io_thread) {
481 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
482
483 // Update metrics for all watched processes; remove dead entries from the map.
484 MetricsMap::iterator iter = metrics_map_.begin();
485 while (iter != metrics_map_.end()) {
486 ProcessMetricsHistory& process_metrics = iter->second;
487 if (process_metrics.GetLastUpdateSequence() != current_update_sequence) {
488 // Not touched this iteration; let's get rid of it.
489 metrics_map_.erase(iter++);
490 } else {
491 process_metrics.SampleMetrics();
492 ++iter;
493 }
494 }
495
496 base::Time time_now = base::Time::Now();
497
498 // Time for a collection to be made, of previously sampled metrics.
Devlin 2013/09/12 00:44:47 nit: "Make a collection of previously-sampled metr
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Why the move? That seems to take information away
Devlin 2013/09/12 18:20:42 Again, no strong feelings, so if you think it make
499 // The timing can be off by kSampleInterval during any one particular run,
500 // but will be correct over time.
501 if (time_now > next_collection_time_) {
502 next_collection_time_ +=
503 base::TimeDelta::FromSeconds(gather_interval_in_seconds_);
504
505 if (!metrics_map_.empty()) {
506 double cpu_usage = 0.0;
507 size_t private_memory_sum = 0;
508 size_t shared_memory_sum = 0;
509
510 for (MetricsMap::iterator iter = metrics_map_.begin();
511 iter != metrics_map_.end();
512 ++iter) {
Devlin 2013/09/12 00:44:47 nit: put this on the previous line.
513
514 ProcessMetricsHistory& process_metrics = iter->second;
Devlin 2013/09/12 00:44:47 nit: avoid non-const references when possible.
515 cpu_usage += process_metrics.GetAverageCPUUsage();
516
517 size_t private_memory = 0;
518 size_t shared_memory = 0;
519 process_metrics.GetAverageMemoryBytes(&private_memory, &shared_memory);
520 private_memory_sum += private_memory;
521 shared_memory_sum += shared_memory;
522
523 process_metrics.EndOfCycle();
524 }
525
526 if (database_logging_enabled_) {
527 database_->AddMetric(Metric(METRIC_CPU_USAGE, time_now, cpu_usage));
Devlin 2013/09/12 00:44:47 This seems bad to me. I don't think we should be
oystein (OOO til 10th of July) 2013/09/12 15:02:31 EndOfCycle() always needs to be called. I can call
528 database_->AddMetric(Metric(METRIC_PRIVATE_MEMORY_USAGE,
529 time_now,
530 static_cast<double>(private_memory_sum)));
531 database_->AddMetric(Metric(METRIC_SHARED_MEMORY_USAGE,
532 time_now,
533 static_cast<double>(shared_memory_sum)));
534 }
535 }
536
537 if (database_logging_enabled_) {
538 database_->AddMetric(
539 Metric(METRIC_NETWORK_BYTES_READ,
540 time_now,
541 static_cast<double>(
542 performance_data_for_io_thread.network_bytes_read)));
543 }
544 }
451 545
452 BrowserThread::PostTask( 546 BrowserThread::PostTask(
453 BrowserThread::IO, 547 BrowserThread::UI,
454 FROM_HERE, 548 FROM_HERE,
455 base::Bind(&PerformanceMonitor::CallInsertIOData, 549 base::Bind(&PerformanceMonitor::ResetMetricsTimerOnUIThread,
456 base::Unretained(this))); 550 base::Unretained(this)));
457 } 551 }
458 552
459 void PerformanceMonitor::CallInsertIOData() { 553 void PerformanceMonitor::ResetMetricsTimerOnUIThread() {
460 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 554 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
461 555
462 BrowserThread::PostBlockingPoolSequencedTask( 556 // Start up the timer again; we avoid the use of a repeating timer
463 Database::kDatabaseSequenceToken, 557 // to not have concurrent metrics gathering running.
464 FROM_HERE, 558 if (!disable_timer_autostart_) {
Devlin 2013/09/12 00:44:47 nit: no brackets
oystein (OOO til 10th of July) 2013/09/12 15:02:31 Done.
465 base::Bind(&PerformanceMonitor::InsertIOData, 559 timer_.Reset();
466 base::Unretained(this), 560 }
467 performance_data_for_io_thread_));
468 }
469
470 void PerformanceMonitor::InsertIOData(
471 const PerformanceDataForIOThread& performance_data_for_io_thread) {
472 CHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
473 database_->AddMetric(
474 Metric(METRIC_NETWORK_BYTES_READ,
475 base::Time::Now(),
476 static_cast<double>(
477 performance_data_for_io_thread.network_bytes_read)));
478 } 561 }
479 562
480 void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request, 563 void PerformanceMonitor::BytesReadOnIOThread(const net::URLRequest& request,
481 const int bytes_read) { 564 const int bytes_read) {
482 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 565 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
483 566
484 if (initialized_ && !request.url().SchemeIsFile()) 567 if (initialized_ && !request.url().SchemeIsFile())
485 performance_data_for_io_thread_.network_bytes_read += bytes_read; 568 performance_data_for_io_thread_.network_bytes_read += bytes_read;
486 } 569 }
487 570
488 void PerformanceMonitor::Observe(int type, 571 void PerformanceMonitor::Observe(int type,
489 const content::NotificationSource& source, 572 const content::NotificationSource& source,
490 const content::NotificationDetails& details) { 573 const content::NotificationDetails& details) {
574 DCHECK(database_logging_enabled_);
575
491 switch (type) { 576 switch (type) {
492 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { 577 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
493 AddExtensionEvent( 578 AddExtensionEvent(
494 EVENT_EXTENSION_INSTALL, 579 EVENT_EXTENSION_INSTALL,
495 content::Details<const extensions::InstalledExtensionInfo>(details)-> 580 content::Details<const extensions::InstalledExtensionInfo>(details)->
496 extension); 581 extension);
497 break; 582 break;
498 } 583 }
499 case chrome::NOTIFICATION_EXTENSION_ENABLED: { 584 case chrome::NOTIFICATION_EXTENSION_ENABLED: {
500 AddExtensionEvent(EVENT_EXTENSION_ENABLE, 585 AddExtensionEvent(EVENT_EXTENSION_ENABLE,
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 if (!url_list.empty()) 723 if (!url_list.empty())
639 url_list += ", "; 724 url_list += ", ";
640 725
641 url_list += url; 726 url_list += url;
642 } 727 }
643 728
644 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list)); 729 AddEvent(util::CreateRendererFailureEvent(base::Time::Now(), type, url_list));
645 } 730 }
646 731
647 } // namespace performance_monitor 732 } // namespace performance_monitor
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698