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 | |
20 namespace { | 22 namespace { |
21 | 23 |
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 | 24 // 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 | 25 // too much memory. If the size of cached protobufs exceeds this value, stop |
31 // collecting further perf data. The current value is 4 MB. | 26 // collecting further perf data. The current value is 4 MB. |
32 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; | 27 const size_t kCachedPerfDataProtobufSizeThreshold = 4 * 1024 * 1024; |
33 | 28 |
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 | 29 // 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 | 30 // 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. | 31 // much time between collections. |
47 const int kMinIntervalBetweenSessionRestoreCollectionsMs = 30 * 1000; | 32 const base::TimeDelta kMinIntervalBetweenSessionRestoreCollections = |
Alexei Svitkine (slow)
2015/10/09 19:24:32
I'm not sure this is ok to do - I think this gener
dhsharp
2015/10/09 21:18:34
You're right. This is left over from when I though
| |
48 | 33 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 | 34 |
59 // Enumeration representing success and various failure modes for collecting and | 35 // Enumeration representing success and various failure modes for collecting and |
60 // sending perf data. | 36 // sending perf data. |
61 enum GetPerfDataOutcome { | 37 enum GetPerfDataOutcome { |
62 SUCCESS, | 38 SUCCESS, |
63 NOT_READY_TO_UPLOAD, | 39 NOT_READY_TO_UPLOAD, |
64 NOT_READY_TO_COLLECT, | 40 NOT_READY_TO_COLLECT, |
65 INCOGNITO_ACTIVE, | 41 INCOGNITO_ACTIVE, |
66 INCOGNITO_LAUNCHED, | 42 INCOGNITO_LAUNCHED, |
67 PROTOBUF_NOT_PARSED, | 43 PROTOBUF_NOT_PARSED, |
(...skipping 10 matching lines...) Expand all Loading... | |
78 outcome, | 54 outcome, |
79 NUM_OUTCOMES); | 55 NUM_OUTCOMES); |
80 } | 56 } |
81 | 57 |
82 // Returns true if a normal user is logged in. Returns false otherwise (e.g. if | 58 // 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). | 59 // logged in as a guest or as a kiosk app). |
84 bool IsNormalUserLoggedIn() { | 60 bool IsNormalUserLoggedIn() { |
85 return chromeos::LoginState::Get()->IsUserAuthenticated(); | 61 return chromeos::LoginState::Get()->IsUserAuthenticated(); |
86 } | 62 } |
87 | 63 |
64 // Returns a random TimeDelta between zero and |max|. | |
65 base::TimeDelta RandomTimeDelta(base::TimeDelta max) { | |
66 return base::TimeDelta::FromMicroseconds( | |
67 base::RandGenerator(max.InMicroseconds())); | |
68 } | |
69 | |
88 } // namespace | 70 } // namespace |
89 | 71 |
90 namespace metrics { | 72 PerfProvider::CollectionParams::CollectionParams( |
73 base::TimeDelta collection_duration, | |
74 base::TimeDelta periodic_interval, | |
75 TriggerParams resume_from_suspend, | |
76 TriggerParams restore_session) | |
77 : collection_duration_(collection_duration.ToInternalValue()), | |
78 periodic_interval_(periodic_interval.ToInternalValue()), | |
79 resume_from_suspend_(resume_from_suspend), | |
80 restore_session_(restore_session) { | |
81 } | |
82 | |
83 PerfProvider::CollectionParams::TriggerParams::TriggerParams( | |
84 int64 sampling_factor, | |
85 base::TimeDelta max_collection_delay) | |
86 : sampling_factor_(sampling_factor), | |
87 max_collection_delay_(max_collection_delay.ToInternalValue()) { | |
88 } | |
89 | |
90 const PerfProvider::CollectionParams kDefaultParameters( | |
Alexei Svitkine (slow)
2015/10/09 19:24:32
This should be in the anon namespace above.
dhsharp
2015/10/09 21:18:34
This actually doesn't compile (did I forget to try
| |
91 /* collection_duration = */ base::TimeDelta::FromSeconds(2), | |
92 /* periodic_interval = */ base::TimeDelta::FromHours(3), | |
93 /* resume_from_suspend = */ PerfProvider::CollectionParams::TriggerParams( | |
94 /* sampling_factor = */ 10, | |
95 /* max_collection_delay = */ base::TimeDelta::FromSeconds(5)), | |
96 /* restore_session = */ PerfProvider::CollectionParams::TriggerParams( | |
97 /* sampling_factor = */ 10, | |
98 /* max_collection_delay = */ base::TimeDelta::FromSeconds(10))); | |
91 | 99 |
92 PerfProvider::PerfProvider() | 100 PerfProvider::PerfProvider() |
93 : login_observer_(this), | 101 : collection_params_(kDefaultParameters), |
94 next_profiling_interval_start_(base::TimeTicks::Now()), | 102 login_observer_(this), |
95 weak_factory_(this) { | 103 next_profiling_interval_start_(base::TimeTicks::Now()), |
104 weak_factory_(this) { | |
96 // Register the login observer with LoginState. | 105 // Register the login observer with LoginState. |
97 chromeos::LoginState::Get()->AddObserver(&login_observer_); | 106 chromeos::LoginState::Get()->AddObserver(&login_observer_); |
98 | 107 |
99 // Register as an observer of power manager events. | 108 // Register as an observer of power manager events. |
100 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | 109 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> |
101 AddObserver(this); | 110 AddObserver(this); |
102 | 111 |
103 // Register as an observer of session restore. | 112 // Register as an observer of session restore. |
104 on_session_restored_callback_subscription_ = | 113 on_session_restored_callback_subscription_ = |
105 SessionRestore::RegisterOnSessionRestoredCallback( | 114 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. | 208 // canceled. Do not collect anything if that's the case. |
200 if (sleep_duration == base::TimeDelta()) | 209 if (sleep_duration == base::TimeDelta()) |
201 return; | 210 return; |
202 | 211 |
203 // Do not collect a profile unless logged in. The system behavior when closing | 212 // 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 | 213 // 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. | 214 // suspending. But it's good to enforce the rule here in case that changes. |
206 if (!IsNormalUserLoggedIn()) | 215 if (!IsNormalUserLoggedIn()) |
207 return; | 216 return; |
208 | 217 |
209 // Collect a profile only 1/|kResumeSamplingFactor| of the time, to avoid | 218 // Collect a profile only 1/|sampling_factor| of the time, to avoid |
210 // collecting too much data. | 219 // collecting too much data. |
211 if (base::RandGenerator(kResumeSamplingFactor) != 0) | 220 const auto& resume_params = collection_params_.resume_from_suspend(); |
221 if (base::RandGenerator(resume_params.sampling_factor()) != 0) | |
212 return; | 222 return; |
213 | 223 |
214 // Override any existing profiling. | 224 // Override any existing profiling. |
215 if (timer_.IsRunning()) | 225 if (timer_.IsRunning()) |
216 timer_.Stop(); | 226 timer_.Stop(); |
217 | 227 |
218 // Randomly pick a delay before doing the collection. | 228 // Randomly pick a delay before doing the collection. |
219 base::TimeDelta collection_delay = | 229 base::TimeDelta collection_delay = RandomTimeDelta( |
220 base::TimeDelta::FromMilliseconds( | 230 resume_params.max_collection_delay()); |
221 base::RandGenerator(kMaxResumeCollectionDelayMs)); | |
222 timer_.Start(FROM_HERE, | 231 timer_.Start(FROM_HERE, |
223 collection_delay, | 232 collection_delay, |
224 base::Bind(&PerfProvider::CollectPerfDataAfterResume, | 233 base::Bind(&PerfProvider::CollectPerfDataAfterResume, |
225 weak_factory_.GetWeakPtr(), | 234 weak_factory_.GetWeakPtr(), |
226 sleep_duration, | 235 sleep_duration, |
227 collection_delay)); | 236 collection_delay)); |
228 } | 237 } |
229 | 238 |
230 void PerfProvider::OnSessionRestoreDone(int num_tabs_restored) { | 239 void PerfProvider::OnSessionRestoreDone(int num_tabs_restored) { |
231 // Do not collect a profile unless logged in as a normal user. | 240 // Do not collect a profile unless logged in as a normal user. |
232 if (!IsNormalUserLoggedIn()) | 241 if (!IsNormalUserLoggedIn()) |
233 return; | 242 return; |
234 | 243 |
235 // Collect a profile only 1/|kRestoreSessionSamplingFactor| of the time, to | 244 // Collect a profile only 1/|sampling_factor| of the time, to |
236 // avoid collecting too much data and potentially causing UI latency. | 245 // avoid collecting too much data and potentially causing UI latency. |
237 if (base::RandGenerator(kRestoreSessionSamplingFactor) != 0) | 246 const auto& restore_params = collection_params_.restore_session(); |
247 if (base::RandGenerator(restore_params.sampling_factor()) != 0) | |
238 return; | 248 return; |
239 | 249 |
240 const base::TimeDelta min_interval = | 250 const auto min_interval = kMinIntervalBetweenSessionRestoreCollections; |
241 base::TimeDelta::FromMilliseconds( | |
242 kMinIntervalBetweenSessionRestoreCollectionsMs); | |
243 const base::TimeDelta time_since_last_collection = | 251 const base::TimeDelta time_since_last_collection = |
244 (base::TimeTicks::Now() - last_session_restore_collection_time_); | 252 (base::TimeTicks::Now() - last_session_restore_collection_time_); |
245 // Do not collect if there hasn't been enough elapsed time since the last | 253 // Do not collect if there hasn't been enough elapsed time since the last |
246 // collection. | 254 // collection. |
247 if (!last_session_restore_collection_time_.is_null() && | 255 if (!last_session_restore_collection_time_.is_null() && |
248 time_since_last_collection < min_interval) { | 256 time_since_last_collection < min_interval) { |
249 return; | 257 return; |
250 } | 258 } |
251 | 259 |
252 // Stop any existing scheduled collection. | 260 // Stop any existing scheduled collection. |
253 if (timer_.IsRunning()) | 261 if (timer_.IsRunning()) |
254 timer_.Stop(); | 262 timer_.Stop(); |
255 | 263 |
256 // Randomly pick a delay before doing the collection. | 264 // Randomly pick a delay before doing the collection. |
257 base::TimeDelta collection_delay = | 265 base::TimeDelta collection_delay = RandomTimeDelta( |
258 base::TimeDelta::FromMilliseconds( | 266 restore_params.max_collection_delay()); |
259 base::RandGenerator(kMaxRestoreSessionCollectionDelayMs)); | |
260 timer_.Start( | 267 timer_.Start( |
261 FROM_HERE, | 268 FROM_HERE, |
262 collection_delay, | 269 collection_delay, |
263 base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore, | 270 base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore, |
264 weak_factory_.GetWeakPtr(), | 271 weak_factory_.GetWeakPtr(), |
265 collection_delay, | 272 collection_delay, |
266 num_tabs_restored)); | 273 num_tabs_restored)); |
267 } | 274 } |
268 | 275 |
269 void PerfProvider::OnUserLoggedIn() { | 276 void PerfProvider::OnUserLoggedIn() { |
270 login_time_ = base::TimeTicks::Now(); | 277 login_time_ = base::TimeTicks::Now(); |
271 ScheduleIntervalCollection(); | 278 ScheduleIntervalCollection(); |
272 } | 279 } |
273 | 280 |
274 void PerfProvider::Deactivate() { | 281 void PerfProvider::Deactivate() { |
275 // Stop the timer, but leave |cached_perf_data_| intact. | 282 // Stop the timer, but leave |cached_perf_data_| intact. |
276 timer_.Stop(); | 283 timer_.Stop(); |
277 } | 284 } |
278 | 285 |
279 void PerfProvider::ScheduleIntervalCollection() { | 286 void PerfProvider::ScheduleIntervalCollection() { |
280 DCHECK(CalledOnValidThread()); | 287 DCHECK(CalledOnValidThread()); |
281 if (timer_.IsRunning()) | 288 if (timer_.IsRunning()) |
282 return; | 289 return; |
283 | 290 |
284 // Pick a random time in the current interval. | 291 // Pick a random time in the current interval. |
285 base::TimeTicks scheduled_time = | 292 base::TimeTicks scheduled_time = |
286 next_profiling_interval_start_ + | 293 next_profiling_interval_start_ + |
287 base::TimeDelta::FromMilliseconds( | 294 RandomTimeDelta(collection_params_.periodic_interval()); |
288 base::RandGenerator(kPerfProfilingIntervalMs)); | |
289 | 295 |
290 // If the scheduled time has already passed in the time it took to make the | 296 // If the scheduled time has already passed in the time it took to make the |
291 // above calculations, trigger the collection event immediately. | 297 // above calculations, trigger the collection event immediately. |
292 base::TimeTicks now = base::TimeTicks::Now(); | 298 base::TimeTicks now = base::TimeTicks::Now(); |
293 if (scheduled_time < now) | 299 if (scheduled_time < now) |
294 scheduled_time = now; | 300 scheduled_time = now; |
295 | 301 |
296 timer_.Start(FROM_HERE, scheduled_time - now, this, | 302 timer_.Start(FROM_HERE, scheduled_time - now, this, |
297 &PerfProvider::DoPeriodicCollection); | 303 &PerfProvider::DoPeriodicCollection); |
298 | 304 |
299 // Update the profiling interval tracker to the start of the next interval. | 305 // Update the profiling interval tracker to the start of the next interval. |
300 next_profiling_interval_start_ += | 306 next_profiling_interval_start_ += collection_params_.periodic_interval(); |
301 base::TimeDelta::FromMilliseconds(kPerfProfilingIntervalMs); | |
302 } | 307 } |
303 | 308 |
304 void PerfProvider::CollectIfNecessary( | 309 void PerfProvider::CollectIfNecessary( |
305 scoped_ptr<SampledProfile> sampled_profile) { | 310 scoped_ptr<SampledProfile> sampled_profile) { |
306 DCHECK(CalledOnValidThread()); | 311 DCHECK(CalledOnValidThread()); |
307 | 312 |
308 // Schedule another interval collection. This call makes sense regardless of | 313 // Schedule another interval collection. This call makes sense regardless of |
309 // whether or not the current collection was interval-triggered. If it had | 314 // 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 | 315 // been another type of trigger event, the interval timer would have been |
311 // halted, so it makes sense to reschedule a new interval collection. | 316 // halted, so it makes sense to reschedule a new interval collection. |
(...skipping 16 matching lines...) Expand all Loading... | |
328 AddToPerfHistogram(INCOGNITO_ACTIVE); | 333 AddToPerfHistogram(INCOGNITO_ACTIVE); |
329 return; | 334 return; |
330 } | 335 } |
331 | 336 |
332 scoped_ptr<WindowedIncognitoObserver> incognito_observer( | 337 scoped_ptr<WindowedIncognitoObserver> incognito_observer( |
333 new WindowedIncognitoObserver); | 338 new WindowedIncognitoObserver); |
334 | 339 |
335 chromeos::DebugDaemonClient* client = | 340 chromeos::DebugDaemonClient* client = |
336 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 341 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
337 | 342 |
338 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( | |
339 kPerfCommandDurationDefaultSeconds); | |
340 | |
341 client->GetPerfOutput( | 343 client->GetPerfOutput( |
342 collection_duration.InSeconds(), | 344 collection_params_.collection_duration().InSeconds(), |
343 base::Bind(&PerfProvider::ParseOutputProtoIfValid, | 345 base::Bind(&PerfProvider::ParseOutputProtoIfValid, |
344 weak_factory_.GetWeakPtr(), base::Passed(&incognito_observer), | 346 weak_factory_.GetWeakPtr(), base::Passed(&incognito_observer), |
345 base::Passed(&sampled_profile))); | 347 base::Passed(&sampled_profile))); |
346 } | 348 } |
347 | 349 |
348 void PerfProvider::DoPeriodicCollection() { | 350 void PerfProvider::DoPeriodicCollection() { |
349 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 351 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
350 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); | 352 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); |
351 | 353 |
352 CollectIfNecessary(sampled_profile.Pass()); | 354 CollectIfNecessary(sampled_profile.Pass()); |
(...skipping 18 matching lines...) Expand all Loading... | |
371 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 373 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
372 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 374 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); |
373 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | 375 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); |
374 sampled_profile->set_num_tabs_restored(num_tabs_restored); | 376 sampled_profile->set_num_tabs_restored(num_tabs_restored); |
375 | 377 |
376 CollectIfNecessary(sampled_profile.Pass()); | 378 CollectIfNecessary(sampled_profile.Pass()); |
377 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 379 last_session_restore_collection_time_ = base::TimeTicks::Now(); |
378 } | 380 } |
379 | 381 |
380 } // namespace metrics | 382 } // namespace metrics |
OLD | NEW |