diff options
author | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-24 03:53:39 +0000 |
---|---|---|
committer | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-24 03:53:39 +0000 |
commit | 4fdd06284b47b856130fdf684e720e2eccc784ec (patch) | |
tree | f7c4798cf910b5f58e8d2c8c73eb1b6936445c50 /remoting/base | |
parent | 984aecc2429b5656d853cb1b9a70973fc477337c (diff) | |
download | chromium_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.cc | 31 | ||||
-rw-r--r-- | remoting/base/rate_counter.h | 48 | ||||
-rw-r--r-- | remoting/base/rate_counter_unittest.cc | 84 | ||||
-rw-r--r-- | remoting/base/running_average.cc | 11 | ||||
-rw-r--r-- | remoting/base/running_average.h | 36 | ||||
-rw-r--r-- | remoting/base/running_average_unittest.cc | 56 |
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 |