a simple first step towards using clocks properly in the stats code
authorAdam Simpkins <simpkins@fb.com>
Thu, 15 Sep 2016 18:02:47 +0000 (11:02 -0700)
committerFacebook Github Bot 9 <facebook-github-bot-9-bot@fb.com>
Thu, 15 Sep 2016 18:08:27 +0000 (11:08 -0700)
Summary:
Update the timeseries and histogram classes to accept a clock parameter as a
template parameter, instead of a time duration type.

This is a first step towards transitioning the code to correctly distinguishing
between time_point and duration types.  This defines TimePoint and Duration
type aliases, but does not start using them yet.

In upcoming diffs I will start converting more APIs to correctly use TimePoint
instead of just Duration.

For now the default clock type is folly::LegacyStatsClock, which still uses
std::chrono::seconds as the default duration.  At the moment the stats code is
optimized for second granularity--the addValue() code has a fast path when
called in the same second as the last update.  When using finer granularity
durations this fast path can't be used as often.  I will also send out
subsequent diffs to make the code optimized for updates within the same bucket,
rather than just updates with the exact same time value.

Reviewed By: yfeldblum

Differential Revision: D3807715

fbshipit-source-id: 77696c4f44a8d85e4d6ff84d7656fe7a9709797c

folly/stats/BucketedTimeSeries-defs.h
folly/stats/BucketedTimeSeries.h
folly/stats/MultiLevelTimeSeries-defs.h
folly/stats/MultiLevelTimeSeries.h
folly/stats/TimeseriesHistogram-defs.h
folly/stats/TimeseriesHistogram.h

index a726f2ee54d517a4e2535eaa58d118ca9345a604..8941503cde88a28da7083929cc2f5a8836fa505a 100644 (file)
 
 namespace folly {
 
 
 namespace folly {
 
-template <typename VT, typename TT>
-BucketedTimeSeries<VT, TT>::BucketedTimeSeries(size_t nBuckets,
-                                               TimeType maxDuration)
-  : firstTime_(1),
-    latestTime_(0),
-    duration_(maxDuration) {
+template <typename VT, typename CT>
+BucketedTimeSeries<VT, CT>::BucketedTimeSeries(
+    size_t nBuckets,
+    TimeType maxDuration)
+    : firstTime_(1), latestTime_(0), duration_(maxDuration) {
   // For tracking all-time data we only use total_, and don't need to bother
   // with buckets_
   if (!isAllTime()) {
   // For tracking all-time data we only use total_, and don't need to bother
   // with buckets_
   if (!isAllTime()) {
@@ -43,22 +42,24 @@ BucketedTimeSeries<VT, TT>::BucketedTimeSeries(size_t nBuckets,
   }
 }
 
   }
 }
 
-template <typename VT, typename TT>
-bool BucketedTimeSeries<VT, TT>::addValue(TimeType now, const ValueType& val) {
+template <typename VT, typename CT>
+bool BucketedTimeSeries<VT, CT>::addValue(TimeType now, const ValueType& val) {
   return addValueAggregated(now, val, 1);
 }
 
   return addValueAggregated(now, val, 1);
 }
 
-template <typename VT, typename TT>
-bool BucketedTimeSeries<VT, TT>::addValue(TimeType now,
-                                          const ValueType& val,
-                                          int64_t times) {
+template <typename VT, typename CT>
+bool BucketedTimeSeries<VT, CT>::addValue(
+    TimeType now,
+    const ValueType& val,
+    int64_t times) {
   return addValueAggregated(now, val * times, times);
 }
 
   return addValueAggregated(now, val * times, times);
 }
 
-template <typename VT, typename TT>
-bool BucketedTimeSeries<VT, TT>::addValueAggregated(TimeType now,
-                                                    const ValueType& total,
-                                                    int64_t nsamples) {
+template <typename VT, typename CT>
+bool BucketedTimeSeries<VT, CT>::addValueAggregated(
+    TimeType now,
+    const ValueType& total,
+    int64_t nsamples) {
   if (isAllTime()) {
     if (UNLIKELY(empty())) {
       firstTime_ = now;
   if (isAllTime()) {
     if (UNLIKELY(empty())) {
       firstTime_ = now;
@@ -98,8 +99,8 @@ bool BucketedTimeSeries<VT, TT>::addValueAggregated(TimeType now,
   return true;
 }
 
   return true;
 }
 
-template <typename VT, typename TT>
-size_t BucketedTimeSeries<VT, TT>::update(TimeType now) {
+template <typename VT, typename CT>
+size_t BucketedTimeSeries<VT, CT>::update(TimeType now) {
   if (empty()) {
     // This is the first data point.
     firstTime_ = now;
   if (empty()) {
     // This is the first data point.
     firstTime_ = now;
@@ -121,8 +122,8 @@ size_t BucketedTimeSeries<VT, TT>::update(TimeType now) {
   return updateBuckets(now);
 }
 
   return updateBuckets(now);
 }
 
-template <typename VT, typename TT>
-size_t BucketedTimeSeries<VT, TT>::updateBuckets(TimeType now) {
+template <typename VT, typename CT>
+size_t BucketedTimeSeries<VT, CT>::updateBuckets(TimeType now) {
   // We could cache nextBucketStart as a member variable, so we don't have to
   // recompute it each time update() is called with a new timestamp value.
   // This makes things faster when update() (or addValue()) is called once
   // We could cache nextBucketStart as a member variable, so we don't have to
   // recompute it each time update() is called with a new timestamp value.
   // This makes things faster when update() (or addValue()) is called once
@@ -172,8 +173,8 @@ size_t BucketedTimeSeries<VT, TT>::updateBuckets(TimeType now) {
   }
 }
 
   }
 }
 
-template <typename VT, typename TT>
-void BucketedTimeSeries<VT, TT>::clear() {
+template <typename VT, typename CT>
+void BucketedTimeSeries<VT, CT>::clear() {
   for (Bucket& bucket : buckets_) {
     bucket.clear();
   }
   for (Bucket& bucket : buckets_) {
     bucket.clear();
   }
@@ -184,9 +185,8 @@ void BucketedTimeSeries<VT, TT>::clear() {
   latestTime_ = TimeType(0);
 }
 
   latestTime_ = TimeType(0);
 }
 
-
-template <typename VT, typename TT>
-TT BucketedTimeSeries<VT, TT>::getEarliestTime() const {
+template <typename VT, typename CT>
+typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTime() const {
   if (empty()) {
     return TimeType(0);
   }
   if (empty()) {
     return TimeType(0);
   }
@@ -203,8 +203,9 @@ TT BucketedTimeSeries<VT, TT>::getEarliestTime() const {
   return earliestTime;
 }
 
   return earliestTime;
 }
 
-template <typename VT, typename TT>
-TT BucketedTimeSeries<VT, TT>::getEarliestTimeNonEmpty() const {
+template <typename VT, typename CT>
+typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTimeNonEmpty()
+    const {
   size_t currentBucket;
   TimeType currentBucketStart;
   TimeType nextBucketStart;
   size_t currentBucket;
   TimeType currentBucketStart;
   TimeType nextBucketStart;
@@ -216,8 +217,8 @@ TT BucketedTimeSeries<VT, TT>::getEarliestTimeNonEmpty() const {
   return nextBucketStart - duration_;
 }
 
   return nextBucketStart - duration_;
 }
 
-template <typename VT, typename TT>
-TT BucketedTimeSeries<VT, TT>::elapsed() const {
+template <typename VT, typename CT>
+typename CT::duration BucketedTimeSeries<VT, CT>::elapsed() const {
   if (empty()) {
     return TimeType(0);
   }
   if (empty()) {
     return TimeType(0);
   }
@@ -226,8 +227,10 @@ TT BucketedTimeSeries<VT, TT>::elapsed() const {
   return latestTime_ - getEarliestTime() + TimeType(1);
 }
 
   return latestTime_ - getEarliestTime() + TimeType(1);
 }
 
-template <typename VT, typename TT>
-TT BucketedTimeSeries<VT, TT>::elapsed(TimeType start, TimeType end) const {
+template <typename VT, typename CT>
+typename CT::duration BucketedTimeSeries<VT, CT>::elapsed(
+    TimeType start,
+    TimeType end) const {
   if (empty()) {
     return TimeType(0);
   }
   if (empty()) {
     return TimeType(0);
   }
@@ -237,8 +240,8 @@ TT BucketedTimeSeries<VT, TT>::elapsed(TimeType start, TimeType end) const {
   return end - start;
 }
 
   return end - start;
 }
 
-template <typename VT, typename TT>
-VT BucketedTimeSeries<VT, TT>::sum(TimeType start, TimeType end) const {
+template <typename VT, typename CT>
+VT BucketedTimeSeries<VT, CT>::sum(TimeType start, TimeType end) const {
   ValueType total = ValueType();
   forEachBucket(start, end, [&](const Bucket& bucket,
                                 TimeType bucketStart,
   ValueType total = ValueType();
   forEachBucket(start, end, [&](const Bucket& bucket,
                                 TimeType bucketStart,
@@ -251,8 +254,8 @@ VT BucketedTimeSeries<VT, TT>::sum(TimeType start, TimeType end) const {
   return total;
 }
 
   return total;
 }
 
-template <typename VT, typename TT>
-uint64_t BucketedTimeSeries<VT, TT>::count(TimeType start, TimeType end) const {
+template <typename VT, typename CT>
+uint64_t BucketedTimeSeries<VT, CT>::count(TimeType start, TimeType end) const {
   uint64_t sample_count = 0;
   forEachBucket(start, end, [&](const Bucket& bucket,
                                 TimeType bucketStart,
   uint64_t sample_count = 0;
   forEachBucket(start, end, [&](const Bucket& bucket,
                                 TimeType bucketStart,
@@ -265,9 +268,9 @@ uint64_t BucketedTimeSeries<VT, TT>::count(TimeType start, TimeType end) const {
   return sample_count;
 }
 
   return sample_count;
 }
 
-template <typename VT, typename TT>
+template <typename VT, typename CT>
 template <typename ReturnType>
 template <typename ReturnType>
-ReturnType BucketedTimeSeries<VT, TT>::avg(TimeType start, TimeType end) const {
+ReturnType BucketedTimeSeries<VT, CT>::avg(TimeType start, TimeType end) const {
   ValueType total = ValueType();
   uint64_t sample_count = 0;
   forEachBucket(start, end, [&](const Bucket& bucket,
   ValueType total = ValueType();
   uint64_t sample_count = 0;
   forEachBucket(start, end, [&](const Bucket& bucket,
@@ -304,8 +307,8 @@ ReturnType BucketedTimeSeries<VT, TT>::avg(TimeType start, TimeType end) const {
  * into, we then divide by duration_.
  */
 
  * into, we then divide by duration_.
  */
 
-template <typename VT, typename TT>
-size_t BucketedTimeSeries<VT, TT>::getBucketIdx(TimeType time) const {
+template <typename VT, typename CT>
+size_t BucketedTimeSeries<VT, CT>::getBucketIdx(TimeType time) const {
   // For all-time data we don't use buckets_.  Everything is tracked in total_.
   DCHECK(!isAllTime());
 
   // For all-time data we don't use buckets_.  Everything is tracked in total_.
   DCHECK(!isAllTime());
 
@@ -317,10 +320,12 @@ size_t BucketedTimeSeries<VT, TT>::getBucketIdx(TimeType time) const {
  * Compute the bucket index for the specified time, as well as the earliest
  * time that falls into this bucket.
  */
  * Compute the bucket index for the specified time, as well as the earliest
  * time that falls into this bucket.
  */
-template <typename VT, typename TT>
-void BucketedTimeSeries<VT, TT>::getBucketInfo(
-    TimeType time, size_t *bucketIdx,
-    TimeType* bucketStart, TimeType* nextBucketStart) const {
+template <typename VT, typename CT>
+void BucketedTimeSeries<VT, CT>::getBucketInfo(
+    TimeType time,
+    size_t* bucketIdx,
+    TimeType* bucketStart,
+    TimeType* nextBucketStart) const {
   typedef typename TimeType::rep TimeInt;
   DCHECK(!isAllTime());
 
   typedef typename TimeType::rep TimeInt;
   DCHECK(!isAllTime());
 
@@ -349,9 +354,9 @@ void BucketedTimeSeries<VT, TT>::getBucketInfo(
   *nextBucketStart = nextBucketStartMod + durationStart;
 }
 
   *nextBucketStart = nextBucketStartMod + durationStart;
 }
 
-template <typename VT, typename TT>
+template <typename VT, typename CT>
 template <typename Function>
 template <typename Function>
-void BucketedTimeSeries<VT, TT>::forEachBucket(Function fn) const {
+void BucketedTimeSeries<VT, CT>::forEachBucket(Function fn) const {
   if (isAllTime()) {
     fn(total_, firstTime_, latestTime_ + TimeType(1));
     return;
   if (isAllTime()) {
     fn(total_, firstTime_, latestTime_ + TimeType(1));
     return;
@@ -417,10 +422,13 @@ void BucketedTimeSeries<VT, TT>::forEachBucket(Function fn) const {
  * For example, if the bucket spans time [10, 20), but we only care about the
  * range [10, 16), this will return 60% of the input value.
  */
  * For example, if the bucket spans time [10, 20), but we only care about the
  * range [10, 16), this will return 60% of the input value.
  */
-template<typename VT, typename TT>
-VT BucketedTimeSeries<VT, TT>::rangeAdjust(
-    TimeType bucketStart, TimeType nextBucketStart,
-    TimeType start, TimeType end, ValueType input) const {
+template <typename VT, typename CT>
+VT BucketedTimeSeries<VT, CT>::rangeAdjust(
+    TimeType bucketStart,
+    TimeType nextBucketStart,
+    TimeType start,
+    TimeType end,
+    ValueType input) const {
   // If nextBucketStart is greater than latestTime_, treat nextBucketStart as
   // if it were latestTime_.  This makes us more accurate when someone is
   // querying for all of the data up to latestTime_.  Even though latestTime_
   // If nextBucketStart is greater than latestTime_, treat nextBucketStart as
   // if it were latestTime_.  This makes us more accurate when someone is
   // querying for all of the data up to latestTime_.  Even though latestTime_
@@ -442,10 +450,12 @@ VT BucketedTimeSeries<VT, TT>::rangeAdjust(
     (nextBucketStart - bucketStart);
 }
 
     (nextBucketStart - bucketStart);
 }
 
-template <typename VT, typename TT>
+template <typename VT, typename CT>
 template <typename Function>
 template <typename Function>
-void BucketedTimeSeries<VT, TT>::forEachBucket(TimeType start, TimeType end,
-                                               Function fn) const {
+void BucketedTimeSeries<VT, CT>::forEachBucket(
+    TimeType start,
+    TimeType end,
+    Function fn) const {
   forEachBucket([&start, &end, &fn] (const Bucket& bucket, TimeType bucketStart,
                                      TimeType nextBucketStart) -> bool {
     if (start >= nextBucketStart) {
   forEachBucket([&start, &end, &fn] (const Bucket& bucket, TimeType bucketStart,
                                      TimeType nextBucketStart) -> bool {
     if (start >= nextBucketStart) {
index c3c2c1e4d111dc9187d21175b8428183c1853c70..c64053a8ce238c6bb5c4d727fb7843ebbbbf070b 100644 (file)
 
 namespace folly {
 
 
 namespace folly {
 
+/*
+ * A helper clock type to helper older code using BucketedTimeSeries with
+ * std::chrono::seconds transition to properly using clock types and time_point
+ * objects.
+ */
+template <typename TT = std::chrono::seconds>
+class LegacyStatsClock {
+ public:
+  using duration = TT;
+  using time_point = std::chrono::time_point<LegacyStatsClock, TT>;
+
+  // This clock does not actually implement now(), since the older API
+  // did not really specify what clock should be used.  (In practice most
+  // callers unfortuantely used wall clock time rather than a monotonic clock.)
+};
+
 /*
  * This class represents a bucketed time series which keeps track of values
  * added in the recent past, and merges these values together into a fixed
 /*
  * This class represents a bucketed time series which keeps track of values
  * added in the recent past, and merges these values together into a fixed
@@ -44,12 +60,18 @@ namespace folly {
  *
  * This class is not thread-safe -- use your own synchronization!
  */
  *
  * This class is not thread-safe -- use your own synchronization!
  */
-template <typename VT, typename TT=std::chrono::seconds>
+template <typename VT, typename CT = LegacyStatsClock<std::chrono::seconds>>
 class BucketedTimeSeries {
  public:
 class BucketedTimeSeries {
  public:
-  typedef VT ValueType;
-  typedef TT TimeType;
-  typedef detail::Bucket<ValueType> Bucket;
+  using ValueType = VT;
+  using Clock = CT;
+  using Duration = typename Clock::duration;
+  using TimePoint = typename Clock::time_point;
+  // The legacy TimeType.  The older code used this instead of Duration and
+  // TimePoint.  This will eventually be removed as the code is transitioned to
+  // Duration and TimePoint.
+  using TimeType = typename Clock::duration;
+  using Bucket = detail::Bucket<ValueType>;
 
   /*
    * Create a new BucketedTimeSeries.
 
   /*
    * Create a new BucketedTimeSeries.
@@ -61,7 +83,7 @@ class BucketedTimeSeries {
    * and does not need the rolling buckets.  The numBuckets parameter is
    * ignored when duration is 0.
    */
    * and does not need the rolling buckets.  The numBuckets parameter is
    * ignored when duration is 0.
    */
-  BucketedTimeSeries(size_t numBuckets, TimeType duration);
+  BucketedTimeSeries(size_t numBuckets, Duration duration);
 
   /*
    * Adds the value 'val' at time 'now'
 
   /*
    * Adds the value 'val' at time 'now'
index 763aaebe08a56099ecaf82c40c91413476113342..c3ddba896d963e4cbf86f3aaf7444f8c2bd5f61e 100644 (file)
 
 namespace folly {
 
 
 namespace folly {
 
-template <typename VT, typename TT>
-MultiLevelTimeSeries<VT, TT>::MultiLevelTimeSeries(
-  size_t nBuckets,
-  size_t nLevels,
-  const TimeType levelDurations[])
-    : cachedTime_(0),
-      cachedSum_(0),
-      cachedCount_(0) {
-    CHECK_GT(nLevels, 0);
-    CHECK(levelDurations);
+template <typename VT, typename CT>
+MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
+    size_t nBuckets,
+    size_t nLevels,
+    const TimeType levelDurations[])
+    : cachedTime_(0), cachedSum_(0), cachedCount_(0) {
+  CHECK_GT(nLevels, 0);
+  CHECK(levelDurations);
 
 
-    levels_.reserve(nLevels);
-    for (size_t i = 0; i < nLevels; ++i) {
-      if (levelDurations[i] == TT(0)) {
-        CHECK_EQ(i, nLevels - 1);
-      } else if (i > 0) {
-        CHECK(levelDurations[i-1] < levelDurations[i]);
-      }
-      levels_.emplace_back(nBuckets, levelDurations[i]);
+  levels_.reserve(nLevels);
+  for (size_t i = 0; i < nLevels; ++i) {
+    if (levelDurations[i] == Duration(0)) {
+      CHECK_EQ(i, nLevels - 1);
+    } else if (i > 0) {
+      CHECK(levelDurations[i - 1] < levelDurations[i]);
     }
     }
+    levels_.emplace_back(nBuckets, levelDurations[i]);
+  }
 }
 
 }
 
-template <typename VT, typename TT>
-MultiLevelTimeSeries<VT, TT>::MultiLevelTimeSeries(
+template <typename VT, typename CT>
+MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
     size_t nBuckets,
     std::initializer_list<TimeType> durations)
     : cachedTime_(0), cachedSum_(0), cachedCount_(0) {
     size_t nBuckets,
     std::initializer_list<TimeType> durations)
     : cachedTime_(0), cachedSum_(0), cachedCount_(0) {
@@ -54,7 +52,7 @@ MultiLevelTimeSeries<VT, TT>::MultiLevelTimeSeries(
   int i = 0;
   TimeType prev;
   for (auto dur : durations) {
   int i = 0;
   TimeType prev;
   for (auto dur : durations) {
-    if (dur == TT(0)) {
+    if (dur == Duration(0)) {
       CHECK_EQ(i, durations.size() - 1);
     } else if (i > 0) {
       CHECK(prev < dur);
       CHECK_EQ(i, durations.size() - 1);
     } else if (i > 0) {
       CHECK(prev < dur);
@@ -65,24 +63,26 @@ MultiLevelTimeSeries<VT, TT>::MultiLevelTimeSeries(
   }
 }
 
   }
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::addValue(
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::addValue(
     TimeType now,
     const ValueType& val) {
   addValueAggregated(now, val, 1);
 }
 
     TimeType now,
     const ValueType& val) {
   addValueAggregated(now, val, 1);
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::addValue(TimeType now,
-                                            const ValueType& val,
-                                            int64_t times) {
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::addValue(
+    TimeType now,
+    const ValueType& val,
+    int64_t times) {
   addValueAggregated(now, val * times, times);
 }
 
   addValueAggregated(now, val * times, times);
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::addValueAggregated(TimeType now,
-                                                      const ValueType& total,
-                                                      int64_t nsamples) {
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::addValueAggregated(
+    TimeType now,
+    const ValueType& total,
+    int64_t nsamples) {
   if (cachedTime_ != now) {
     flush();
     cachedTime_ = now;
   if (cachedTime_ != now) {
     flush();
     cachedTime_ = now;
@@ -91,16 +91,16 @@ void MultiLevelTimeSeries<VT, TT>::addValueAggregated(TimeType now,
   cachedCount_ += nsamples;
 }
 
   cachedCount_ += nsamples;
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::update(TimeType now) {
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::update(TimeType now) {
   flush();
   for (size_t i = 0; i < levels_.size(); ++i) {
     levels_[i].update(now);
   }
 }
 
   flush();
   for (size_t i = 0; i < levels_.size(); ++i) {
     levels_[i].update(now);
   }
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::flush() {
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::flush() {
   // update all the underlying levels
   if (cachedCount_ > 0) {
     for (size_t i = 0; i < levels_.size(); ++i) {
   // update all the underlying levels
   if (cachedCount_ > 0) {
     for (size_t i = 0; i < levels_.size(); ++i) {
@@ -111,8 +111,8 @@ void MultiLevelTimeSeries<VT, TT>::flush() {
   }
 }
 
   }
 }
 
-template <typename VT, typename TT>
-void MultiLevelTimeSeries<VT, TT>::clear() {
+template <typename VT, typename CT>
+void MultiLevelTimeSeries<VT, CT>::clear() {
   for (auto & level : levels_) {
     level.clear();
   }
   for (auto & level : levels_) {
     level.clear();
   }
index f5a9d5a64dee0d05e5c2867f5d52d0bbf1be1c62..7a43f175ad32099c40d81a72e1daf56761a71ec6 100644 (file)
@@ -49,12 +49,18 @@ namespace folly {
  *
  * The class is not thread-safe -- use your own synchronization!
  */
  *
  * The class is not thread-safe -- use your own synchronization!
  */
-template <typename VT, typename TT=std::chrono::seconds>
+template <typename VT, typename CT = LegacyStatsClock<std::chrono::seconds>>
 class MultiLevelTimeSeries {
  public:
 class MultiLevelTimeSeries {
  public:
-  typedef VT ValueType;
-  typedef TT TimeType;
-  typedef folly::BucketedTimeSeries<ValueType, TimeType> Level;
+  using ValueType = VT;
+  using Clock = CT;
+  using Duration = typename Clock::duration;
+  using TimePoint = typename Clock::time_point;
+  // The legacy TimeType.  The older code used this instead of Duration and
+  // TimePoint.  This will eventually be removed as the code is transitioned to
+  // Duration and TimePoint.
+  using TimeType = typename Clock::duration;
+  using Level = folly::BucketedTimeSeries<ValueType, Clock>;
 
   /*
    * Create a new MultiLevelTimeSeries.
 
   /*
    * Create a new MultiLevelTimeSeries.
index f41b749e6510cd27c1ef462c2f140042c3ed3c3c..3594bec48ce309b2ab9b1f3c0799318b07aeade3 100644 (file)
 
 namespace folly {
 
 
 namespace folly {
 
-template <typename T, typename TT, typename C>
-TimeseriesHistogram<T, TT, C>::TimeseriesHistogram(ValueType bucketSize,
-                                            ValueType min,
-                                            ValueType max,
-                                            const ContainerType& copyMe)
-  : buckets_(bucketSize, min, max, copyMe),
-    haveNotSeenValue_(true),
-    singleUniqueValue_(false) {
-}
-
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::addValue(TimeType now,
-                                             const ValueType& value) {
+template <typename T, typename CT, typename C>
+TimeseriesHistogram<T, CT, C>::TimeseriesHistogram(
+    ValueType bucketSize,
+    ValueType min,
+    ValueType max,
+    const ContainerType& copyMe)
+    : buckets_(bucketSize, min, max, copyMe),
+      haveNotSeenValue_(true),
+      singleUniqueValue_(false) {}
+
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::addValue(
+    TimeType now,
+    const ValueType& value) {
   buckets_.getByValue(value).addValue(now, value);
   maybeHandleSingleUniqueValue(value);
 }
 
   buckets_.getByValue(value).addValue(now, value);
   maybeHandleSingleUniqueValue(value);
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::addValue(TimeType now,
-                                      const ValueType& value,
-                                      int64_t times) {
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::addValue(
+    TimeType now,
+    const ValueType& value,
+    int64_t times) {
   buckets_.getByValue(value).addValue(now, value, times);
   maybeHandleSingleUniqueValue(value);
 }
 
   buckets_.getByValue(value).addValue(now, value, times);
   maybeHandleSingleUniqueValue(value);
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::addValues(
-    TimeType now, const folly::Histogram<ValueType>& hist) {
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::addValues(
+    TimeType now,
+    const folly::Histogram<ValueType>& hist) {
   CHECK_EQ(hist.getMin(), getMin());
   CHECK_EQ(hist.getMax(), getMax());
   CHECK_EQ(hist.getBucketSize(), getBucketSize());
   CHECK_EQ(hist.getMin(), getMin());
   CHECK_EQ(hist.getMax(), getMax());
   CHECK_EQ(hist.getBucketSize(), getBucketSize());
@@ -68,9 +71,9 @@ void TimeseriesHistogram<T, TT, C>::addValues(
   singleUniqueValue_ = false;
 }
 
   singleUniqueValue_ = false;
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::maybeHandleSingleUniqueValue(
-  const ValueType& value) {
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::maybeHandleSingleUniqueValue(
+    const ValueType& value) {
   if (haveNotSeenValue_) {
     firstValue_ = value;
     singleUniqueValue_ = true;
   if (haveNotSeenValue_) {
     firstValue_ = value;
     singleUniqueValue_ = true;
@@ -82,9 +85,9 @@ void TimeseriesHistogram<T, TT, C>::maybeHandleSingleUniqueValue(
   }
 }
 
   }
 }
 
-template <typename T, typename TT, typename C>
-T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
-                                                       int level) const {
+template <typename T, typename CT, typename C>
+T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(double pct, int level)
+    const {
   if (singleUniqueValue_) {
     return firstValue_;
   }
   if (singleUniqueValue_) {
     return firstValue_;
   }
@@ -93,10 +96,11 @@ T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
                                         AvgFromLevel(level));
 }
 
                                         AvgFromLevel(level));
 }
 
-template <typename T, typename TT, typename C>
-T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
-                                                TimeType start,
-                                                TimeType end) const {
+template <typename T, typename CT, typename C>
+T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(
+    double pct,
+    TimeType start,
+    TimeType end) const {
   if (singleUniqueValue_) {
     return firstValue_;
   }
   if (singleUniqueValue_) {
     return firstValue_;
   }
@@ -106,38 +110,37 @@ T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
                                         AvgFromInterval<T>(start, end));
 }
 
                                         AvgFromInterval<T>(start, end));
 }
 
-template <typename T, typename TT, typename C>
-int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx(
-  double pct,
-  int level
-) const {
+template <typename T, typename CT, typename C>
+int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(double pct, int level)
+    const {
   return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level));
 }
 
   return buckets_.getPercentileBucketIdx(pct / 100.0, CountFromLevel(level));
 }
 
-template <typename T, typename TT, typename C>
-int TimeseriesHistogram<T, TT, C>::getPercentileBucketIdx(double pct,
-                                                   TimeType start,
-                                                   TimeType end) const {
+template <typename T, typename CT, typename C>
+int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
+    double pct,
+    TimeType start,
+    TimeType end) const {
   return buckets_.getPercentileBucketIdx(pct / 100.0,
                                          CountFromInterval(start, end));
 }
 
   return buckets_.getPercentileBucketIdx(pct / 100.0,
                                          CountFromInterval(start, end));
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::clear() {
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::clear() {
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
     buckets_.getByIndex(i).clear();
   }
 }
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
     buckets_.getByIndex(i).clear();
   }
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::update(TimeType now) {
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::update(TimeType now) {
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
     buckets_.getByIndex(i).update(now);
   }
 }
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
     buckets_.getByIndex(i).update(now);
   }
 }
 
-template <typename T, typename TT, typename C>
-std::string TimeseriesHistogram<T, TT, C>::getString(int level) const {
+template <typename T, typename CT, typename C>
+std::string TimeseriesHistogram<T, CT, C>::getString(int level) const {
   std::string result;
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
   std::string result;
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
@@ -153,9 +156,10 @@ std::string TimeseriesHistogram<T, TT, C>::getString(int level) const {
   return result;
 }
 
   return result;
 }
 
-template <typename T, typename TT, typename C>
-std::string TimeseriesHistogram<T, TT, C>::getString(TimeType start,
-                                                     TimeType end) const {
+template <typename T, typename CT, typename C>
+std::string TimeseriesHistogram<T, CT, C>::getString(
+    TimeType start,
+    TimeType end) const {
   std::string result;
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
   std::string result;
 
   for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
@@ -171,8 +175,8 @@ std::string TimeseriesHistogram<T, TT, C>::getString(TimeType start,
   return result;
 }
 
   return result;
 }
 
-template <class T, class TT, class C>
-void TimeseriesHistogram<T, TT, C>::computeAvgData(
+template <class T, class CT, class C>
+void TimeseriesHistogram<T, CT, C>::computeAvgData(
     ValueType* total,
     int64_t* nsamples,
     int level) const {
     ValueType* total,
     int64_t* nsamples,
     int level) const {
@@ -183,8 +187,8 @@ void TimeseriesHistogram<T, TT, C>::computeAvgData(
   }
 }
 
   }
 }
 
-template <class T, class TT, class C>
-void TimeseriesHistogram<T, TT, C>::computeAvgData(
+template <class T, class CT, class C>
+void TimeseriesHistogram<T, CT, C>::computeAvgData(
     ValueType* total,
     int64_t* nsamples,
     TimeType start,
     ValueType* total,
     int64_t* nsamples,
     TimeType start,
@@ -196,8 +200,8 @@ void TimeseriesHistogram<T, TT, C>::computeAvgData(
   }
 }
 
   }
 }
 
-template <typename T, typename TT, typename C>
-void TimeseriesHistogram<T, TT, C>::computeRateData(
+template <typename T, typename CT, typename C>
+void TimeseriesHistogram<T, CT, C>::computeRateData(
     ValueType* total,
     TimeType* elapsed,
     int level) const {
     ValueType* total,
     TimeType* elapsed,
     int level) const {
@@ -208,8 +212,8 @@ void TimeseriesHistogram<T, TT, C>::computeRateData(
   }
 }
 
   }
 }
 
-template <class T, class TT, class C>
-void TimeseriesHistogram<T, TT, C>::computeRateData(
+template <class T, class CT, class C>
+void TimeseriesHistogram<T, CT, C>::computeRateData(
     ValueType* total,
     TimeType* elapsed,
     TimeType start,
     ValueType* total,
     TimeType* elapsed,
     TimeType start,
index d5ce089d75b1191e3f38b2fb339da6b55f5ef158..71471887e826742bfb6265eaf39d8f320424396d 100644 (file)
@@ -47,20 +47,28 @@ namespace folly {
  * The memory usage for a typical histogram is roughly 3k * (# of buckets).  All
  * insertion operations are amortized O(1), and all queries are O(# of buckets).
  */
  * The memory usage for a typical histogram is roughly 3k * (# of buckets).  All
  * insertion operations are amortized O(1), and all queries are O(# of buckets).
  */
-template <class T, class TT=std::chrono::seconds,
-          class C=folly::MultiLevelTimeSeries<T, TT>>
+template <
+    class T,
+    class CT = LegacyStatsClock<std::chrono::seconds>,
+    class C = folly::MultiLevelTimeSeries<T, CT>>
 class TimeseriesHistogram {
  private:
    // NOTE: T must be equivalent to _signed_ numeric type for our math.
    static_assert(std::numeric_limits<T>::is_signed, "");
 
  public:
 class TimeseriesHistogram {
  private:
    // NOTE: T must be equivalent to _signed_ numeric type for our math.
    static_assert(std::numeric_limits<T>::is_signed, "");
 
  public:
-  // values to be inserted into container
-  typedef T ValueType;
-  // the container type we use internally for each bucket
-  typedef C ContainerType;
-  // The time type.
-  typedef TT TimeType;
+  // Values to be inserted into container
+  using ValueType = T;
+  // The container type we use internally for each bucket
+  using ContainerType = C;
+  // Clock, duration, and time point types
+  using Clock = CT;
+  using Duration = typename Clock::duration;
+  using TimePoint = typename Clock::time_point;
+  // The legacy TimeType.  The older code used this instead of Duration and
+  // TimePoint.  This will eventually be removed as the code is transitioned to
+  // Duration and TimePoint.
+  using TimeType = typename Clock::duration;
 
   /*
    * Create a TimeSeries histogram and initialize the bucketing and levels.
 
   /*
    * Create a TimeSeries histogram and initialize the bucketing and levels.