Roll src/third_party/skia de7665a:76033be
[chromium-blink-merge.git] / components / metrics / metrics_reporting_scheduler.cc
blob1318b22b3abbdab366f7e2e1d624fdfff663280f
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/metrics/metrics_reporting_scheduler.h"
7 #include "base/compiler_specific.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "components/variations/variations_associated_data.h"
12 using base::TimeDelta;
14 namespace metrics {
16 namespace {
18 // The delay, in seconds, after startup before sending the first log message.
19 #if defined(OS_ANDROID) || defined(OS_IOS)
20 // Sessions are more likely to be short on a mobile device, so handle the
21 // initial log quickly.
22 const int kInitialUploadIntervalSeconds = 15;
23 #else
24 const int kInitialUploadIntervalSeconds = 60;
25 #endif
27 // The delay, in seconds, between uploading when there are queued logs from
28 // previous sessions to send.
29 #if defined(OS_ANDROID) || defined(OS_IOS)
30 // Sending in a burst is better on a mobile device, since keeping the radio on
31 // is very expensive.
32 const int kUnsentLogsIntervalSeconds = 3;
33 #else
34 const int kUnsentLogsIntervalSeconds = 15;
35 #endif
37 // When uploading metrics to the server fails, we progressively wait longer and
38 // longer before sending the next log. This backoff process helps reduce load
39 // on a server that is having issues.
40 // The following is the multiplier we use to expand that inter-log duration.
41 const double kBackoffMultiplier = 1.1;
43 // The maximum backoff multiplier.
44 const int kMaxBackoffMultiplier = 10;
46 enum InitSequence {
47 TIMER_FIRED_FIRST,
48 INIT_TASK_COMPLETED_FIRST,
49 INIT_SEQUENCE_ENUM_SIZE,
52 void LogMetricsInitSequence(InitSequence sequence) {
53 UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence,
54 INIT_SEQUENCE_ENUM_SIZE);
57 void LogActualUploadInterval(TimeDelta interval) {
58 UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
59 interval.InMinutes(),
61 base::TimeDelta::FromHours(12).InMinutes(),
62 50);
65 } // anonymous namespace
67 MetricsReportingScheduler::MetricsReportingScheduler(
68 const base::Closure& upload_callback,
69 const base::Callback<base::TimeDelta(void)>& upload_interval_callback)
70 : upload_callback_(upload_callback),
71 upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
72 running_(false),
73 callback_pending_(false),
74 init_task_complete_(false),
75 waiting_for_init_task_complete_(false),
76 upload_interval_callback_(upload_interval_callback) {
79 MetricsReportingScheduler::~MetricsReportingScheduler() {}
81 void MetricsReportingScheduler::Start() {
82 running_ = true;
83 ScheduleNextUpload();
86 void MetricsReportingScheduler::Stop() {
87 running_ = false;
88 if (upload_timer_.IsRunning())
89 upload_timer_.Stop();
92 // Callback from MetricsService when the startup init task has completed.
93 void MetricsReportingScheduler::InitTaskComplete() {
94 DCHECK(!init_task_complete_);
95 init_task_complete_ = true;
96 if (waiting_for_init_task_complete_) {
97 waiting_for_init_task_complete_ = false;
98 TriggerUpload();
99 } else {
100 LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST);
104 void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
105 bool more_logs_remaining) {
106 DCHECK(callback_pending_);
107 callback_pending_ = false;
108 // If the server is having issues, back off. Otherwise, reset to default
109 // (unless there are more logs to send, in which case the next upload should
110 // happen sooner).
111 if (!server_is_healthy) {
112 BackOffUploadInterval();
113 } else if (more_logs_remaining) {
114 upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
115 } else {
116 upload_interval_ = GetStandardUploadInterval();
117 last_upload_finish_time_ = base::TimeTicks::Now();
120 if (running_)
121 ScheduleNextUpload();
124 void MetricsReportingScheduler::UploadCancelled() {
125 DCHECK(callback_pending_);
126 callback_pending_ = false;
127 if (running_)
128 ScheduleNextUpload();
131 void MetricsReportingScheduler::SetUploadIntervalForTesting(
132 base::TimeDelta interval) {
133 upload_interval_ = interval;
136 void MetricsReportingScheduler::TriggerUpload() {
137 // If the timer fired before the init task has completed, don't trigger the
138 // upload yet - wait for the init task to complete and do it then.
139 if (!init_task_complete_) {
140 LogMetricsInitSequence(TIMER_FIRED_FIRST);
141 waiting_for_init_task_complete_ = true;
142 return;
145 if (!last_upload_finish_time_.is_null()) {
146 LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
147 last_upload_finish_time_ = base::TimeTicks();
150 callback_pending_ = true;
151 upload_callback_.Run();
154 void MetricsReportingScheduler::ScheduleNextUpload() {
155 DCHECK(running_);
156 if (upload_timer_.IsRunning() || callback_pending_)
157 return;
159 upload_timer_.Start(FROM_HERE, upload_interval_, this,
160 &MetricsReportingScheduler::TriggerUpload);
163 void MetricsReportingScheduler::BackOffUploadInterval() {
164 DCHECK_GT(kBackoffMultiplier, 1.0);
165 upload_interval_ = TimeDelta::FromMicroseconds(
166 static_cast<int64>(kBackoffMultiplier *
167 upload_interval_.InMicroseconds()));
169 TimeDelta max_interval = kMaxBackoffMultiplier * GetStandardUploadInterval();
170 if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
171 upload_interval_ = max_interval;
175 base::TimeDelta MetricsReportingScheduler::GetStandardUploadInterval() {
176 return upload_interval_callback_.Run();
179 } // namespace metrics