Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / components / metrics / metrics_reporting_scheduler.cc
blob53c0cc553f26bac20f89bc18339caadd4d01ef60
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/field_trial.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "components/variations/variations_associated_data.h"
13 using base::TimeDelta;
15 namespace metrics {
17 namespace {
19 // The delay, in seconds, after startup before sending the first log message.
20 #if defined(OS_ANDROID) || defined(OS_IOS)
21 // Sessions are more likely to be short on a mobile device, so handle the
22 // initial log quickly.
23 const int kInitialUploadIntervalSeconds = 15;
24 #else
25 const int kInitialUploadIntervalSeconds = 60;
26 #endif
28 // The delay, in seconds, between uploading when there are queued logs from
29 // previous sessions to send.
30 #if defined(OS_ANDROID) || defined(OS_IOS)
31 // Sending in a burst is better on a mobile device, since keeping the radio on
32 // is very expensive.
33 const int kUnsentLogsIntervalSeconds = 3;
34 #else
35 const int kUnsentLogsIntervalSeconds = 15;
36 #endif
38 // Standard interval between log uploads, in seconds.
39 #if defined(OS_ANDROID) || defined(OS_IOS)
40 const int kStandardUploadIntervalSeconds = 5 * 60; // Five minutes.
41 #else
42 const int kStandardUploadIntervalSeconds = 30 * 60; // Thirty minutes.
43 #endif
45 // When uploading metrics to the server fails, we progressively wait longer and
46 // longer before sending the next log. This backoff process helps reduce load
47 // on a server that is having issues.
48 // The following is the multiplier we use to expand that inter-log duration.
49 const double kBackoffMultiplier = 1.1;
51 // The maximum backoff multiplier.
52 const int kMaxBackoffMultiplier = 10;
54 enum InitSequence {
55 TIMER_FIRED_FIRST,
56 INIT_TASK_COMPLETED_FIRST,
57 INIT_SEQUENCE_ENUM_SIZE,
60 void LogMetricsInitSequence(InitSequence sequence) {
61 UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence,
62 INIT_SEQUENCE_ENUM_SIZE);
65 void LogActualUploadInterval(TimeDelta interval) {
66 UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
67 interval.InMinutes(),
69 base::TimeDelta::FromHours(12).InMinutes(),
70 50);
73 // Returns upload interval specified for the current experiment running.
74 // TODO(gayane): Only for experimenting with upload interval for Android
75 // (bug: 17391128). Should be removed once the experiments are done.
76 base::TimeDelta GetUploadIntervalFromExperiment() {
77 std::string interval_str = variations::GetVariationParamValue(
78 "UMALogUploadInterval", "interval");
79 int interval;
80 if (interval_str.empty() || !base::StringToInt(interval_str, &interval))
81 return TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
83 return TimeDelta::FromMinutes(interval);
86 } // anonymous namespace
88 MetricsReportingScheduler::MetricsReportingScheduler(
89 const base::Closure& upload_callback)
90 : upload_callback_(upload_callback),
91 upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
92 running_(false),
93 callback_pending_(false),
94 init_task_complete_(false),
95 waiting_for_init_task_complete_(false) {
98 MetricsReportingScheduler::~MetricsReportingScheduler() {}
100 void MetricsReportingScheduler::Start() {
101 GetUploadIntervalFromExperiment();
102 running_ = true;
103 ScheduleNextUpload();
106 void MetricsReportingScheduler::Stop() {
107 running_ = false;
108 if (upload_timer_.IsRunning())
109 upload_timer_.Stop();
112 // Callback from MetricsService when the startup init task has completed.
113 void MetricsReportingScheduler::InitTaskComplete() {
114 DCHECK(!init_task_complete_);
115 init_task_complete_ = true;
116 if (waiting_for_init_task_complete_) {
117 waiting_for_init_task_complete_ = false;
118 TriggerUpload();
119 } else {
120 LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST);
124 void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
125 bool more_logs_remaining) {
126 DCHECK(callback_pending_);
127 callback_pending_ = false;
128 // If the server is having issues, back off. Otherwise, reset to default
129 // (unless there are more logs to send, in which case the next upload should
130 // happen sooner).
131 if (!server_is_healthy) {
132 BackOffUploadInterval();
133 } else if (more_logs_remaining) {
134 upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
135 } else {
136 upload_interval_ = GetStandardUploadInterval();
137 last_upload_finish_time_ = base::TimeTicks::Now();
140 if (running_)
141 ScheduleNextUpload();
144 void MetricsReportingScheduler::UploadCancelled() {
145 DCHECK(callback_pending_);
146 callback_pending_ = false;
147 if (running_)
148 ScheduleNextUpload();
151 void MetricsReportingScheduler::SetUploadIntervalForTesting(
152 base::TimeDelta interval) {
153 upload_interval_ = interval;
156 void MetricsReportingScheduler::TriggerUpload() {
157 // If the timer fired before the init task has completed, don't trigger the
158 // upload yet - wait for the init task to complete and do it then.
159 if (!init_task_complete_) {
160 LogMetricsInitSequence(TIMER_FIRED_FIRST);
161 waiting_for_init_task_complete_ = true;
162 return;
165 if (!last_upload_finish_time_.is_null()) {
166 LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
167 last_upload_finish_time_ = base::TimeTicks();
170 callback_pending_ = true;
171 upload_callback_.Run();
174 void MetricsReportingScheduler::ScheduleNextUpload() {
175 DCHECK(running_);
176 if (upload_timer_.IsRunning() || callback_pending_)
177 return;
179 upload_timer_.Start(FROM_HERE, upload_interval_, this,
180 &MetricsReportingScheduler::TriggerUpload);
183 void MetricsReportingScheduler::BackOffUploadInterval() {
184 DCHECK_GT(kBackoffMultiplier, 1.0);
185 upload_interval_ = TimeDelta::FromMicroseconds(
186 static_cast<int64>(kBackoffMultiplier *
187 upload_interval_.InMicroseconds()));
189 TimeDelta max_interval = kMaxBackoffMultiplier * GetStandardUploadInterval();
190 if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
191 upload_interval_ = max_interval;
195 base::TimeDelta MetricsReportingScheduler::GetStandardUploadInterval() {
196 #if defined(OS_ANDROID)
197 return GetUploadIntervalFromExperiment();
198 #else
199 return TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
200 #endif
203 } // namespace metrics