summaryrefslogtreecommitdiffstats
path: root/remoting/base
diff options
context:
space:
mode:
authorwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-24 03:53:39 +0000
committerwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-24 03:53:39 +0000
commit4fdd06284b47b856130fdf684e720e2eccc784ec (patch)
treef7c4798cf910b5f58e8d2c8c73eb1b6936445c50 /remoting/base
parent984aecc2429b5656d853cb1b9a70973fc477337c (diff)
downloadchromium_src-4fdd06284b47b856130fdf684e720e2eccc784ec.zip
chromium_src-4fdd06284b47b856130fdf684e720e2eccc784ec.tar.gz
chromium_src-4fdd06284b47b856130fdf684e720e2eccc784ec.tar.bz2
Add unit tests for sub-components of CaptureScheduler.
Unit tests are added for RateCounter, RunningAverage and CaptureScheduler. BUG=166275 Review URL: https://chromiumcodereview.appspot.com/12803008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190172 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/base')
-rw-r--r--remoting/base/rate_counter.cc31
-rw-r--r--remoting/base/rate_counter.h48
-rw-r--r--remoting/base/rate_counter_unittest.cc84
-rw-r--r--remoting/base/running_average.cc11
-rw-r--r--remoting/base/running_average.h36
-rw-r--r--remoting/base/running_average_unittest.cc56
6 files changed, 206 insertions, 60 deletions
diff --git a/remoting/base/rate_counter.cc b/remoting/base/rate_counter.cc
index fff9b6c..e6532da 100644
--- a/remoting/base/rate_counter.cc
+++ b/remoting/base/rate_counter.cc
@@ -4,36 +4,43 @@
#include "remoting/base/rate_counter.h"
+#include "base/logging.h"
+
namespace remoting {
RateCounter::RateCounter(base::TimeDelta time_window)
: time_window_(time_window),
sum_(0) {
+ DCHECK_GT(time_window.InMilliseconds(), 0);
}
RateCounter::~RateCounter() {
}
void RateCounter::Record(int64 value) {
- base::Time current_time = base::Time::Now();
- Evict(current_time);
+ DCHECK(CalledOnValidThread());
- base::AutoLock auto_lock(lock_);
+ base::Time current_time = CurrentTime();
+ EvictOldDataPoints(current_time);
sum_ += value;
data_points_.push(std::make_pair(current_time, value));
}
double RateCounter::Rate() {
- Evict(base::Time::Now());
+ DCHECK(CalledOnValidThread());
- base::AutoLock auto_lock(lock_);
- return static_cast<double>(base::Time::kMillisecondsPerSecond) * sum_ /
- time_window_.InMilliseconds();
+ EvictOldDataPoints(CurrentTime());
+ return sum_ / time_window_.InSecondsF();
}
-void RateCounter::Evict(base::Time current_time) {
- base::AutoLock auto_lock(lock_);
+void RateCounter::SetCurrentTimeForTest(base::Time current_time) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(current_time >= current_time_for_test_);
+
+ current_time_for_test_ = current_time;
+}
+void RateCounter::EvictOldDataPoints(base::Time current_time) {
// Remove data points outside of the window.
base::Time window_start = current_time - time_window_;
@@ -46,4 +53,10 @@ void RateCounter::Evict(base::Time current_time) {
}
}
+base::Time RateCounter::CurrentTime() const {
+ if (current_time_for_test_ == base::Time())
+ return base::Time::Now();
+ return current_time_for_test_;
+}
+
} // namespace remoting
diff --git a/remoting/base/rate_counter.h b/remoting/base/rate_counter.h
index c427b96..b5d3d7e 100644
--- a/remoting/base/rate_counter.h
+++ b/remoting/base/rate_counter.h
@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// RateCounter is defined to measure average rate over a given time window.
-// Rate is reported as the sum of values recorded divided by the time window.
-// This can be used for measuring bandwidth, bitrate, etc.
-
-// This class is thread-safe.
-
#ifndef REMOTING_BASE_RATE_COUNTER_H_
#define REMOTING_BASE_RATE_COUNTER_H_
@@ -15,44 +9,52 @@
#include <utility>
#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
+#include "base/threading/non_thread_safe.h"
#include "base/time.h"
namespace remoting {
-class RateCounter {
+// Measures average rate per second of a sequence of point rate samples
+// over a specified time window. This can be used to measure bandwidth, frame
+// rates, etc.
+class RateCounter : public base::NonThreadSafe {
public:
- // Construct a counter for a specific time window.
- RateCounter(base::TimeDelta time_window);
-
+ // Constructs a rate counter over the specified |time_window|.
+ explicit RateCounter(base::TimeDelta time_window);
virtual ~RateCounter();
- // Record the data point.
+ // Records a point event count to include in the rate.
void Record(int64 value);
- // Report the rate recorded. At the beginning of recording the numbers before
- // |time_window| is reached the reported rate will not be accurate.
+ // Returns the rate-per-second of values recorded over the time window.
+ // Note that rates reported before |time_window| has elapsed are not accurate.
double Rate();
- private:
- // Helper function to evict old data points.
- void Evict(base::Time current_time);
+ // Overrides the current time for testing.
+ void SetCurrentTimeForTest(base::Time current_time);
- // A data point consists of a timestamp and a data value.
+ private:
+ // Type used to store data points with timestamps.
typedef std::pair<base::Time, int64> DataPoint;
- // Duration of the time window.
- base::TimeDelta time_window_;
+ // Removes data points more than |time_window| older than |current_time|.
+ void EvictOldDataPoints(base::Time current_time);
+
+ // Returns the current time specified for test, if set, or base::Time::Now().
+ base::Time CurrentTime() const;
- // Protects |data_points_| and |sum_|.
- base::Lock lock_;
+ // Time window over which to calculate the rate.
+ const base::TimeDelta time_window_;
- // Keep the values of all the data points in a queue.
+ // Queue containing data points in the order in which they were recorded.
std::queue<DataPoint> data_points_;
// Sum of values in |data_points_|.
int64 sum_;
+ // If set, used to calculate the running average, in place of Now().
+ base::Time current_time_for_test_;
+
DISALLOW_COPY_AND_ASSIGN(RateCounter);
};
diff --git a/remoting/base/rate_counter_unittest.cc b/remoting/base/rate_counter_unittest.cc
new file mode 100644
index 0000000..cf5962d
--- /dev/null
+++ b/remoting/base/rate_counter_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright 2013 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 "remoting/base/rate_counter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+static const int64 kTestValues[] = { 10, 20, 30, 10, 25, 16, 15 };
+
+// One second window and one sample per second, so rate equals each sample.
+TEST(RateCounterTest, OneSecondWindow) {
+ RateCounter rate_counter(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(0, rate_counter.Rate());
+
+ base::Time now = base::Time::Now();
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ now += base::TimeDelta::FromSeconds(1);
+ rate_counter.SetCurrentTimeForTest(now);
+ rate_counter.Record(kTestValues[i]);
+ EXPECT_EQ(static_cast<double>(kTestValues[i]), rate_counter.Rate());
+ }
+}
+
+// Record all samples instantaneously, so the rate is the total of the samples.
+TEST(RateCounterTest, OneSecondWindowAllSamples) {
+ RateCounter rate_counter(base::TimeDelta::FromSeconds(1));
+ EXPECT_EQ(0, rate_counter.Rate());
+
+ rate_counter.SetCurrentTimeForTest(base::Time::Now());
+
+ double expected = 0.0;
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ rate_counter.Record(kTestValues[i]);
+ expected += kTestValues[i];
+ }
+
+ EXPECT_EQ(expected, rate_counter.Rate());
+}
+
+// Two second window, one sample per second. For all but the first sample, the
+// rate should be the average of it and the preceding one. For the first it
+// will be the average of the sample with zero.
+TEST(RateCounterTest, TwoSecondWindow) {
+ RateCounter rate_counter(base::TimeDelta::FromSeconds(2));
+ EXPECT_EQ(0, rate_counter.Rate());
+
+ base::Time now = base::Time::Now();
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ now += base::TimeDelta::FromSeconds(1);
+ rate_counter.SetCurrentTimeForTest(now);
+ rate_counter.Record(kTestValues[i]);
+ double expected = kTestValues[i];
+ if (i > 0)
+ expected += kTestValues[i-1];
+ expected /= 2;
+ EXPECT_EQ(expected, rate_counter.Rate());
+ }
+}
+
+// Sample over a window one second shorter than the number of samples.
+// Rate should be the average of all but the first sample.
+TEST(RateCounterTest, LongWindow) {
+ const size_t kWindowSeconds = arraysize(kTestValues) - 1;
+
+ RateCounter rate_counter(base::TimeDelta::FromSeconds(kWindowSeconds));
+ EXPECT_EQ(0, rate_counter.Rate());
+
+ double expected = 0.0;
+ base::Time now = base::Time::Now();
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ now += base::TimeDelta::FromSeconds(1);
+ rate_counter.SetCurrentTimeForTest(now);
+ rate_counter.Record(kTestValues[i]);
+ if (i != 0)
+ expected += kTestValues[i];
+ }
+ expected /= kWindowSeconds;
+
+ EXPECT_EQ(expected, rate_counter.Rate());
+}
+
+} // namespace remoting
diff --git a/remoting/base/running_average.cc b/remoting/base/running_average.cc
index 4daa650..dd7c7be 100644
--- a/remoting/base/running_average.cc
+++ b/remoting/base/running_average.cc
@@ -2,22 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/logging.h"
#include "remoting/base/running_average.h"
+#include "base/logging.h"
+
namespace remoting {
RunningAverage::RunningAverage(int window_size)
: window_size_(window_size),
sum_(0) {
- CHECK(window_size_);
+ DCHECK_GT(window_size, 0);
}
RunningAverage::~RunningAverage() {
}
void RunningAverage::Record(int64 value) {
- base::AutoLock auto_lock(lock_);
+ DCHECK(CalledOnValidThread());
data_points_.push_back(value);
sum_ += value;
@@ -28,8 +29,8 @@ void RunningAverage::Record(int64 value) {
}
}
-double RunningAverage::Average() {
- base::AutoLock auto_lock(lock_);
+double RunningAverage::Average() const {
+ DCHECK(CalledOnValidThread());
if (data_points_.empty())
return 0;
diff --git a/remoting/base/running_average.h b/remoting/base/running_average.h
index bc556b9..042f773 100644
--- a/remoting/base/running_average.h
+++ b/remoting/base/running_average.h
@@ -2,50 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// RunningAverage defined in this file is used to generate statistics for
-// bandwidth, latency and other performance metrics for remoting. Usually
-// this data comes in as a stream and fluctuates a lot. They are processed by
-// this class to generate a more stable value by taking average within a
-// window of data points.
-
-// All classes defined are thread-safe.
-
#ifndef REMOTING_BASE_RUNNING_AVERAGE_H_
#define REMOTING_BASE_RUNNING_AVERAGE_H_
#include <deque>
#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
+#include "base/threading/non_thread_safe.h"
namespace remoting {
-class RunningAverage {
+// Calculates the average of the most recent N recorded samples.
+// This is typically used to smooth out random variation in point samples
+// over bandwidth, frame rate, etc.
+class RunningAverage : public base::NonThreadSafe {
public:
- // Construct a running average counter for a specific window size. The
- // |windows_size| most recent values are kept and the average is reported.
+ // Constructs a helper to average over the |window_size| most recent samples.
explicit RunningAverage(int window_size);
-
virtual ~RunningAverage();
- // Record the provided data point.
+ // Records a point sample.
void Record(int64 value);
- // Return the average of data points in the last window.
- double Average();
+ // Returns the average over up to |window_size| of the most recent samples.
+ double Average() const;
private:
- // Size of the window. This is of type size_t to avoid casting when comparing
+ // Stores the desired window size, as size_t to avoid casting when comparing
// with the size of |data_points_|.
- size_t window_size_;
-
- // Protects |data_points_| and |sum_|.
- base::Lock lock_;
+ const size_t window_size_;
- // Keep the values of all the data points.
+ // Stores the |window_size| most recently recorded samples.
std::deque<int64> data_points_;
- // Sum of values in |data_points_|.
+ // Holds the sum of the samples in |data_points_|.
int64 sum_;
DISALLOW_COPY_AND_ASSIGN(RunningAverage);
diff --git a/remoting/base/running_average_unittest.cc b/remoting/base/running_average_unittest.cc
new file mode 100644
index 0000000..709abd6
--- /dev/null
+++ b/remoting/base/running_average_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2013 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 "remoting/base/running_average.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+static const int64 kTestValues[] = { 10, 20, 30, 10, 25, 16, 15 };
+
+// Average across a single element, i.e. just return the most recent.
+TEST(RunningAverageTest, OneElementWindow) {
+ RunningAverage running_average(1);
+ EXPECT_EQ(0, running_average.Average());
+
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ running_average.Record(kTestValues[i]);
+ EXPECT_EQ(static_cast<double>(kTestValues[i]), running_average.Average());
+ }
+}
+
+// Average the two most recent elements.
+TEST(RunningAverageTest, TwoElementWindow) {
+ RunningAverage running_average(2);
+ EXPECT_EQ(0, running_average.Average());
+
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ running_average.Record(kTestValues[i]);
+
+ double expected = kTestValues[i];
+ if (i > 0)
+ expected = (expected + kTestValues[i-1]) / 2;
+
+ EXPECT_EQ(expected, running_average.Average());
+ }
+}
+
+// Average across all the elements if the window size exceeds the element count.
+TEST(RunningAverageTest, LongWindow) {
+ RunningAverage running_average(arraysize(kTestValues) + 1);
+ EXPECT_EQ(0, running_average.Average());
+
+ for (size_t i = 0; i < arraysize(kTestValues); ++i) {
+ running_average.Record(kTestValues[i]);
+
+ double expected = 0.0;
+ for (size_t j = 0; j <= i; ++j)
+ expected += kTestValues[j];
+ expected /= i + 1;
+
+ EXPECT_EQ(expected, running_average.Average());
+ }
+}
+
+} // namespace remoting