summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authormotek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-20 17:16:45 +0000
committermotek@chromium.org <motek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-20 17:16:45 +0000
commit14bb46691011873fc4d7f63951ea521fb521aa6a (patch)
treedc661631095dd855d76da80a111fcc749740386a /components
parenta90c8cae340737062a8ab03af4667a55ebac103c (diff)
downloadchromium_src-14bb46691011873fc4d7f63951ea521fb521aa6a.zip
chromium_src-14bb46691011873fc4d7f63951ea521fb521aa6a.tar.gz
chromium_src-14bb46691011873fc4d7f63951ea521fb521aa6a.tar.bz2
Moved metrics_reporting_scheduler* to //components/metrics.
Automove with some manual fixes. BUG=374214 Review URL: https://codereview.chromium.org/294693002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271676 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/components_tests.gyp1
-rw-r--r--components/metrics.gypi2
-rw-r--r--components/metrics/metrics_reporting_scheduler.cc160
-rw-r--r--components/metrics/metrics_reporting_scheduler.h78
-rw-r--r--components/metrics/metrics_reporting_scheduler_unittest.cc58
5 files changed, 299 insertions, 0 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 6f2e098..64cf12b 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -107,6 +107,7 @@
'metrics/metrics_hashes_unittest.cc',
'metrics/metrics_log_base_unittest.cc',
'metrics/metrics_log_manager_unittest.cc',
+ 'metrics/metrics_reporting_scheduler_unittest.cc',
'metrics/persisted_logs_unittest.cc',
'navigation_interception/intercept_navigation_resource_throttle_unittest.cc',
'os_crypt/ie7_password_win_unittest.cc',
diff --git a/components/metrics.gypi b/components/metrics.gypi
index f7fdc23..a572cda 100644
--- a/components/metrics.gypi
+++ b/components/metrics.gypi
@@ -24,6 +24,8 @@
'metrics/metrics_log_manager.h',
'metrics/metrics_pref_names.cc',
'metrics/metrics_pref_names.h',
+ 'metrics/metrics_reporting_scheduler.cc',
+ 'metrics/metrics_reporting_scheduler.h',
'metrics/metrics_service_client.h',
'metrics/metrics_service_observer.cc',
'metrics/metrics_service_observer.h',
diff --git a/components/metrics/metrics_reporting_scheduler.cc b/components/metrics/metrics_reporting_scheduler.cc
new file mode 100644
index 0000000..4b67271b2
--- /dev/null
+++ b/components/metrics/metrics_reporting_scheduler.cc
@@ -0,0 +1,160 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/metrics_reporting_scheduler.h"
+
+#include "base/compiler_specific.h"
+#include "base/metrics/histogram.h"
+
+using base::TimeDelta;
+
+namespace {
+
+// The delay, in seconds, after startup before sending the first log message.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+// Sessions are more likely to be short on a mobile device, so handle the
+// initial log quickly.
+const int kInitialUploadIntervalSeconds = 15;
+#else
+const int kInitialUploadIntervalSeconds = 60;
+#endif
+
+// The delay, in seconds, between uploading when there are queued logs from
+// previous sessions to send.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+// Sending in a burst is better on a mobile device, since keeping the radio on
+// is very expensive.
+const int kUnsentLogsIntervalSeconds = 3;
+#else
+const int kUnsentLogsIntervalSeconds = 15;
+#endif
+
+// Standard interval between log uploads, in seconds.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+const int kStandardUploadIntervalSeconds = 5 * 60; // Five minutes.
+#else
+const int kStandardUploadIntervalSeconds = 30 * 60; // Thirty minutes.
+#endif
+
+// When uploading metrics to the server fails, we progressively wait longer and
+// longer before sending the next log. This backoff process helps reduce load
+// on a server that is having issues.
+// The following is the multiplier we use to expand that inter-log duration.
+const double kBackoffMultiplier = 1.1;
+
+// The maximum backoff multiplier.
+const int kMaxBackoffMultiplier = 10;
+
+enum InitSequence {
+ TIMER_FIRED_FIRST,
+ INIT_TASK_COMPLETED_FIRST,
+ INIT_SEQUENCE_ENUM_SIZE,
+};
+
+void LogMetricsInitSequence(InitSequence sequence) {
+ UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence,
+ INIT_SEQUENCE_ENUM_SIZE);
+}
+
+} // anonymous namespace
+
+MetricsReportingScheduler::MetricsReportingScheduler(
+ const base::Closure& upload_callback)
+ : upload_callback_(upload_callback),
+ upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
+ running_(false),
+ callback_pending_(false),
+ init_task_complete_(false),
+ waiting_for_init_task_complete_(false) {
+}
+
+MetricsReportingScheduler::~MetricsReportingScheduler() {}
+
+void MetricsReportingScheduler::Start() {
+ running_ = true;
+ ScheduleNextUpload();
+}
+
+void MetricsReportingScheduler::Stop() {
+ running_ = false;
+ if (upload_timer_.IsRunning())
+ upload_timer_.Stop();
+}
+
+// Callback from MetricsService when the startup init task has completed.
+void MetricsReportingScheduler::InitTaskComplete() {
+ DCHECK(!init_task_complete_);
+ init_task_complete_ = true;
+ if (waiting_for_init_task_complete_) {
+ waiting_for_init_task_complete_ = false;
+ TriggerUpload();
+ } else {
+ LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST);
+ }
+}
+
+void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
+ bool more_logs_remaining) {
+ DCHECK(callback_pending_);
+ callback_pending_ = false;
+ // If the server is having issues, back off. Otherwise, reset to default
+ // (unless there are more logs to send, in which case the next upload should
+ // happen sooner).
+ if (!server_is_healthy) {
+ BackOffUploadInterval();
+ } else if (more_logs_remaining) {
+ upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
+ } else {
+ upload_interval_ = TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
+ }
+
+ if (running_)
+ ScheduleNextUpload();
+}
+
+void MetricsReportingScheduler::UploadCancelled() {
+ DCHECK(callback_pending_);
+ callback_pending_ = false;
+ if (running_)
+ ScheduleNextUpload();
+}
+
+void MetricsReportingScheduler::SetUploadIntervalForTesting(
+ base::TimeDelta interval) {
+ upload_interval_ = interval;
+}
+
+void MetricsReportingScheduler::TriggerUpload() {
+ // If the timer fired before the init task has completed, don't trigger the
+ // upload yet - wait for the init task to complete and do it then.
+ if (!init_task_complete_) {
+ LogMetricsInitSequence(TIMER_FIRED_FIRST);
+ waiting_for_init_task_complete_ = true;
+ return;
+ }
+ callback_pending_ = true;
+ upload_callback_.Run();
+}
+
+void MetricsReportingScheduler::ScheduleNextUpload() {
+ DCHECK(running_);
+ if (upload_timer_.IsRunning() || callback_pending_)
+ return;
+
+ upload_timer_.Start(FROM_HERE, upload_interval_, this,
+ &MetricsReportingScheduler::TriggerUpload);
+}
+
+void MetricsReportingScheduler::BackOffUploadInterval() {
+ DCHECK_GT(kBackoffMultiplier, 1.0);
+ upload_interval_ = TimeDelta::FromMicroseconds(
+ static_cast<int64>(kBackoffMultiplier *
+ upload_interval_.InMicroseconds()));
+
+ TimeDelta max_interval = kMaxBackoffMultiplier *
+ TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
+ if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
+ upload_interval_ = max_interval;
+ }
+}
diff --git a/components/metrics/metrics_reporting_scheduler.h b/components/metrics/metrics_reporting_scheduler.h
new file mode 100644
index 0000000..7cdfad8
--- /dev/null
+++ b/components/metrics/metrics_reporting_scheduler.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_METRICS_REPORTING_SCHEDULER_H_
+#define COMPONENTS_METRICS_METRICS_REPORTING_SCHEDULER_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+// Scheduler task to drive a MetricsService object's uploading.
+class MetricsReportingScheduler {
+ public:
+ explicit MetricsReportingScheduler(const base::Closure& upload_callback);
+ ~MetricsReportingScheduler();
+
+ // Starts scheduling uploads. This in a no-op if the scheduler is already
+ // running, so it is safe to call more than once.
+ void Start();
+
+ // Stops scheduling uploads.
+ void Stop();
+
+ // Callback from MetricsService when the startup init task has completed.
+ void InitTaskComplete();
+
+ // Callback from MetricsService when a triggered upload finishes.
+ void UploadFinished(bool server_is_healthy, bool more_logs_remaining);
+
+ // Callback from MetricsService when a triggered upload is cancelled by the
+ // MetricsService.
+ void UploadCancelled();
+
+ // Sets the upload interval to a specific value, exposed for unit tests.
+ void SetUploadIntervalForTesting(base::TimeDelta interval);
+
+ private:
+ // Timer callback indicating it's time for the MetricsService to upload
+ // metrics.
+ void TriggerUpload();
+
+ // Schedules a future call to TriggerUpload if one isn't already pending.
+ void ScheduleNextUpload();
+
+ // Increases the upload interval each time it's called, to handle the case
+ // where the server is having issues.
+ void BackOffUploadInterval();
+
+ // The MetricsService method to call when uploading should happen.
+ const base::Closure upload_callback_;
+
+ base::OneShotTimer<MetricsReportingScheduler> upload_timer_;
+
+ // The interval between being told an upload is done and starting the next
+ // upload.
+ base::TimeDelta upload_interval_;
+
+ // Indicates that the scheduler is running (i.e., that Start has been called
+ // more recently than Stop).
+ bool running_;
+
+ // Indicates that the last triggered upload hasn't resolved yet.
+ bool callback_pending_;
+
+ // Whether the InitTaskComplete() callback has been called.
+ bool init_task_complete_;
+
+ // Whether the initial scheduled upload timer has fired before the init task
+ // has been completed.
+ bool waiting_for_init_task_complete_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsReportingScheduler);
+};
+
+#endif // COMPONENTS_METRICS_METRICS_REPORTING_SCHEDULER_H_
diff --git a/components/metrics/metrics_reporting_scheduler_unittest.cc b/components/metrics/metrics_reporting_scheduler_unittest.cc
new file mode 100644
index 0000000..f7a3d081
--- /dev/null
+++ b/components/metrics/metrics_reporting_scheduler_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/metrics_reporting_scheduler.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class MetricsReportingSchedulerTest : public testing::Test {
+ public:
+ MetricsReportingSchedulerTest() : callback_call_count_(0) {}
+ virtual ~MetricsReportingSchedulerTest() {}
+
+ base::Closure GetCallback() {
+ return base::Bind(&MetricsReportingSchedulerTest::SchedulerCallback,
+ base::Unretained(this));
+ }
+
+ int callback_call_count() const { return callback_call_count_; }
+
+ private:
+ void SchedulerCallback() {
+ ++callback_call_count_;
+ }
+
+ int callback_call_count_;
+
+ base::MessageLoopForUI message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsReportingSchedulerTest);
+};
+
+
+TEST_F(MetricsReportingSchedulerTest, InitTaskCompleteBeforeTimer) {
+ MetricsReportingScheduler scheduler(GetCallback());
+ scheduler.SetUploadIntervalForTesting(base::TimeDelta());
+ scheduler.InitTaskComplete();
+ scheduler.Start();
+ EXPECT_EQ(0, callback_call_count());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, callback_call_count());
+}
+
+TEST_F(MetricsReportingSchedulerTest, InitTaskCompleteAfterTimer) {
+ MetricsReportingScheduler scheduler(GetCallback());
+ scheduler.SetUploadIntervalForTesting(base::TimeDelta());
+ scheduler.Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, callback_call_count());
+
+ scheduler.InitTaskComplete();
+ EXPECT_EQ(1, callback_call_count());
+}