Moves SampleStats and EventRateCounter to rtc_base/numerics

Bug: webrtc:9883
Change-Id: I53934c86cad3b7cd60bba6c78e5db66c10e5d56a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159821
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29965}
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 2de8c4f..2b10d1e 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -577,6 +577,8 @@
   sources = [
     "numerics/event_based_exponential_moving_average.cc",
     "numerics/event_based_exponential_moving_average.h",
+    "numerics/event_rate_counter.cc",
+    "numerics/event_rate_counter.h",
     "numerics/exp_filter.cc",
     "numerics/exp_filter.h",
     "numerics/math_utils.h",
@@ -585,6 +587,8 @@
     "numerics/moving_median_filter.h",
     "numerics/percentile_filter.h",
     "numerics/running_statistics.h",
+    "numerics/sample_stats.cc",
+    "numerics/sample_stats.h",
     "numerics/samples_stats_counter.cc",
     "numerics/samples_stats_counter.h",
     "numerics/sequence_number_util.h",
@@ -594,6 +598,8 @@
     ":rtc_base_approved",
     ":safe_compare",
     "../api:array_view",
+    "../api/units:data_rate",
+    "../api/units:time_delta",
     "../api/units:timestamp",
     "//third_party/abseil-cpp/absl/algorithm:container",
     "//third_party/abseil-cpp/absl/types:optional",
diff --git a/rtc_base/numerics/event_rate_counter.cc b/rtc_base/numerics/event_rate_counter.cc
new file mode 100644
index 0000000..d7b7293
--- /dev/null
+++ b/rtc_base/numerics/event_rate_counter.cc
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/numerics/event_rate_counter.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+void EventRateCounter::AddEvent(Timestamp event_time) {
+  if (first_time_.IsFinite())
+    interval_.AddSample(event_time - last_time_);
+  first_time_ = std::min(first_time_, event_time);
+  last_time_ = std::max(last_time_, event_time);
+  event_count_++;
+}
+
+void EventRateCounter::AddEvents(EventRateCounter other) {
+  first_time_ = std::min(first_time_, other.first_time_);
+  last_time_ = std::max(last_time_, other.last_time_);
+  event_count_ += other.event_count_;
+  interval_.AddSamples(other.interval_);
+}
+
+bool EventRateCounter::IsEmpty() const {
+  return first_time_ == last_time_;
+}
+
+double EventRateCounter::Rate() const {
+  if (event_count_ == 0)
+    return 0;
+  if (event_count_ == 1)
+    return NAN;
+  return (event_count_ - 1) / (last_time_ - first_time_).seconds<double>();
+}
+
+TimeDelta EventRateCounter::TotalDuration() const {
+  if (first_time_.IsInfinite()) {
+    return TimeDelta::Zero();
+  }
+  return last_time_ - first_time_;
+}
+}  // namespace webrtc
diff --git a/rtc_base/numerics/event_rate_counter.h b/rtc_base/numerics/event_rate_counter.h
new file mode 100644
index 0000000..ebeac87
--- /dev/null
+++ b/rtc_base/numerics/event_rate_counter.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_
+#define RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_
+
+#include "rtc_base/numerics/sample_stats.h"
+
+namespace webrtc {
+
+// Calculates statistics based on events. For example for computing frame rates.
+// Note that it doesn't provide any running statistics or reset funcitonality,
+// so it's mostly useful for end of call statistics.
+class EventRateCounter {
+ public:
+  // Adds an event based on it's |event_time| for correct updates of the
+  // interval statistics, each event must be added past the previous events.
+  void AddEvent(Timestamp event_time);
+  // Adds the events from |other|. Note that the interval stats won't be
+  // recalculated, only merged, so this is not equivalent to if the events would
+  // have been added to the same counter from the start.
+  void AddEvents(EventRateCounter other);
+  bool IsEmpty() const;
+  // Average number of events per second. Defaults to 0 for no events and NAN
+  // for one event.
+  double Rate() const;
+  SampleStats<TimeDelta>& interval() { return interval_; }
+  TimeDelta TotalDuration() const;
+  int Count() const { return event_count_; }
+
+ private:
+  Timestamp first_time_ = Timestamp::PlusInfinity();
+  Timestamp last_time_ = Timestamp::MinusInfinity();
+  int64_t event_count_ = 0;
+  SampleStats<TimeDelta> interval_;
+};
+}  // namespace webrtc
+#endif  // RTC_BASE_NUMERICS_EVENT_RATE_COUNTER_H_
diff --git a/rtc_base/numerics/sample_stats.cc b/rtc_base/numerics/sample_stats.cc
new file mode 100644
index 0000000..7a6f01e
--- /dev/null
+++ b/rtc_base/numerics/sample_stats.cc
@@ -0,0 +1,152 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/numerics/sample_stats.h"
+
+namespace webrtc {
+
+double SampleStats<double>::Max() {
+  if (IsEmpty())
+    return INFINITY;
+  return GetMax();
+}
+
+double SampleStats<double>::Mean() {
+  if (IsEmpty())
+    return 0;
+  return GetAverage();
+}
+
+double SampleStats<double>::Median() {
+  return Quantile(0.5);
+}
+
+double SampleStats<double>::Quantile(double quantile) {
+  if (IsEmpty())
+    return 0;
+  return GetPercentile(quantile);
+}
+
+double SampleStats<double>::Min() {
+  if (IsEmpty())
+    return -INFINITY;
+  return GetMin();
+}
+
+double SampleStats<double>::Variance() {
+  if (IsEmpty())
+    return 0;
+  return GetVariance();
+}
+
+double SampleStats<double>::StandardDeviation() {
+  return sqrt(Variance());
+}
+
+int SampleStats<double>::Count() {
+  return static_cast<int>(GetSamples().size());
+}
+
+void SampleStats<TimeDelta>::AddSample(TimeDelta delta) {
+  RTC_DCHECK(delta.IsFinite());
+  stats_.AddSample(delta.seconds<double>());
+}
+
+void SampleStats<TimeDelta>::AddSampleMs(double delta_ms) {
+  AddSample(TimeDelta::ms(delta_ms));
+}
+void SampleStats<TimeDelta>::AddSamples(const SampleStats<TimeDelta>& other) {
+  stats_.AddSamples(other.stats_);
+}
+
+bool SampleStats<TimeDelta>::IsEmpty() {
+  return stats_.IsEmpty();
+}
+
+TimeDelta SampleStats<TimeDelta>::Max() {
+  return TimeDelta::seconds(stats_.Max());
+}
+
+TimeDelta SampleStats<TimeDelta>::Mean() {
+  return TimeDelta::seconds(stats_.Mean());
+}
+
+TimeDelta SampleStats<TimeDelta>::Median() {
+  return Quantile(0.5);
+}
+
+TimeDelta SampleStats<TimeDelta>::Quantile(double quantile) {
+  return TimeDelta::seconds(stats_.Quantile(quantile));
+}
+
+TimeDelta SampleStats<TimeDelta>::Min() {
+  return TimeDelta::seconds(stats_.Min());
+}
+
+TimeDelta SampleStats<TimeDelta>::Variance() {
+  return TimeDelta::seconds(stats_.Variance());
+}
+
+TimeDelta SampleStats<TimeDelta>::StandardDeviation() {
+  return TimeDelta::seconds(stats_.StandardDeviation());
+}
+
+int SampleStats<TimeDelta>::Count() {
+  return stats_.Count();
+}
+
+void SampleStats<DataRate>::AddSample(DataRate sample) {
+  stats_.AddSample(sample.bps<double>());
+}
+
+void SampleStats<DataRate>::AddSampleBps(double rate_bps) {
+  stats_.AddSample(rate_bps);
+}
+
+void SampleStats<DataRate>::AddSamples(const SampleStats<DataRate>& other) {
+  stats_.AddSamples(other.stats_);
+}
+
+bool SampleStats<DataRate>::IsEmpty() {
+  return stats_.IsEmpty();
+}
+
+DataRate SampleStats<DataRate>::Max() {
+  return DataRate::bps(stats_.Max());
+}
+
+DataRate SampleStats<DataRate>::Mean() {
+  return DataRate::bps(stats_.Mean());
+}
+
+DataRate SampleStats<DataRate>::Median() {
+  return Quantile(0.5);
+}
+
+DataRate SampleStats<DataRate>::Quantile(double quantile) {
+  return DataRate::bps(stats_.Quantile(quantile));
+}
+
+DataRate SampleStats<DataRate>::Min() {
+  return DataRate::bps(stats_.Min());
+}
+
+DataRate SampleStats<DataRate>::Variance() {
+  return DataRate::bps(stats_.Variance());
+}
+
+DataRate SampleStats<DataRate>::StandardDeviation() {
+  return DataRate::bps(stats_.StandardDeviation());
+}
+
+int SampleStats<DataRate>::Count() {
+  return stats_.Count();
+}
+
+}  // namespace webrtc
diff --git a/rtc_base/numerics/sample_stats.h b/rtc_base/numerics/sample_stats.h
new file mode 100644
index 0000000..f634741
--- /dev/null
+++ b/rtc_base/numerics/sample_stats.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_NUMERICS_SAMPLE_STATS_H_
+#define RTC_BASE_NUMERICS_SAMPLE_STATS_H_
+
+#include "api/units/data_rate.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/numerics/samples_stats_counter.h"
+
+namespace webrtc {
+template <typename T>
+class SampleStats;
+
+// TODO(srte): Merge this implementation with SamplesStatsCounter.
+template <>
+class SampleStats<double> : public SamplesStatsCounter {
+ public:
+  double Max();
+  double Mean();
+  double Median();
+  double Quantile(double quantile);
+  double Min();
+  double Variance();
+  double StandardDeviation();
+  int Count();
+};
+
+template <>
+class SampleStats<TimeDelta> {
+ public:
+  void AddSample(TimeDelta delta);
+  void AddSampleMs(double delta_ms);
+  void AddSamples(const SampleStats<TimeDelta>& other);
+  bool IsEmpty();
+  TimeDelta Max();
+  TimeDelta Mean();
+  TimeDelta Median();
+  TimeDelta Quantile(double quantile);
+  TimeDelta Min();
+  TimeDelta Variance();
+  TimeDelta StandardDeviation();
+  int Count();
+
+ private:
+  SampleStats<double> stats_;
+};
+
+template <>
+class SampleStats<DataRate> {
+ public:
+  void AddSample(DataRate rate);
+  void AddSampleBps(double rate_bps);
+  void AddSamples(const SampleStats<DataRate>& other);
+  bool IsEmpty();
+  DataRate Max();
+  DataRate Mean();
+  DataRate Median();
+  DataRate Quantile(double quantile);
+  DataRate Min();
+  DataRate Variance();
+  DataRate StandardDeviation();
+  int Count();
+
+ private:
+  SampleStats<double> stats_;
+};
+}  // namespace webrtc
+
+#endif  // RTC_BASE_NUMERICS_SAMPLE_STATS_H_
diff --git a/test/scenario/performance_stats.cc b/test/scenario/performance_stats.cc
index 5f5b506..e12be8a 100644
--- a/test/scenario/performance_stats.cc
+++ b/test/scenario/performance_stats.cc
@@ -13,178 +13,6 @@
 
 namespace webrtc {
 namespace test {
-void EventRateCounter::AddEvent(Timestamp event_time) {
-  if (first_time_.IsFinite())
-    interval_.AddSample(event_time - last_time_);
-  first_time_ = std::min(first_time_, event_time);
-  last_time_ = std::max(last_time_, event_time);
-  event_count_++;
-}
-
-void EventRateCounter::AddEvents(EventRateCounter other) {
-  first_time_ = std::min(first_time_, other.first_time_);
-  last_time_ = std::max(last_time_, other.last_time_);
-  event_count_ += other.event_count_;
-  interval_.AddSamples(other.interval_);
-}
-
-bool EventRateCounter::IsEmpty() const {
-  return first_time_ == last_time_;
-}
-
-double EventRateCounter::Rate() const {
-  if (event_count_ == 0)
-    return 0;
-  if (event_count_ == 1)
-    return NAN;
-  return (event_count_ - 1) / (last_time_ - first_time_).seconds<double>();
-}
-
-TimeDelta EventRateCounter::TotalDuration() const {
-  if (first_time_.IsInfinite()) {
-    return TimeDelta::Zero();
-  }
-  return last_time_ - first_time_;
-}
-
-double SampleStats<double>::Max() {
-  if (IsEmpty())
-    return INFINITY;
-  return GetMax();
-}
-
-double SampleStats<double>::Mean() {
-  if (IsEmpty())
-    return 0;
-  return GetAverage();
-}
-
-double SampleStats<double>::Median() {
-  return Quantile(0.5);
-}
-
-double SampleStats<double>::Quantile(double quantile) {
-  if (IsEmpty())
-    return 0;
-  return GetPercentile(quantile);
-}
-
-double SampleStats<double>::Min() {
-  if (IsEmpty())
-    return -INFINITY;
-  return GetMin();
-}
-
-double SampleStats<double>::Variance() {
-  if (IsEmpty())
-    return 0;
-  return GetVariance();
-}
-
-double SampleStats<double>::StandardDeviation() {
-  return sqrt(Variance());
-}
-
-int SampleStats<double>::Count() {
-  return static_cast<int>(GetSamples().size());
-}
-
-void SampleStats<TimeDelta>::AddSample(TimeDelta delta) {
-  RTC_DCHECK(delta.IsFinite());
-  stats_.AddSample(delta.seconds<double>());
-}
-
-void SampleStats<TimeDelta>::AddSampleMs(double delta_ms) {
-  AddSample(TimeDelta::ms(delta_ms));
-}
-void SampleStats<TimeDelta>::AddSamples(const SampleStats<TimeDelta>& other) {
-  stats_.AddSamples(other.stats_);
-}
-
-bool SampleStats<TimeDelta>::IsEmpty() {
-  return stats_.IsEmpty();
-}
-
-TimeDelta SampleStats<TimeDelta>::Max() {
-  return TimeDelta::seconds(stats_.Max());
-}
-
-TimeDelta SampleStats<TimeDelta>::Mean() {
-  return TimeDelta::seconds(stats_.Mean());
-}
-
-TimeDelta SampleStats<TimeDelta>::Median() {
-  return Quantile(0.5);
-}
-
-TimeDelta SampleStats<TimeDelta>::Quantile(double quantile) {
-  return TimeDelta::seconds(stats_.Quantile(quantile));
-}
-
-TimeDelta SampleStats<TimeDelta>::Min() {
-  return TimeDelta::seconds(stats_.Min());
-}
-
-TimeDelta SampleStats<TimeDelta>::Variance() {
-  return TimeDelta::seconds(stats_.Variance());
-}
-
-TimeDelta SampleStats<TimeDelta>::StandardDeviation() {
-  return TimeDelta::seconds(stats_.StandardDeviation());
-}
-
-int SampleStats<TimeDelta>::Count() {
-  return stats_.Count();
-}
-
-void SampleStats<DataRate>::AddSample(DataRate sample) {
-  stats_.AddSample(sample.bps<double>());
-}
-
-void SampleStats<DataRate>::AddSampleBps(double rate_bps) {
-  stats_.AddSample(rate_bps);
-}
-
-void SampleStats<DataRate>::AddSamples(const SampleStats<DataRate>& other) {
-  stats_.AddSamples(other.stats_);
-}
-
-bool SampleStats<DataRate>::IsEmpty() {
-  return stats_.IsEmpty();
-}
-
-DataRate SampleStats<DataRate>::Max() {
-  return DataRate::bps(stats_.Max());
-}
-
-DataRate SampleStats<DataRate>::Mean() {
-  return DataRate::bps(stats_.Mean());
-}
-
-DataRate SampleStats<DataRate>::Median() {
-  return Quantile(0.5);
-}
-
-DataRate SampleStats<DataRate>::Quantile(double quantile) {
-  return DataRate::bps(stats_.Quantile(quantile));
-}
-
-DataRate SampleStats<DataRate>::Min() {
-  return DataRate::bps(stats_.Min());
-}
-
-DataRate SampleStats<DataRate>::Variance() {
-  return DataRate::bps(stats_.Variance());
-}
-
-DataRate SampleStats<DataRate>::StandardDeviation() {
-  return DataRate::bps(stats_.StandardDeviation());
-}
-
-int SampleStats<DataRate>::Count() {
-  return stats_.Count();
-}
-
 void VideoFramesStats::AddFrameInfo(const VideoFrameBuffer& frame,
                                     Timestamp at_time) {
   ++count;
diff --git a/test/scenario/performance_stats.h b/test/scenario/performance_stats.h
index 310ee8d..6974ab6 100644
--- a/test/scenario/performance_stats.h
+++ b/test/scenario/performance_stats.h
@@ -14,7 +14,8 @@
 #include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
 #include "api/video/video_frame_buffer.h"
-#include "rtc_base/numerics/samples_stats_counter.h"
+#include "rtc_base/numerics/event_rate_counter.h"
+#include "rtc_base/numerics/sample_stats.h"
 
 namespace webrtc {
 namespace test {
@@ -36,78 +37,6 @@
   int repeated = 0;
 };
 
-template <typename T>
-class SampleStats;
-
-template <>
-class SampleStats<double> : public SamplesStatsCounter {
- public:
-  double Max();
-  double Mean();
-  double Median();
-  double Quantile(double quantile);
-  double Min();
-  double Variance();
-  double StandardDeviation();
-  int Count();
-};
-
-template <>
-class SampleStats<TimeDelta> {
- public:
-  void AddSample(TimeDelta delta);
-  void AddSampleMs(double delta_ms);
-  void AddSamples(const SampleStats<TimeDelta>& other);
-  bool IsEmpty();
-  TimeDelta Max();
-  TimeDelta Mean();
-  TimeDelta Median();
-  TimeDelta Quantile(double quantile);
-  TimeDelta Min();
-  TimeDelta Variance();
-  TimeDelta StandardDeviation();
-  int Count();
-
- private:
-  SampleStats<double> stats_;
-};
-
-template <>
-class SampleStats<DataRate> {
- public:
-  void AddSample(DataRate rate);
-  void AddSampleBps(double rate_bps);
-  void AddSamples(const SampleStats<DataRate>& other);
-  bool IsEmpty();
-  DataRate Max();
-  DataRate Mean();
-  DataRate Median();
-  DataRate Quantile(double quantile);
-  DataRate Min();
-  DataRate Variance();
-  DataRate StandardDeviation();
-  int Count();
-
- private:
-  SampleStats<double> stats_;
-};
-
-class EventRateCounter {
- public:
-  void AddEvent(Timestamp event_time);
-  void AddEvents(EventRateCounter other);
-  bool IsEmpty() const;
-  double Rate() const;
-  SampleStats<TimeDelta>& interval() { return interval_; }
-  TimeDelta TotalDuration() const;
-  int Count() const { return event_count_; }
-
- private:
-  Timestamp first_time_ = Timestamp::PlusInfinity();
-  Timestamp last_time_ = Timestamp::MinusInfinity();
-  int64_t event_count_ = 0;
-  SampleStats<TimeDelta> interval_;
-};
 
 struct VideoFramesStats {
   int count = 0;