Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/metrics/perf/perf_provider_chromeos.h" | 5 #include "chrome/browser/metrics/perf/perf_provider_chromeos.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/rand_util.h" | 13 #include "base/rand_util.h" |
| 14 #include "base/threading/sequenced_worker_pool.h" | 14 #include "base/threading/sequenced_worker_pool.h" |
| 15 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h" | 15 #include "chrome/browser/metrics/perf/windowed_incognito_observer.h" |
| 16 #include "chrome/browser/ui/browser_list.h" | 16 #include "chrome/browser/ui/browser_list.h" |
| 17 #include "chromeos/dbus/dbus_thread_manager.h" | 17 #include "chromeos/dbus/dbus_thread_manager.h" |
| 18 #include "chromeos/dbus/debug_daemon_client.h" | 18 #include "chromeos/dbus/debug_daemon_client.h" |
| 19 | 19 |
| 20 namespace metrics { | |
| 21 | |
| 22 PerfProvider::CollectionParams::CollectionParams( | |
|
Alexei Svitkine (slow)
2015/10/09 17:27:21
Nit: Move this below the anon namespace decl.
dhsharp
2015/10/09 18:29:48
Done.
| |
| 23 base::TimeDelta collection_duration, | |
| 24 base::TimeDelta periodic_interval, | |
| 25 TriggerParams resume_from_suspend, | |
| 26 TriggerParams restore_session) | |
| 27 : collection_duration_(collection_duration.ToInternalValue()), | |
| 28 periodic_interval_(periodic_interval.ToInternalValue()), | |
| 29 resume_from_suspend_(resume_from_suspend), | |
| 30 restore_session_(restore_session) { | |
| 31 } | |
|
Alexei Svitkine (slow)
2015/10/09 17:27:21
Nit: Add an empty line below.
dhsharp
2015/10/09 18:29:48
Oops. Done.
| |
| 32 PerfProvider::CollectionParams::TriggerParams::TriggerParams( | |
| 33 int64 sampling_factor, | |
| 34 base::TimeDelta max_collection_delay) | |
| 35 : sampling_factor_(sampling_factor), | |
| 36 max_collection_delay_(max_collection_delay.ToInternalValue()) { | |
| 37 } | |
| 38 | |
| 39 const PerfProvider::CollectionParams PerfProvider::kDefaultParameters( | |
|
Alexei Svitkine (slow)
2015/10/09 17:27:21
I'd not make this a static member but instead just
dhsharp
2015/10/09 18:29:48
I had been thinking I needed access to it from tes
| |
| 40 /*collection_duration*/ base::TimeDelta::FromSeconds(2), | |
| 41 /*periodic_interval*/ base::TimeDelta::FromHours(3), | |
| 42 /*resume_from_suspend*/ PerfProvider::CollectionParams::TriggerParams( | |
|
Alexei Svitkine (slow)
2015/10/09 17:27:21
Nit: I'd prefer the comments to be:
/* resume_fro
dhsharp
2015/10/09 18:29:48
Done.
| |
| 43 /*sampling_factor*/ 10, | |
| 44 /*max_collection_delay*/ base::TimeDelta::FromSeconds(5)), | |
| 45 /*restore_session*/ PerfProvider::CollectionParams::TriggerParams( | |
| 46 /*sampling_factor*/ 10, | |
| 47 /*max_collection_delay*/ base::TimeDelta::FromSeconds(10))); | |
| 48 | |
| 20 namespace { | 49 namespace { |
| 21 | 50 |
| 22 // Partition time since login into successive intervals of this size. In each | |
| 23 // interval, pick a random time to collect a profile. | |
| 24 const size_t kPerfProfilingIntervalMs = 3 * 60 * 60 * 1000; | |
| 25 | |
| 26 // Default time in seconds perf is run for. | |
| 27 const size_t kPerfCommandDurationDefaultSeconds = 2; | |
| 28 | |
| 29 // Limit the total size of protobufs that can be cached, so they don't take up | 51 // Limit the total size of protobufs that can be cached, so they don't take up |
| 30 // too much memory. If the size of cached protobufs exceeds this value, stop | 52 // too much memory. If the size of cached protobufs exceeds this value, stop |
| 31 // collecting further perf data. The current value is 4 MB. | 53 // collecting further perf data. The current value is 4 MB. |
| 32 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; | 54 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; |
| 33 | 55 |
| 34 // There may be too many suspends to collect a profile each time there is a | |
| 35 // resume. To limit the number of profiles, collect one for 1 in 10 resumes. | |
| 36 // Adjust this number as needed. | |
| 37 const int kResumeSamplingFactor = 10; | |
| 38 | |
| 39 // There may be too many session restores to collect a profile each time. Limit | |
| 40 // the collection rate by collecting one per 10 restores. Adjust this number as | |
| 41 // needed. | |
| 42 const int kRestoreSessionSamplingFactor = 10; | |
| 43 | |
| 44 // This is used to space out session restore collections in the face of several | 56 // This is used to space out session restore collections in the face of several |
| 45 // notifications in a short period of time. There should be no less than this | 57 // notifications in a short period of time. There should be no less than this |
| 46 // much time between collections. The current value is 30 seconds. | 58 // much time between collections. |
| 47 const int kMinIntervalBetweenSessionRestoreCollectionsMs = 30 * 1000; | 59 const base::TimeDelta kMinIntervalBetweenSessionRestoreCollections = |
| 48 | 60 base::TimeDelta::FromSeconds(30); |
| 49 // If collecting after a resume, add a random delay before collecting. The delay | |
| 50 // should be randomly selected between 0 and this value. Currently the value is | |
| 51 // equal to 5 seconds. | |
| 52 const int kMaxResumeCollectionDelayMs = 5 * 1000; | |
| 53 | |
| 54 // If collecting after a session restore, add a random delay before collecting. | |
| 55 // The delay should be randomly selected between 0 and this value. Currently the | |
| 56 // value is equal to 10 seconds. | |
| 57 const int kMaxRestoreSessionCollectionDelayMs = 10 * 1000; | |
| 58 | 61 |
| 59 // Enumeration representing success and various failure modes for collecting and | 62 // Enumeration representing success and various failure modes for collecting and |
| 60 // sending perf data. | 63 // sending perf data. |
| 61 enum GetPerfDataOutcome { | 64 enum GetPerfDataOutcome { |
| 62 SUCCESS, | 65 SUCCESS, |
| 63 NOT_READY_TO_UPLOAD, | 66 NOT_READY_TO_UPLOAD, |
| 64 NOT_READY_TO_COLLECT, | 67 NOT_READY_TO_COLLECT, |
| 65 INCOGNITO_ACTIVE, | 68 INCOGNITO_ACTIVE, |
| 66 INCOGNITO_LAUNCHED, | 69 INCOGNITO_LAUNCHED, |
| 67 PROTOBUF_NOT_PARSED, | 70 PROTOBUF_NOT_PARSED, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 78 outcome, | 81 outcome, |
| 79 NUM_OUTCOMES); | 82 NUM_OUTCOMES); |
| 80 } | 83 } |
| 81 | 84 |
| 82 // Returns true if a normal user is logged in. Returns false otherwise (e.g. if | 85 // Returns true if a normal user is logged in. Returns false otherwise (e.g. if |
| 83 // logged in as a guest or as a kiosk app). | 86 // logged in as a guest or as a kiosk app). |
| 84 bool IsNormalUserLoggedIn() { | 87 bool IsNormalUserLoggedIn() { |
| 85 return chromeos::LoginState::Get()->IsUserAuthenticated(); | 88 return chromeos::LoginState::Get()->IsUserAuthenticated(); |
| 86 } | 89 } |
| 87 | 90 |
| 91 // Returns a random TimeDelta between zero and |max|. | |
| 92 base::TimeDelta RandomTimeDelta(base::TimeDelta max) { | |
| 93 return base::TimeDelta::FromMicroseconds( | |
| 94 base::RandGenerator(max.InMicroseconds())); | |
| 95 } | |
| 96 | |
| 88 } // namespace | 97 } // namespace |
| 89 | 98 |
| 90 namespace metrics { | |
| 91 | |
| 92 PerfProvider::PerfProvider() | 99 PerfProvider::PerfProvider() |
| 93 : login_observer_(this), | 100 : collection_params_(kDefaultParameters), |
| 94 next_profiling_interval_start_(base::TimeTicks::Now()), | 101 login_observer_(this), |
| 95 weak_factory_(this) { | 102 next_profiling_interval_start_(base::TimeTicks::Now()), |
| 103 weak_factory_(this) { | |
| 96 // Register the login observer with LoginState. | 104 // Register the login observer with LoginState. |
| 97 chromeos::LoginState::Get()->AddObserver(&login_observer_); | 105 chromeos::LoginState::Get()->AddObserver(&login_observer_); |
| 98 | 106 |
| 99 // Register as an observer of power manager events. | 107 // Register as an observer of power manager events. |
| 100 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | 108 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> |
| 101 AddObserver(this); | 109 AddObserver(this); |
| 102 | 110 |
| 103 // Register as an observer of session restore. | 111 // Register as an observer of session restore. |
| 104 on_session_restored_callback_subscription_ = | 112 on_session_restored_callback_subscription_ = |
| 105 SessionRestore::RegisterOnSessionRestoredCallback( | 113 SessionRestore::RegisterOnSessionRestoredCallback( |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 // canceled. Do not collect anything if that's the case. | 207 // canceled. Do not collect anything if that's the case. |
| 200 if (sleep_duration == base::TimeDelta()) | 208 if (sleep_duration == base::TimeDelta()) |
| 201 return; | 209 return; |
| 202 | 210 |
| 203 // Do not collect a profile unless logged in. The system behavior when closing | 211 // Do not collect a profile unless logged in. The system behavior when closing |
| 204 // the lid or idling when not logged in is currently to shut down instead of | 212 // the lid or idling when not logged in is currently to shut down instead of |
| 205 // suspending. But it's good to enforce the rule here in case that changes. | 213 // suspending. But it's good to enforce the rule here in case that changes. |
| 206 if (!IsNormalUserLoggedIn()) | 214 if (!IsNormalUserLoggedIn()) |
| 207 return; | 215 return; |
| 208 | 216 |
| 209 // Collect a profile only 1/|kResumeSamplingFactor| of the time, to avoid | 217 // Collect a profile only 1/|sampling_factor| of the time, to avoid |
| 210 // collecting too much data. | 218 // collecting too much data. |
| 211 if (base::RandGenerator(kResumeSamplingFactor) != 0) | 219 const auto& resume_params = collection_params_.resume_from_suspend(); |
| 220 if (base::RandGenerator(resume_params.sampling_factor()) != 0) | |
| 212 return; | 221 return; |
| 213 | 222 |
| 214 // Override any existing profiling. | 223 // Override any existing profiling. |
| 215 if (timer_.IsRunning()) | 224 if (timer_.IsRunning()) |
| 216 timer_.Stop(); | 225 timer_.Stop(); |
| 217 | 226 |
| 218 // Randomly pick a delay before doing the collection. | 227 // Randomly pick a delay before doing the collection. |
| 219 base::TimeDelta collection_delay = | 228 base::TimeDelta collection_delay = RandomTimeDelta( |
| 220 base::TimeDelta::FromMilliseconds( | 229 resume_params.max_collection_delay()); |
| 221 base::RandGenerator(kMaxResumeCollectionDelayMs)); | |
| 222 timer_.Start(FROM_HERE, | 230 timer_.Start(FROM_HERE, |
| 223 collection_delay, | 231 collection_delay, |
| 224 base::Bind(&PerfProvider::CollectPerfDataAfterResume, | 232 base::Bind(&PerfProvider::CollectPerfDataAfterResume, |
| 225 weak_factory_.GetWeakPtr(), | 233 weak_factory_.GetWeakPtr(), |
| 226 sleep_duration, | 234 sleep_duration, |
| 227 collection_delay)); | 235 collection_delay)); |
| 228 } | 236 } |
| 229 | 237 |
| 230 void PerfProvider::OnSessionRestoreDone(int num_tabs_restored) { | 238 void PerfProvider::OnSessionRestoreDone(int num_tabs_restored) { |
| 231 // Do not collect a profile unless logged in as a normal user. | 239 // Do not collect a profile unless logged in as a normal user. |
| 232 if (!IsNormalUserLoggedIn()) | 240 if (!IsNormalUserLoggedIn()) |
| 233 return; | 241 return; |
| 234 | 242 |
| 235 // Collect a profile only 1/|kRestoreSessionSamplingFactor| of the time, to | 243 // Collect a profile only 1/|sampling_factor| of the time, to |
| 236 // avoid collecting too much data and potentially causing UI latency. | 244 // avoid collecting too much data and potentially causing UI latency. |
| 237 if (base::RandGenerator(kRestoreSessionSamplingFactor) != 0) | 245 const auto& restore_params = collection_params_.restore_session(); |
| 246 if (base::RandGenerator(restore_params.sampling_factor()) != 0) | |
| 238 return; | 247 return; |
| 239 | 248 |
| 240 const base::TimeDelta min_interval = | 249 const auto min_interval = kMinIntervalBetweenSessionRestoreCollections; |
| 241 base::TimeDelta::FromMilliseconds( | |
| 242 kMinIntervalBetweenSessionRestoreCollectionsMs); | |
| 243 const base::TimeDelta time_since_last_collection = | 250 const base::TimeDelta time_since_last_collection = |
| 244 (base::TimeTicks::Now() - last_session_restore_collection_time_); | 251 (base::TimeTicks::Now() - last_session_restore_collection_time_); |
| 245 // Do not collect if there hasn't been enough elapsed time since the last | 252 // Do not collect if there hasn't been enough elapsed time since the last |
| 246 // collection. | 253 // collection. |
| 247 if (!last_session_restore_collection_time_.is_null() && | 254 if (!last_session_restore_collection_time_.is_null() && |
| 248 time_since_last_collection < min_interval) { | 255 time_since_last_collection < min_interval) { |
| 249 return; | 256 return; |
| 250 } | 257 } |
| 251 | 258 |
| 252 // Stop any existing scheduled collection. | 259 // Stop any existing scheduled collection. |
| 253 if (timer_.IsRunning()) | 260 if (timer_.IsRunning()) |
| 254 timer_.Stop(); | 261 timer_.Stop(); |
| 255 | 262 |
| 256 // Randomly pick a delay before doing the collection. | 263 // Randomly pick a delay before doing the collection. |
| 257 base::TimeDelta collection_delay = | 264 base::TimeDelta collection_delay = RandomTimeDelta( |
| 258 base::TimeDelta::FromMilliseconds( | 265 restore_params.max_collection_delay()); |
| 259 base::RandGenerator(kMaxRestoreSessionCollectionDelayMs)); | |
| 260 timer_.Start( | 266 timer_.Start( |
| 261 FROM_HERE, | 267 FROM_HERE, |
| 262 collection_delay, | 268 collection_delay, |
| 263 base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore, | 269 base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore, |
| 264 weak_factory_.GetWeakPtr(), | 270 weak_factory_.GetWeakPtr(), |
| 265 collection_delay, | 271 collection_delay, |
| 266 num_tabs_restored)); | 272 num_tabs_restored)); |
| 267 } | 273 } |
| 268 | 274 |
| 269 void PerfProvider::OnUserLoggedIn() { | 275 void PerfProvider::OnUserLoggedIn() { |
| 270 login_time_ = base::TimeTicks::Now(); | 276 login_time_ = base::TimeTicks::Now(); |
| 271 ScheduleIntervalCollection(); | 277 ScheduleIntervalCollection(); |
| 272 } | 278 } |
| 273 | 279 |
| 274 void PerfProvider::Deactivate() { | 280 void PerfProvider::Deactivate() { |
| 275 // Stop the timer, but leave |cached_perf_data_| intact. | 281 // Stop the timer, but leave |cached_perf_data_| intact. |
| 276 timer_.Stop(); | 282 timer_.Stop(); |
| 277 } | 283 } |
| 278 | 284 |
| 279 void PerfProvider::ScheduleIntervalCollection() { | 285 void PerfProvider::ScheduleIntervalCollection() { |
| 280 DCHECK(CalledOnValidThread()); | 286 DCHECK(CalledOnValidThread()); |
| 281 if (timer_.IsRunning()) | 287 if (timer_.IsRunning()) |
| 282 return; | 288 return; |
| 283 | 289 |
| 284 // Pick a random time in the current interval. | 290 // Pick a random time in the current interval. |
| 285 base::TimeTicks scheduled_time = | 291 base::TimeTicks scheduled_time = |
| 286 next_profiling_interval_start_ + | 292 next_profiling_interval_start_ + |
| 287 base::TimeDelta::FromMilliseconds( | 293 RandomTimeDelta(collection_params_.periodic_interval()); |
| 288 base::RandGenerator(kPerfProfilingIntervalMs)); | |
| 289 | 294 |
| 290 // If the scheduled time has already passed in the time it took to make the | 295 // If the scheduled time has already passed in the time it took to make the |
| 291 // above calculations, trigger the collection event immediately. | 296 // above calculations, trigger the collection event immediately. |
| 292 base::TimeTicks now = base::TimeTicks::Now(); | 297 base::TimeTicks now = base::TimeTicks::Now(); |
| 293 if (scheduled_time < now) | 298 if (scheduled_time < now) |
| 294 scheduled_time = now; | 299 scheduled_time = now; |
| 295 | 300 |
| 296 timer_.Start(FROM_HERE, scheduled_time - now, this, | 301 timer_.Start(FROM_HERE, scheduled_time - now, this, |
| 297 &PerfProvider::DoPeriodicCollection); | 302 &PerfProvider::DoPeriodicCollection); |
| 298 | 303 |
| 299 // Update the profiling interval tracker to the start of the next interval. | 304 // Update the profiling interval tracker to the start of the next interval. |
| 300 next_profiling_interval_start_ += | 305 next_profiling_interval_start_ += collection_params_.periodic_interval(); |
| 301 base::TimeDelta::FromMilliseconds(kPerfProfilingIntervalMs); | |
| 302 } | 306 } |
| 303 | 307 |
| 304 void PerfProvider::CollectIfNecessary( | 308 void PerfProvider::CollectIfNecessary( |
| 305 scoped_ptr<SampledProfile> sampled_profile) { | 309 scoped_ptr<SampledProfile> sampled_profile) { |
| 306 DCHECK(CalledOnValidThread()); | 310 DCHECK(CalledOnValidThread()); |
| 307 | 311 |
| 308 // Schedule another interval collection. This call makes sense regardless of | 312 // Schedule another interval collection. This call makes sense regardless of |
| 309 // whether or not the current collection was interval-triggered. If it had | 313 // whether or not the current collection was interval-triggered. If it had |
| 310 // been another type of trigger event, the interval timer would have been | 314 // been another type of trigger event, the interval timer would have been |
| 311 // halted, so it makes sense to reschedule a new interval collection. | 315 // halted, so it makes sense to reschedule a new interval collection. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 328 AddToPerfHistogram(INCOGNITO_ACTIVE); | 332 AddToPerfHistogram(INCOGNITO_ACTIVE); |
| 329 return; | 333 return; |
| 330 } | 334 } |
| 331 | 335 |
| 332 scoped_ptr<WindowedIncognitoObserver> incognito_observer( | 336 scoped_ptr<WindowedIncognitoObserver> incognito_observer( |
| 333 new WindowedIncognitoObserver); | 337 new WindowedIncognitoObserver); |
| 334 | 338 |
| 335 chromeos::DebugDaemonClient* client = | 339 chromeos::DebugDaemonClient* client = |
| 336 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 340 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
| 337 | 341 |
| 338 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( | |
| 339 kPerfCommandDurationDefaultSeconds); | |
| 340 | |
| 341 client->GetPerfOutput( | 342 client->GetPerfOutput( |
| 342 collection_duration.InSeconds(), | 343 collection_params_.collection_duration().InSeconds(), |
| 343 base::Bind(&PerfProvider::ParseOutputProtoIfValid, | 344 base::Bind(&PerfProvider::ParseOutputProtoIfValid, |
| 344 weak_factory_.GetWeakPtr(), base::Passed(&incognito_observer), | 345 weak_factory_.GetWeakPtr(), base::Passed(&incognito_observer), |
| 345 base::Passed(&sampled_profile))); | 346 base::Passed(&sampled_profile))); |
| 346 } | 347 } |
| 347 | 348 |
| 348 void PerfProvider::DoPeriodicCollection() { | 349 void PerfProvider::DoPeriodicCollection() { |
| 349 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 350 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
| 350 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); | 351 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); |
| 351 | 352 |
| 352 CollectIfNecessary(sampled_profile.Pass()); | 353 CollectIfNecessary(sampled_profile.Pass()); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 371 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 372 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
| 372 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 373 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); |
| 373 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | 374 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); |
| 374 sampled_profile->set_num_tabs_restored(num_tabs_restored); | 375 sampled_profile->set_num_tabs_restored(num_tabs_restored); |
| 375 | 376 |
| 376 CollectIfNecessary(sampled_profile.Pass()); | 377 CollectIfNecessary(sampled_profile.Pass()); |
| 377 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 378 last_session_restore_collection_time_ = base::TimeTicks::Now(); |
| 378 } | 379 } |
| 379 | 380 |
| 380 } // namespace metrics | 381 } // namespace metrics |
| OLD | NEW |