update stats APIs to use TimePoint vs Duration correctly
[folly.git] / folly / stats / BucketedTimeSeries-defs.h
index 8941503cde88a28da7083929cc2f5a8836fa505a..bd38f6d5c8e6cb24043672945e5fa17f6dd437aa 100644 (file)
@@ -25,8 +25,8 @@ namespace folly {
 template <typename VT, typename CT>
 BucketedTimeSeries<VT, CT>::BucketedTimeSeries(
     size_t nBuckets,
-    TimeType maxDuration)
-    : firstTime_(1), latestTime_(0), duration_(maxDuration) {
+    Duration maxDuration)
+    : firstTime_(Duration(1)), latestTime_(), duration_(maxDuration) {
   // For tracking all-time data we only use total_, and don't need to bother
   // with buckets_
   if (!isAllTime()) {
@@ -43,13 +43,13 @@ BucketedTimeSeries<VT, CT>::BucketedTimeSeries(
 }
 
 template <typename VT, typename CT>
-bool BucketedTimeSeries<VT, CT>::addValue(TimeType now, const ValueType& val) {
+bool BucketedTimeSeries<VT, CT>::addValue(TimePoint now, const ValueType& val) {
   return addValueAggregated(now, val, 1);
 }
 
 template <typename VT, typename CT>
 bool BucketedTimeSeries<VT, CT>::addValue(
-    TimeType now,
+    TimePoint now,
     const ValueType& val,
     int64_t times) {
   return addValueAggregated(now, val * times, times);
@@ -57,7 +57,7 @@ bool BucketedTimeSeries<VT, CT>::addValue(
 
 template <typename VT, typename CT>
 bool BucketedTimeSeries<VT, CT>::addValueAggregated(
-    TimeType now,
+    TimePoint now,
     const ValueType& total,
     int64_t nsamples) {
   if (isAllTime()) {
@@ -100,7 +100,7 @@ bool BucketedTimeSeries<VT, CT>::addValueAggregated(
 }
 
 template <typename VT, typename CT>
-size_t BucketedTimeSeries<VT, CT>::update(TimeType now) {
+size_t BucketedTimeSeries<VT, CT>::update(TimePoint now) {
   if (empty()) {
     // This is the first data point.
     firstTime_ = now;
@@ -123,7 +123,7 @@ size_t BucketedTimeSeries<VT, CT>::update(TimeType now) {
 }
 
 template <typename VT, typename CT>
-size_t BucketedTimeSeries<VT, CT>::updateBuckets(TimeType now) {
+size_t BucketedTimeSeries<VT, CT>::updateBuckets(TimePoint 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
@@ -134,8 +134,8 @@ size_t BucketedTimeSeries<VT, CT>::updateBuckets(TimeType now) {
 
   // Get info about the bucket that latestTime_ points at
   size_t currentBucket;
-  TimeType currentBucketStart;
-  TimeType nextBucketStart;
+  TimePoint currentBucketStart;
+  TimePoint nextBucketStart;
   getBucketInfo(latestTime_, &currentBucket,
                 &currentBucketStart, &nextBucketStart);
 
@@ -181,21 +181,21 @@ void BucketedTimeSeries<VT, CT>::clear() {
   total_.clear();
   // Set firstTime_ larger than latestTime_,
   // to indicate that the timeseries is empty
-  firstTime_ = TimeType(1);
-  latestTime_ = TimeType(0);
+  firstTime_ = TimePoint(Duration(1));
+  latestTime_ = TimePoint();
 }
 
 template <typename VT, typename CT>
-typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTime() const {
+typename CT::time_point BucketedTimeSeries<VT, CT>::getEarliestTime() const {
   if (empty()) {
-    return TimeType(0);
+    return TimePoint();
   }
   if (isAllTime()) {
     return firstTime_;
   }
 
   // Compute the earliest time we can track
-  TimeType earliestTime = getEarliestTimeNonEmpty();
+  TimePoint earliestTime = getEarliestTimeNonEmpty();
 
   // We're never tracking data before firstTime_
   earliestTime = std::max(earliestTime, firstTime_);
@@ -204,11 +204,11 @@ typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTime() const {
 }
 
 template <typename VT, typename CT>
-typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTimeNonEmpty()
+typename CT::time_point BucketedTimeSeries<VT, CT>::getEarliestTimeNonEmpty()
     const {
   size_t currentBucket;
-  TimeType currentBucketStart;
-  TimeType nextBucketStart;
+  TimePoint currentBucketStart;
+  TimePoint nextBucketStart;
   getBucketInfo(latestTime_, &currentBucket,
                 &currentBucketStart, &nextBucketStart);
 
@@ -220,68 +220,79 @@ typename CT::duration BucketedTimeSeries<VT, CT>::getEarliestTimeNonEmpty()
 template <typename VT, typename CT>
 typename CT::duration BucketedTimeSeries<VT, CT>::elapsed() const {
   if (empty()) {
-    return TimeType(0);
+    return Duration(0);
   }
 
   // Add 1 since [latestTime_, earliestTime] is an inclusive interval.
-  return latestTime_ - getEarliestTime() + TimeType(1);
+  return latestTime_ - getEarliestTime() + Duration(1);
 }
 
 template <typename VT, typename CT>
 typename CT::duration BucketedTimeSeries<VT, CT>::elapsed(
-    TimeType start,
-    TimeType end) const {
+    TimePoint start,
+    TimePoint end) const {
   if (empty()) {
-    return TimeType(0);
+    return Duration(0);
   }
   start = std::max(start, getEarliestTime());
-  end = std::min(end, latestTime_ + TimeType(1));
+  end = std::min(end, latestTime_ + Duration(1));
   end = std::max(start, end);
   return end - start;
 }
 
 template <typename VT, typename CT>
-VT BucketedTimeSeries<VT, CT>::sum(TimeType start, TimeType end) const {
+VT BucketedTimeSeries<VT, CT>::sum(TimePoint start, TimePoint end) const {
   ValueType total = ValueType();
-  forEachBucket(start, end, [&](const Bucket& bucket,
-                                TimeType bucketStart,
-                                TimeType nextBucketStart) -> bool {
-    total += this->rangeAdjust(bucketStart, nextBucketStart, start, end,
-                             bucket.sum);
-    return true;
-  });
+  forEachBucket(
+      start,
+      end,
+      [&](const Bucket& bucket,
+          TimePoint bucketStart,
+          TimePoint nextBucketStart) -> bool {
+        total += this->rangeAdjust(
+            bucketStart, nextBucketStart, start, end, bucket.sum);
+        return true;
+      });
 
   return total;
 }
 
 template <typename VT, typename CT>
-uint64_t BucketedTimeSeries<VT, CT>::count(TimeType start, TimeType end) const {
+uint64_t BucketedTimeSeries<VT, CT>::count(TimePoint start, TimePoint end)
+    const {
   uint64_t sample_count = 0;
-  forEachBucket(start, end, [&](const Bucket& bucket,
-                                TimeType bucketStart,
-                                TimeType nextBucketStart) -> bool {
-    sample_count += this->rangeAdjust(bucketStart, nextBucketStart, start, end,
-                               bucket.count);
-    return true;
-  });
+  forEachBucket(
+      start,
+      end,
+      [&](const Bucket& bucket,
+          TimePoint bucketStart,
+          TimePoint nextBucketStart) -> bool {
+        sample_count += this->rangeAdjust(
+            bucketStart, nextBucketStart, start, end, bucket.count);
+        return true;
+      });
 
   return sample_count;
 }
 
 template <typename VT, typename CT>
 template <typename ReturnType>
-ReturnType BucketedTimeSeries<VT, CT>::avg(TimeType start, TimeType end) const {
+ReturnType BucketedTimeSeries<VT, CT>::avg(TimePoint start, TimePoint end)
+    const {
   ValueType total = ValueType();
   uint64_t sample_count = 0;
-  forEachBucket(start, end, [&](const Bucket& bucket,
-                                TimeType bucketStart,
-                                TimeType nextBucketStart) -> bool {
-    total += this->rangeAdjust(bucketStart, nextBucketStart, start, end,
-                             bucket.sum);
-    sample_count += this->rangeAdjust(bucketStart, nextBucketStart, start, end,
-                               bucket.count);
-    return true;
-  });
+  forEachBucket(
+      start,
+      end,
+      [&](const Bucket& bucket,
+          TimePoint bucketStart,
+          TimePoint nextBucketStart) -> bool {
+        total += this->rangeAdjust(
+            bucketStart, nextBucketStart, start, end, bucket.sum);
+        sample_count += this->rangeAdjust(
+            bucketStart, nextBucketStart, start, end, bucket.count);
+        return true;
+      });
 
   if (sample_count == 0) {
     return ReturnType(0);
@@ -308,12 +319,12 @@ ReturnType BucketedTimeSeries<VT, CT>::avg(TimeType start, TimeType end) const {
  */
 
 template <typename VT, typename CT>
-size_t BucketedTimeSeries<VT, CT>::getBucketIdx(TimeType time) const {
+size_t BucketedTimeSeries<VT, CT>::getBucketIdx(TimePoint time) const {
   // For all-time data we don't use buckets_.  Everything is tracked in total_.
   DCHECK(!isAllTime());
 
-  time %= duration_;
-  return time.count() * buckets_.size() / duration_.count();
+  auto timeIntoCurrentCycle = (time.time_since_epoch() % duration_);
+  return timeIntoCurrentCycle.count() * buckets_.size() / duration_.count();
 }
 
 /*
@@ -322,17 +333,17 @@ size_t BucketedTimeSeries<VT, CT>::getBucketIdx(TimeType time) const {
  */
 template <typename VT, typename CT>
 void BucketedTimeSeries<VT, CT>::getBucketInfo(
-    TimeType time,
+    TimePoint time,
     size_t* bucketIdx,
-    TimeType* bucketStart,
-    TimeType* nextBucketStart) const {
-  typedef typename TimeType::rep TimeInt;
+    TimePoint* bucketStart,
+    TimePoint* nextBucketStart) const {
+  typedef typename Duration::rep TimeInt;
   DCHECK(!isAllTime());
 
   // Keep these two lines together.  The compiler should be able to compute
   // both the division and modulus with a single operation.
-  TimeType timeMod = time % duration_;
-  TimeInt numFullDurations = time / duration_;
+  Duration timeMod = time.time_since_epoch() % duration_;
+  TimeInt numFullDurations = time.time_since_epoch() / duration_;
 
   TimeInt scaledTime = timeMod.count() * buckets_.size();
 
@@ -344,12 +355,12 @@ void BucketedTimeSeries<VT, CT>::getBucketInfo(
   TimeInt scaledBucketStart = scaledTime - scaledOffsetInBucket;
   TimeInt scaledNextBucketStart = scaledBucketStart + duration_.count();
 
-  TimeType bucketStartMod((scaledBucketStart + buckets_.size() - 1) /
-                          buckets_.size());
-  TimeType nextBucketStartMod((scaledNextBucketStart + buckets_.size() - 1) /
-                              buckets_.size());
+  Duration bucketStartMod(
+      (scaledBucketStart + buckets_.size() - 1) / buckets_.size());
+  Duration nextBucketStartMod(
+      (scaledNextBucketStart + buckets_.size() - 1) / buckets_.size());
 
-  TimeType durationStart(numFullDurations * duration_.count());
+  TimePoint durationStart(numFullDurations * duration_);
   *bucketStart = bucketStartMod + durationStart;
   *nextBucketStart = nextBucketStartMod + durationStart;
 }
@@ -358,17 +369,17 @@ template <typename VT, typename CT>
 template <typename Function>
 void BucketedTimeSeries<VT, CT>::forEachBucket(Function fn) const {
   if (isAllTime()) {
-    fn(total_, firstTime_, latestTime_ + TimeType(1));
+    fn(total_, firstTime_, latestTime_ + Duration(1));
     return;
   }
 
-  typedef typename TimeType::rep TimeInt;
+  typedef typename Duration::rep TimeInt;
 
   // Compute durationStart, latestBucketIdx, and scaledNextBucketStart,
   // the same way as in getBucketInfo().
-  TimeType timeMod = latestTime_ % duration_;
-  TimeInt numFullDurations = latestTime_ / duration_;
-  TimeType durationStart(numFullDurations * duration_.count());
+  Duration timeMod = latestTime_.time_since_epoch() % duration_;
+  TimeInt numFullDurations = latestTime_.time_since_epoch() / duration_;
+  TimePoint durationStart(numFullDurations * duration_);
   TimeInt scaledTime = timeMod.count() * buckets_.size();
   size_t latestBucketIdx = scaledTime / duration_.count();
   TimeInt scaledOffsetInBucket = scaledTime % duration_.count();
@@ -381,9 +392,10 @@ void BucketedTimeSeries<VT, CT>::forEachBucket(Function fn) const {
   size_t idx = latestBucketIdx;
   durationStart -= duration_;
 
-  TimeType nextBucketStart =
-    TimeType((scaledNextBucketStart + buckets_.size() - 1) / buckets_.size()) +
-    durationStart;
+  TimePoint nextBucketStart =
+      Duration(
+          (scaledNextBucketStart + buckets_.size() - 1) / buckets_.size()) +
+      durationStart;
   while (true) {
     ++idx;
     if (idx >= buckets_.size()) {
@@ -394,15 +406,19 @@ void BucketedTimeSeries<VT, CT>::forEachBucket(Function fn) const {
       scaledNextBucketStart += duration_.count();
     }
 
-    TimeType bucketStart = nextBucketStart;
-    nextBucketStart = TimeType((scaledNextBucketStart + buckets_.size() - 1) /
-                               buckets_.size()) + durationStart;
+    TimePoint bucketStart = nextBucketStart;
+    nextBucketStart =
+        Duration(
+            (scaledNextBucketStart + buckets_.size() - 1) / buckets_.size()) +
+        durationStart;
 
     // Should we bother skipping buckets where firstTime_ >= nextBucketStart?
     // For now we go ahead and invoke the function with these buckets.
     // sum and count should always be 0 in these buckets.
 
-    DCHECK_LE(bucketStart.count(), latestTime_.count());
+    DCHECK_LE(
+        bucketStart.time_since_epoch().count(),
+        latestTime_.time_since_epoch().count());
     bool ret = fn(buckets_[idx], bucketStart, nextBucketStart);
     if (!ret) {
       break;
@@ -424,10 +440,10 @@ void BucketedTimeSeries<VT, CT>::forEachBucket(Function fn) const {
  */
 template <typename VT, typename CT>
 VT BucketedTimeSeries<VT, CT>::rangeAdjust(
-    TimeType bucketStart,
-    TimeType nextBucketStart,
-    TimeType start,
-    TimeType end,
+    TimePoint bucketStart,
+    TimePoint nextBucketStart,
+    TimePoint start,
+    TimePoint 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
@@ -436,7 +452,7 @@ VT BucketedTimeSeries<VT, CT>::rangeAdjust(
   // downwards in this case, because the bucket really only has data up to
   // latestTime_.
   if (bucketStart <= latestTime_ && nextBucketStart > latestTime_) {
-    nextBucketStart = latestTime_ + TimeType(1);
+    nextBucketStart = latestTime_ + Duration(1);
   }
 
   if (start <= bucketStart && end >= nextBucketStart) {
@@ -444,8 +460,8 @@ VT BucketedTimeSeries<VT, CT>::rangeAdjust(
     return input;
   }
 
-  TimeType intervalStart = std::max(start, bucketStart);
-  TimeType intervalEnd = std::min(end, nextBucketStart);
+  TimePoint intervalStart = std::max(start, bucketStart);
+  TimePoint intervalEnd = std::min(end, nextBucketStart);
   return input * (intervalEnd - intervalStart) /
     (nextBucketStart - bucketStart);
 }
@@ -453,20 +469,23 @@ VT BucketedTimeSeries<VT, CT>::rangeAdjust(
 template <typename VT, typename CT>
 template <typename Function>
 void BucketedTimeSeries<VT, CT>::forEachBucket(
-    TimeType start,
-    TimeType end,
+    TimePoint start,
+    TimePoint end,
     Function fn) const {
-  forEachBucket([&start, &end, &fn] (const Bucket& bucket, TimeType bucketStart,
-                                     TimeType nextBucketStart) -> bool {
-    if (start >= nextBucketStart) {
-      return true;
-    }
-    if (end <= bucketStart) {
-      return false;
-    }
-    bool ret = fn(bucket, bucketStart, nextBucketStart);
-    return ret;
-  });
+  forEachBucket(
+      [&start, &end, &fn](
+          const Bucket& bucket,
+          TimePoint bucketStart,
+          TimePoint nextBucketStart) -> bool {
+        if (start >= nextBucketStart) {
+          return true;
+        }
+        if (end <= bucketStart) {
+          return false;
+        }
+        bool ret = fn(bucket, bucketStart, nextBucketStart);
+        return ret;
+      });
 }
 
 } // folly