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 <string> | 5 #include <string> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/callback.h" | 9 #include "base/callback.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 // There may be too many session restores to collect a profile each time. Limit | 47 // There may be too many session restores to collect a profile each time. Limit |
48 // the collection rate by collecting one per 10 restores. Adjust this number as | 48 // the collection rate by collecting one per 10 restores. Adjust this number as |
49 // needed. | 49 // needed. |
50 const int kRestoreSessionSamplingFactor = 10; | 50 const int kRestoreSessionSamplingFactor = 10; |
51 | 51 |
52 // This is used to space out session restore collections in the face of several | 52 // This is used to space out session restore collections in the face of several |
53 // notifications in a short period of time. There should be no less than this | 53 // notifications in a short period of time. There should be no less than this |
54 // much time between collections. The current value is 30 seconds. | 54 // much time between collections. The current value is 30 seconds. |
55 const int kMinIntervalBetweenSessionRestoreCollectionsMs = 30 * 1000; | 55 const int kMinIntervalBetweenSessionRestoreCollectionsMs = 30 * 1000; |
56 | 56 |
57 // If collecting after a resume, add a random delay before collecting. The delay | |
58 // should be randomly selected between 0 and this value. Currently the value is | |
59 // equal to 5 seconds. | |
60 const int kMaxResumeCollectionDelayMs = 5 * 1000; | |
61 | |
62 // If collecting after a session restore, add a random delay before collecting. | |
63 // The delay should be randomly selected between 0 and this value. Currently the | |
64 // value is equal to 10 seconds. | |
65 const int kMaxRestoreSessionCollectionDelayMs = 10 * 1000; | |
66 | |
57 // Enumeration representing success and various failure modes for collecting and | 67 // Enumeration representing success and various failure modes for collecting and |
58 // sending perf data. | 68 // sending perf data. |
59 enum GetPerfDataOutcome { | 69 enum GetPerfDataOutcome { |
60 SUCCESS, | 70 SUCCESS, |
61 NOT_READY_TO_UPLOAD, | 71 NOT_READY_TO_UPLOAD, |
62 NOT_READY_TO_COLLECT, | 72 NOT_READY_TO_COLLECT, |
63 INCOGNITO_ACTIVE, | 73 INCOGNITO_ACTIVE, |
64 INCOGNITO_LAUNCHED, | 74 INCOGNITO_LAUNCHED, |
65 PROTOBUF_NOT_PARSED, | 75 PROTOBUF_NOT_PARSED, |
66 NUM_OUTCOMES | 76 NUM_OUTCOMES |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 // the lid or idling when not logged in is currently to shut down instead of | 193 // the lid or idling when not logged in is currently to shut down instead of |
184 // suspending. But it's good to enforce the rule here in case that changes. | 194 // suspending. But it's good to enforce the rule here in case that changes. |
185 if (!IsNormalUserLoggedIn()) | 195 if (!IsNormalUserLoggedIn()) |
186 return; | 196 return; |
187 | 197 |
188 // Collect a profile only 1/|kResumeSamplingFactor| of the time, to avoid | 198 // Collect a profile only 1/|kResumeSamplingFactor| of the time, to avoid |
189 // collecting too much data. | 199 // collecting too much data. |
190 if (base::RandGenerator(kResumeSamplingFactor) != 0) | 200 if (base::RandGenerator(kResumeSamplingFactor) != 0) |
191 return; | 201 return; |
192 | 202 |
193 // Fill out a SampledProfile protobuf that will contain the collected data. | 203 // Override any existing profiling. |
194 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 204 if (timer_.IsRunning()) |
195 sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND); | 205 timer_.Stop(); |
196 sampled_profile->set_suspend_duration_ms(sleep_duration.InMilliseconds()); | 206 |
197 // TODO(sque): Vary the time after resume at which to collect a profile. | 207 // Randomly pick a delay before doing the collection. |
198 // http://crbug.com/358778. | 208 base::TimeDelta collection_delay = |
199 sampled_profile->set_ms_after_resume(0); | 209 base::TimeDelta::FromMilliseconds( |
200 CollectIfNecessary(sampled_profile.Pass()); | 210 base::RandGenerator(kMaxResumeCollectionDelayMs)); |
211 timer_.Start(FROM_HERE, | |
212 collection_delay, | |
213 base::Bind(&PerfProvider::CollectPerfDataAfterResume, | |
214 weak_factory_.GetWeakPtr(), | |
215 sleep_duration, | |
216 collection_delay)); | |
201 } | 217 } |
202 | 218 |
203 void PerfProvider::Observe(int type, | 219 void PerfProvider::Observe(int type, |
204 const content::NotificationSource& source, | 220 const content::NotificationSource& source, |
205 const content::NotificationDetails& details) { | 221 const content::NotificationDetails& details) { |
206 // Only handle session restore notifications. | 222 // Only handle session restore notifications. |
207 DCHECK_EQ(type, chrome::NOTIFICATION_SESSION_RESTORE_DONE); | 223 DCHECK_EQ(type, chrome::NOTIFICATION_SESSION_RESTORE_DONE); |
208 | 224 |
225 // Do not collect a profile unless logged in as a normal user. | |
226 if (!IsNormalUserLoggedIn()) | |
227 return; | |
228 | |
209 // Collect a profile only 1/|kRestoreSessionSamplingFactor| of the time, to | 229 // Collect a profile only 1/|kRestoreSessionSamplingFactor| of the time, to |
210 // avoid collecting too much data and potentially causing UI latency. | 230 // avoid collecting too much data and potentially causing UI latency. |
211 if (base::RandGenerator(kRestoreSessionSamplingFactor) != 0) | 231 if (base::RandGenerator(kRestoreSessionSamplingFactor) != 0) |
212 return; | 232 return; |
213 | 233 |
214 const base::TimeDelta min_interval = | 234 const base::TimeDelta min_interval = |
215 base::TimeDelta::FromMilliseconds( | 235 base::TimeDelta::FromMilliseconds( |
216 kMinIntervalBetweenSessionRestoreCollectionsMs); | 236 kMinIntervalBetweenSessionRestoreCollectionsMs); |
217 const base::TimeDelta time_since_last_collection = | 237 const base::TimeDelta time_since_last_collection = |
218 (base::TimeTicks::Now() - last_session_restore_collection_time_); | 238 (base::TimeTicks::Now() - last_session_restore_collection_time_); |
219 // Do not collect if there hasn't been enough elapsed time since the last | 239 // Do not collect if there hasn't been enough elapsed time since the last |
220 // collection. | 240 // collection. |
221 if (!last_session_restore_collection_time_.is_null() && | 241 if (!last_session_restore_collection_time_.is_null() && |
222 time_since_last_collection < min_interval) { | 242 time_since_last_collection < min_interval) { |
223 return; | 243 return; |
224 } | 244 } |
225 | 245 |
226 // Fill out a SampledProfile protobuf that will contain the collected data. | 246 // Stop any existing scheduled collection. |
227 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 247 if (timer_.IsRunning()) |
228 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | 248 timer_.Stop(); |
229 // TODO(sque): Vary the time after restore at which to collect a profile, | |
230 // and find a way to determine the number of tabs restored. | |
231 // http://crbug.com/358778. | |
232 sampled_profile->set_ms_after_restore(0); | |
233 | 249 |
234 CollectIfNecessary(sampled_profile.Pass()); | 250 // Randomly pick a delay before doing the collection. |
235 last_session_restore_collection_time_ = base::TimeTicks::Now(); | 251 base::TimeDelta collection_delay = |
252 base::TimeDelta::FromMilliseconds( | |
253 base::RandGenerator(kMaxRestoreSessionCollectionDelayMs)); | |
254 timer_.Start( | |
255 FROM_HERE, | |
256 collection_delay, | |
257 base::Bind(&PerfProvider::CollectPerfDataAfterSessionRestore, | |
258 weak_factory_.GetWeakPtr(), | |
259 collection_delay)); | |
236 } | 260 } |
237 | 261 |
238 void PerfProvider::OnUserLoggedIn() { | 262 void PerfProvider::OnUserLoggedIn() { |
239 login_time_ = base::TimeTicks::Now(); | 263 login_time_ = base::TimeTicks::Now(); |
240 ScheduleCollection(); | 264 ScheduleIntervalCollection(); |
241 } | 265 } |
242 | 266 |
243 void PerfProvider::Deactivate() { | 267 void PerfProvider::Deactivate() { |
244 // Stop the timer, but leave |cached_perf_data_| intact. | 268 // Stop the timer, but leave |cached_perf_data_| intact. |
245 timer_.Stop(); | 269 timer_.Stop(); |
246 } | 270 } |
247 | 271 |
248 void PerfProvider::ScheduleCollection() { | 272 void PerfProvider::ScheduleIntervalCollection() { |
249 DCHECK(CalledOnValidThread()); | 273 DCHECK(CalledOnValidThread()); |
250 if (timer_.IsRunning()) | 274 if (timer_.IsRunning()) |
251 return; | 275 return; |
252 | 276 |
253 // Pick a random time in the current interval. | 277 // Pick a random time in the current interval. |
254 base::TimeTicks scheduled_time = | 278 base::TimeTicks scheduled_time = |
255 next_profiling_interval_start_ + | 279 next_profiling_interval_start_ + |
256 base::TimeDelta::FromMilliseconds( | 280 base::TimeDelta::FromMilliseconds( |
257 base::RandGenerator(kPerfProfilingIntervalMs)); | 281 base::RandGenerator(kPerfProfilingIntervalMs)); |
258 | 282 |
(...skipping 16 matching lines...) Expand all Loading... | |
275 DCHECK(CalledOnValidThread()); | 299 DCHECK(CalledOnValidThread()); |
276 | 300 |
277 // Do not collect further data if we've already collected a substantial amount | 301 // Do not collect further data if we've already collected a substantial amount |
278 // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|. | 302 // of data, as indicated by |kCachedPerfDataProtobufSizeThreshold|. |
279 size_t cached_perf_data_size = 0; | 303 size_t cached_perf_data_size = 0; |
280 for (size_t i = 0; i < cached_perf_data_.size(); ++i) { | 304 for (size_t i = 0; i < cached_perf_data_.size(); ++i) { |
281 cached_perf_data_size += cached_perf_data_[i].ByteSize(); | 305 cached_perf_data_size += cached_perf_data_[i].ByteSize(); |
282 } | 306 } |
283 if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) { | 307 if (cached_perf_data_size >= kCachedPerfDataProtobufSizeThreshold) { |
284 AddToPerfHistogram(NOT_READY_TO_COLLECT); | 308 AddToPerfHistogram(NOT_READY_TO_COLLECT); |
309 // Schedule the next interval-based perf collection. | |
310 ScheduleIntervalCollection(); | |
Ilya Sherman
2014/07/16 22:01:19
Why not just call this at the beginning of Collect
Simon Que
2014/07/16 22:26:54
Done.
| |
285 return; | 311 return; |
286 } | 312 } |
287 | 313 |
288 // For privacy reasons, Chrome should only collect perf data if there is no | 314 // For privacy reasons, Chrome should only collect perf data if there is no |
289 // incognito session active (or gets spawned during the collection). | 315 // incognito session active (or gets spawned during the collection). |
290 if (BrowserList::IsOffTheRecordSessionActive()) { | 316 if (BrowserList::IsOffTheRecordSessionActive()) { |
291 AddToPerfHistogram(INCOGNITO_ACTIVE); | 317 AddToPerfHistogram(INCOGNITO_ACTIVE); |
318 // Schedule the next interval-based perf collection. | |
319 ScheduleIntervalCollection(); | |
292 return; | 320 return; |
293 } | 321 } |
294 | 322 |
295 scoped_ptr<WindowedIncognitoObserver> incognito_observer( | 323 scoped_ptr<WindowedIncognitoObserver> incognito_observer( |
296 new WindowedIncognitoObserver); | 324 new WindowedIncognitoObserver); |
297 | 325 |
298 chromeos::DebugDaemonClient* client = | 326 chromeos::DebugDaemonClient* client = |
299 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 327 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
300 | 328 |
301 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( | 329 base::TimeDelta collection_duration = base::TimeDelta::FromSeconds( |
302 kPerfCommandDurationDefaultSeconds); | 330 kPerfCommandDurationDefaultSeconds); |
303 | 331 |
304 client->GetPerfData(collection_duration.InSeconds(), | 332 client->GetPerfData(collection_duration.InSeconds(), |
305 base::Bind(&PerfProvider::ParseProtoIfValid, | 333 base::Bind(&PerfProvider::ParseProtoIfValid, |
306 weak_factory_.GetWeakPtr(), | 334 weak_factory_.GetWeakPtr(), |
307 base::Passed(&incognito_observer), | 335 base::Passed(&incognito_observer), |
308 base::Passed(&sampled_profile))); | 336 base::Passed(&sampled_profile))); |
309 } | 337 } |
310 | 338 |
311 void PerfProvider::DoPeriodicCollection() { | 339 void PerfProvider::DoPeriodicCollection() { |
312 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | 340 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); |
313 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); | 341 sampled_profile->set_trigger_event(SampledProfile::PERIODIC_COLLECTION); |
314 | 342 |
315 CollectIfNecessary(sampled_profile.Pass()); | 343 CollectIfNecessary(sampled_profile.Pass()); |
316 ScheduleCollection(); | 344 } |
345 | |
346 void PerfProvider::CollectPerfDataAfterResume( | |
347 const base::TimeDelta& sleep_duration, | |
348 const base::TimeDelta& time_after_resume) { | |
349 // Fill out a SampledProfile protobuf that will contain the collected data. | |
350 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | |
351 sampled_profile->set_trigger_event(SampledProfile::RESUME_FROM_SUSPEND); | |
352 sampled_profile->set_suspend_duration_ms(sleep_duration.InMilliseconds()); | |
353 sampled_profile->set_ms_after_resume(time_after_resume.InMilliseconds()); | |
354 | |
355 CollectIfNecessary(sampled_profile.Pass()); | |
356 } | |
357 | |
358 void PerfProvider::CollectPerfDataAfterSessionRestore( | |
359 const base::TimeDelta& time_after_restore) { | |
360 // Fill out a SampledProfile protobuf that will contain the collected data. | |
361 scoped_ptr<SampledProfile> sampled_profile(new SampledProfile); | |
362 sampled_profile->set_trigger_event(SampledProfile::RESTORE_SESSION); | |
363 sampled_profile->set_ms_after_restore(time_after_restore.InMilliseconds()); | |
364 | |
365 CollectIfNecessary(sampled_profile.Pass()); | |
366 last_session_restore_collection_time_ = base::TimeTicks::Now(); | |
317 } | 367 } |
318 | 368 |
319 void PerfProvider::ParseProtoIfValid( | 369 void PerfProvider::ParseProtoIfValid( |
320 scoped_ptr<WindowedIncognitoObserver> incognito_observer, | 370 scoped_ptr<WindowedIncognitoObserver> incognito_observer, |
321 scoped_ptr<SampledProfile> sampled_profile, | 371 scoped_ptr<SampledProfile> sampled_profile, |
322 const std::vector<uint8>& data) { | 372 const std::vector<uint8>& data) { |
323 DCHECK(CalledOnValidThread()); | 373 DCHECK(CalledOnValidThread()); |
324 | 374 |
375 // Schedule another interval collection. This call makes sense regardless of | |
376 // whether or not the current collection was interval-triggered. If it had | |
377 // been another type of trigger event, the interval timer would have been | |
378 // halted, so it makes sense to reschedule a new interval collection. | |
379 ScheduleIntervalCollection(); | |
380 | |
325 if (incognito_observer->incognito_launched()) { | 381 if (incognito_observer->incognito_launched()) { |
326 AddToPerfHistogram(INCOGNITO_LAUNCHED); | 382 AddToPerfHistogram(INCOGNITO_LAUNCHED); |
327 return; | 383 return; |
328 } | 384 } |
329 | 385 |
330 PerfDataProto perf_data_proto; | 386 PerfDataProto perf_data_proto; |
331 if (!perf_data_proto.ParseFromArray(data.data(), data.size())) { | 387 if (!perf_data_proto.ParseFromArray(data.data(), data.size())) { |
332 AddToPerfHistogram(PROTOBUF_NOT_PARSED); | 388 AddToPerfHistogram(PROTOBUF_NOT_PARSED); |
333 return; | 389 return; |
334 } | 390 } |
(...skipping 11 matching lines...) Expand all Loading... | |
346 DCHECK(!login_time_.is_null()); | 402 DCHECK(!login_time_.is_null()); |
347 collection_data. | 403 collection_data. |
348 set_ms_after_login((base::TimeTicks::Now() - login_time_) | 404 set_ms_after_login((base::TimeTicks::Now() - login_time_) |
349 .InMilliseconds()); | 405 .InMilliseconds()); |
350 | 406 |
351 // Finally, store the perf data itself. | 407 // Finally, store the perf data itself. |
352 collection_data.mutable_perf_data()->Swap(&perf_data_proto); | 408 collection_data.mutable_perf_data()->Swap(&perf_data_proto); |
353 } | 409 } |
354 | 410 |
355 } // namespace metrics | 411 } // namespace metrics |
OLD | NEW |