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()) {
}
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);
template <typename VT, typename CT>
bool BucketedTimeSeries<VT, CT>::addValueAggregated(
- TimeType now,
+ TimePoint now,
const ValueType& total,
int64_t nsamples) {
if (isAllTime()) {
}
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;
}
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
// Get info about the bucket that latestTime_ points at
size_t currentBucket;
- TimeType currentBucketStart;
- TimeType nextBucketStart;
+ TimePoint currentBucketStart;
+ TimePoint nextBucketStart;
getBucketInfo(latestTime_, ¤tBucket,
¤tBucketStart, &nextBucketStart);
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_);
}
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_, ¤tBucket,
¤tBucketStart, &nextBucketStart);
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);
*/
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();
}
/*
*/
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();
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;
}
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();
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()) {
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;
*/
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
// 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) {
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);
}
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