Commit 42ca5613 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot 2

update stats APIs to use TimePoint vs Duration correctly

Summary:
Update the stats APIs to correcly distinguish between TimePoint and Duration
types.

This does leave addValue() and update() APIs in place that accept Duration
values, for backwards compatibility.  These should eventually be removed once
all code has been converted to call the new APIs.

Reviewed By: yfeldblum

Differential Revision: D3808805

fbshipit-source-id: 36d6574ba4a09db7eb9f1a35e47addd3e07f8461
parent 864eb2a6
...@@ -53,11 +53,12 @@ avgHelper(ValueType sum, uint64_t count) { ...@@ -53,11 +53,12 @@ avgHelper(ValueType sum, uint64_t count) {
* Helper function to compute the rate per Interval, * Helper function to compute the rate per Interval,
* given the specified count recorded over the elapsed time period. * given the specified count recorded over the elapsed time period.
*/ */
template <typename ReturnType=double, template <
typename TimeType=std::chrono::seconds, typename ReturnType = double,
typename Interval=TimeType> typename Duration = std::chrono::seconds,
ReturnType rateHelper(ReturnType count, TimeType elapsed) { typename Interval = Duration>
if (elapsed == TimeType(0)) { ReturnType rateHelper(ReturnType count, Duration elapsed) {
if (elapsed == Duration(0)) {
return 0; return 0;
} }
...@@ -68,8 +69,9 @@ ReturnType rateHelper(ReturnType count, TimeType elapsed) { ...@@ -68,8 +69,9 @@ ReturnType rateHelper(ReturnType count, TimeType elapsed) {
// is less than the desired interval, which will incorrectly result in // is less than the desired interval, which will incorrectly result in
// an infinite rate. // an infinite rate.
typedef std::chrono::duration< typedef std::chrono::duration<
ReturnType, std::ratio<TimeType::period::den, ReturnType,
TimeType::period::num>> NativeRate; std::ratio<Duration::period::den, Duration::period::num>>
NativeRate;
typedef std::chrono::duration< typedef std::chrono::duration<
ReturnType, std::ratio<Interval::period::den, ReturnType, std::ratio<Interval::period::den,
Interval::period::num>> DesiredRate; Interval::period::num>> DesiredRate;
......
This diff is collapsed.
This diff is collapsed.
...@@ -25,8 +25,8 @@ template <typename VT, typename CT> ...@@ -25,8 +25,8 @@ template <typename VT, typename CT>
MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
size_t nBuckets, size_t nBuckets,
size_t nLevels, size_t nLevels,
const TimeType levelDurations[]) const Duration levelDurations[])
: cachedTime_(0), cachedSum_(0), cachedCount_(0) { : cachedTime_(), cachedSum_(0), cachedCount_(0) {
CHECK_GT(nLevels, 0); CHECK_GT(nLevels, 0);
CHECK(levelDurations); CHECK(levelDurations);
...@@ -44,13 +44,13 @@ MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( ...@@ -44,13 +44,13 @@ MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
template <typename VT, typename CT> template <typename VT, typename CT>
MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
size_t nBuckets, size_t nBuckets,
std::initializer_list<TimeType> durations) std::initializer_list<Duration> durations)
: cachedTime_(0), cachedSum_(0), cachedCount_(0) { : cachedTime_(), cachedSum_(0), cachedCount_(0) {
CHECK_GT(durations.size(), 0); CHECK_GT(durations.size(), 0);
levels_.reserve(durations.size()); levels_.reserve(durations.size());
int i = 0; int i = 0;
TimeType prev; Duration prev;
for (auto dur : durations) { for (auto dur : durations) {
if (dur == Duration(0)) { if (dur == Duration(0)) {
CHECK_EQ(i, durations.size() - 1); CHECK_EQ(i, durations.size() - 1);
...@@ -65,14 +65,14 @@ MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries( ...@@ -65,14 +65,14 @@ MultiLevelTimeSeries<VT, CT>::MultiLevelTimeSeries(
template <typename VT, typename CT> template <typename VT, typename CT>
void MultiLevelTimeSeries<VT, CT>::addValue( void MultiLevelTimeSeries<VT, CT>::addValue(
TimeType now, TimePoint now,
const ValueType& val) { const ValueType& val) {
addValueAggregated(now, val, 1); addValueAggregated(now, val, 1);
} }
template <typename VT, typename CT> template <typename VT, typename CT>
void MultiLevelTimeSeries<VT, CT>::addValue( void MultiLevelTimeSeries<VT, CT>::addValue(
TimeType now, TimePoint now,
const ValueType& val, const ValueType& val,
int64_t times) { int64_t times) {
addValueAggregated(now, val * times, times); addValueAggregated(now, val * times, times);
...@@ -80,7 +80,7 @@ void MultiLevelTimeSeries<VT, CT>::addValue( ...@@ -80,7 +80,7 @@ void MultiLevelTimeSeries<VT, CT>::addValue(
template <typename VT, typename CT> template <typename VT, typename CT>
void MultiLevelTimeSeries<VT, CT>::addValueAggregated( void MultiLevelTimeSeries<VT, CT>::addValueAggregated(
TimeType now, TimePoint now,
const ValueType& total, const ValueType& total,
int64_t nsamples) { int64_t nsamples) {
if (cachedTime_ != now) { if (cachedTime_ != now) {
...@@ -92,7 +92,7 @@ void MultiLevelTimeSeries<VT, CT>::addValueAggregated( ...@@ -92,7 +92,7 @@ void MultiLevelTimeSeries<VT, CT>::addValueAggregated(
} }
template <typename VT, typename CT> template <typename VT, typename CT>
void MultiLevelTimeSeries<VT, CT>::update(TimeType now) { void MultiLevelTimeSeries<VT, CT>::update(TimePoint now) {
flush(); flush();
for (size_t i = 0; i < levels_.size(); ++i) { for (size_t i = 0; i < levels_.size(); ++i) {
levels_[i].update(now); levels_[i].update(now);
...@@ -117,7 +117,7 @@ void MultiLevelTimeSeries<VT, CT>::clear() { ...@@ -117,7 +117,7 @@ void MultiLevelTimeSeries<VT, CT>::clear() {
level.clear(); level.clear();
} }
cachedTime_ = TimeType(0); cachedTime_ = TimePoint();
cachedSum_ = 0; cachedSum_ = 0;
cachedCount_ = 0; cachedCount_ = 0;
} }
......
...@@ -56,10 +56,6 @@ class MultiLevelTimeSeries { ...@@ -56,10 +56,6 @@ class MultiLevelTimeSeries {
using Clock = CT; using Clock = CT;
using Duration = typename Clock::duration; using Duration = typename Clock::duration;
using TimePoint = typename Clock::time_point; 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>; using Level = folly::BucketedTimeSeries<ValueType, Clock>;
/* /*
...@@ -73,13 +69,14 @@ class MultiLevelTimeSeries { ...@@ -73,13 +69,14 @@ class MultiLevelTimeSeries {
* be provided with a duration of '0' -- this will be an "all-time" level. If * be provided with a duration of '0' -- this will be an "all-time" level. If
* an all-time level is provided, it MUST be the last level present. * an all-time level is provided, it MUST be the last level present.
*/ */
MultiLevelTimeSeries(size_t numBuckets, MultiLevelTimeSeries(
size_t numLevels, size_t numBuckets,
const TimeType levelDurations[]); size_t numLevels,
const Duration levelDurations[]);
MultiLevelTimeSeries( MultiLevelTimeSeries(
size_t numBuckets, size_t numBuckets,
std::initializer_list<TimeType> durations); std::initializer_list<Duration> durations);
/* /*
* Return the number of buckets used to track time series at each level. * Return the number of buckets used to track time series at each level.
...@@ -115,7 +112,7 @@ class MultiLevelTimeSeries { ...@@ -115,7 +112,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
const Level& getLevel(TimeType start) const { const Level& getLevel(TimePoint start) const {
for (const auto& level : levels_) { for (const auto& level : levels_) {
if (level.isAllTime()) { if (level.isAllTime()) {
return level; return level;
...@@ -130,7 +127,7 @@ class MultiLevelTimeSeries { ...@@ -130,7 +127,7 @@ class MultiLevelTimeSeries {
} }
// We should always have an all-time level, so this is never reached. // We should always have an all-time level, so this is never reached.
LOG(FATAL) << "No level of timeseries covers internval" LOG(FATAL) << "No level of timeseries covers internval"
<< " from " << start.count() << " to now"; << " from " << start.time_since_epoch().count() << " to now";
return levels_.back(); return levels_.back();
} }
...@@ -141,7 +138,7 @@ class MultiLevelTimeSeries { ...@@ -141,7 +138,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
const Level& getLevelByDuration(TimeType duration) const { const Level& getLevelByDuration(Duration duration) const {
// since the number of levels is expected to be small (less than 5 in most // since the number of levels is expected to be small (less than 5 in most
// cases), a simple linear scan would be efficient and is intentionally // cases), a simple linear scan would be efficient and is intentionally
// chosen here over other alternatives for lookup. // chosen here over other alternatives for lookup.
...@@ -189,7 +186,7 @@ class MultiLevelTimeSeries { ...@@ -189,7 +186,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType=double, typename Interval=TimeType> template <typename ReturnType = double, typename Interval = Duration>
ReturnType rate(int level) const { ReturnType rate(int level) const {
return getLevel(level).template rate<ReturnType, Interval>(); return getLevel(level).template rate<ReturnType, Interval>();
} }
...@@ -212,7 +209,7 @@ class MultiLevelTimeSeries { ...@@ -212,7 +209,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType=double, typename Interval=TimeType> template <typename ReturnType = double, typename Interval = Duration>
ReturnType countRate(int level) const { ReturnType countRate(int level) const {
return getLevel(level).template countRate<ReturnType, Interval>(); return getLevel(level).template countRate<ReturnType, Interval>();
} }
...@@ -227,7 +224,7 @@ class MultiLevelTimeSeries { ...@@ -227,7 +224,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
ValueType sum(TimeType duration) const { ValueType sum(Duration duration) const {
return getLevelByDuration(duration).sum(); return getLevelByDuration(duration).sum();
} }
...@@ -243,7 +240,7 @@ class MultiLevelTimeSeries { ...@@ -243,7 +240,7 @@ class MultiLevelTimeSeries {
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType = double> template <typename ReturnType = double>
ReturnType avg(TimeType duration) const { ReturnType avg(Duration duration) const {
return getLevelByDuration(duration).template avg<ReturnType>(); return getLevelByDuration(duration).template avg<ReturnType>();
} }
...@@ -258,8 +255,8 @@ class MultiLevelTimeSeries { ...@@ -258,8 +255,8 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType = double, typename Interval = TimeType> template <typename ReturnType = double, typename Interval = Duration>
ReturnType rate(TimeType duration) const { ReturnType rate(Duration duration) const {
return getLevelByDuration(duration).template rate<ReturnType, Interval>(); return getLevelByDuration(duration).template rate<ReturnType, Interval>();
} }
...@@ -273,7 +270,7 @@ class MultiLevelTimeSeries { ...@@ -273,7 +270,7 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
int64_t count(TimeType duration) const { int64_t count(Duration duration) const {
return getLevelByDuration(duration).count(); return getLevelByDuration(duration).count();
} }
...@@ -287,8 +284,8 @@ class MultiLevelTimeSeries { ...@@ -287,8 +284,8 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType = double, typename Interval = TimeType> template <typename ReturnType = double, typename Interval = Duration>
ReturnType countRate(TimeType duration) const { ReturnType countRate(Duration duration) const {
return getLevelByDuration(duration) return getLevelByDuration(duration)
.template countRate<ReturnType, Interval>(); .template countRate<ReturnType, Interval>();
} }
...@@ -311,51 +308,51 @@ class MultiLevelTimeSeries { ...@@ -311,51 +308,51 @@ class MultiLevelTimeSeries {
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
ValueType sum(TimeType start, TimeType end) const { ValueType sum(TimePoint start, TimePoint end) const {
return getLevel(start).sum(start, end); return getLevel(start).sum(start, end);
} }
/* /*
* Estimate the average value during the specified time period. * Estimate the average value during the specified time period.
* *
* The same caveats documented in the sum(TimeType start, TimeType end) * The same caveats documented in the sum(TimePoint start, TimePoint end)
* comments apply here as well. * comments apply here as well.
* *
* Note: you should generally call update() or flush() before accessing the * Note: you should generally call update() or flush() before accessing the
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType=double> template <typename ReturnType = double>
ReturnType avg(TimeType start, TimeType end) const { ReturnType avg(TimePoint start, TimePoint end) const {
return getLevel(start).template avg<ReturnType>(start, end); return getLevel(start).template avg<ReturnType>(start, end);
} }
/* /*
* Estimate the rate during the specified time period. * Estimate the rate during the specified time period.
* *
* The same caveats documented in the sum(TimeType start, TimeType end) * The same caveats documented in the sum(TimePoint start, TimePoint end)
* comments apply here as well. * comments apply here as well.
* *
* Note: you should generally call update() or flush() before accessing the * Note: you should generally call update() or flush() before accessing the
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
template <typename ReturnType=double> template <typename ReturnType = double>
ReturnType rate(TimeType start, TimeType end) const { ReturnType rate(TimePoint start, TimePoint end) const {
return getLevel(start).template rate<ReturnType>(start, end); return getLevel(start).template rate<ReturnType>(start, end);
} }
/* /*
* Estimate the count during the specified time period. * Estimate the count during the specified time period.
* *
* The same caveats documented in the sum(TimeType start, TimeType end) * The same caveats documented in the sum(TimePoint start, TimePoint end)
* comments apply here as well. * comments apply here as well.
* *
* Note: you should generally call update() or flush() before accessing the * Note: you should generally call update() or flush() before accessing the
* data. Otherwise you may be reading stale data if update() or flush() has * data. Otherwise you may be reading stale data if update() or flush() has
* not been called recently. * not been called recently.
*/ */
int64_t count(TimeType start, TimeType end) const { int64_t count(TimePoint start, TimePoint end) const {
return getLevel(start).count(start, end); return getLevel(start).count(start, end);
} }
...@@ -372,18 +369,19 @@ class MultiLevelTimeSeries { ...@@ -372,18 +369,19 @@ class MultiLevelTimeSeries {
* addValue() or update(), now will be ignored and the latest timestamp will * addValue() or update(), now will be ignored and the latest timestamp will
* be used. * be used.
*/ */
void addValue(TimeType now, const ValueType& val); void addValue(TimePoint now, const ValueType& val);
/* /*
* Adds the value 'val' at time 'now' to all levels. * Adds the value 'val' at time 'now' to all levels.
*/ */
void addValue(TimeType now, const ValueType& val, int64_t times); void addValue(TimePoint now, const ValueType& val, int64_t times);
/* /*
* Adds the value 'val' at time 'now' to all levels as the sum of 'nsamples' * Adds the value 'total' at time 'now' to all levels as the sum of
* samples. * 'nsamples' samples.
*/ */
void addValueAggregated(TimeType now, const ValueType& sum, int64_t nsamples); void
addValueAggregated(TimePoint now, const ValueType& total, int64_t nsamples);
/* /*
* Update all the levels to the specified time, doing all the necessary * Update all the levels to the specified time, doing all the necessary
...@@ -393,7 +391,7 @@ class MultiLevelTimeSeries { ...@@ -393,7 +391,7 @@ class MultiLevelTimeSeries {
* call update() before accessing the data. Otherwise you may be reading * call update() before accessing the data. Otherwise you may be reading
* stale data if update() has not been called recently. * stale data if update() has not been called recently.
*/ */
void update(TimeType now); void update(TimePoint now);
/* /*
* Reset all the timeseries to an empty state as if no data points have ever * Reset all the timeseries to an empty state as if no data points have ever
...@@ -406,13 +404,34 @@ class MultiLevelTimeSeries { ...@@ -406,13 +404,34 @@ class MultiLevelTimeSeries {
*/ */
void flush(); void flush();
/*
* Legacy APIs that accept a Duration parameters rather than TimePoint.
*
* These treat the Duration as relative to the clock epoch.
* Prefer using the correct TimePoint-based APIs instead. These APIs will
* eventually be deprecated and removed.
*/
void update(Duration now) {
update(TimePoint(now));
}
void addValue(Duration now, const ValueType& value) {
addValue(TimePoint(now), value);
}
void addValue(Duration now, const ValueType& value, int64_t times) {
addValue(TimePoint(now), value, times);
}
void
addValueAggregated(Duration now, const ValueType& total, int64_t nsamples) {
addValueAggregated(TimePoint(now), total, nsamples);
}
private: private:
std::vector<Level> levels_; std::vector<Level> levels_;
// Updates within the same time interval are cached // Updates within the same time interval are cached
// They are flushed out when updates from a different time comes, // They are flushed out when updates from a different time comes,
// or flush() is called. // or flush() is called.
TimeType cachedTime_; TimePoint cachedTime_;
ValueType cachedSum_; ValueType cachedSum_;
int cachedCount_; int cachedCount_;
}; };
......
...@@ -35,7 +35,7 @@ TimeseriesHistogram<T, CT, C>::TimeseriesHistogram( ...@@ -35,7 +35,7 @@ TimeseriesHistogram<T, CT, C>::TimeseriesHistogram(
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
void TimeseriesHistogram<T, CT, C>::addValue( void TimeseriesHistogram<T, CT, C>::addValue(
TimeType now, TimePoint now,
const ValueType& value) { const ValueType& value) {
buckets_.getByValue(value).addValue(now, value); buckets_.getByValue(value).addValue(now, value);
maybeHandleSingleUniqueValue(value); maybeHandleSingleUniqueValue(value);
...@@ -43,7 +43,7 @@ void TimeseriesHistogram<T, CT, C>::addValue( ...@@ -43,7 +43,7 @@ void TimeseriesHistogram<T, CT, C>::addValue(
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
void TimeseriesHistogram<T, CT, C>::addValue( void TimeseriesHistogram<T, CT, C>::addValue(
TimeType now, TimePoint now,
const ValueType& value, const ValueType& value,
int64_t times) { int64_t times) {
buckets_.getByValue(value).addValue(now, value, times); buckets_.getByValue(value).addValue(now, value, times);
...@@ -52,7 +52,7 @@ void TimeseriesHistogram<T, CT, C>::addValue( ...@@ -52,7 +52,7 @@ void TimeseriesHistogram<T, CT, C>::addValue(
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
void TimeseriesHistogram<T, CT, C>::addValues( void TimeseriesHistogram<T, CT, C>::addValues(
TimeType now, TimePoint now,
const folly::Histogram<ValueType>& hist) { const folly::Histogram<ValueType>& hist) {
CHECK_EQ(hist.getMin(), getMin()); CHECK_EQ(hist.getMin(), getMin());
CHECK_EQ(hist.getMax(), getMax()); CHECK_EQ(hist.getMax(), getMax());
...@@ -99,8 +99,8 @@ T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(double pct, int level) ...@@ -99,8 +99,8 @@ T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(double pct, int level)
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
T TimeseriesHistogram<T, CT, C>::getPercentileEstimate( T TimeseriesHistogram<T, CT, C>::getPercentileEstimate(
double pct, double pct,
TimeType start, TimePoint start,
TimeType end) const { TimePoint end) const {
if (singleUniqueValue_) { if (singleUniqueValue_) {
return firstValue_; return firstValue_;
} }
...@@ -119,8 +119,8 @@ int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(double pct, int level) ...@@ -119,8 +119,8 @@ int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(double pct, int level)
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx( int TimeseriesHistogram<T, CT, C>::getPercentileBucketIdx(
double pct, double pct,
TimeType start, TimePoint start,
TimeType end) const { TimePoint end) const {
return buckets_.getPercentileBucketIdx(pct / 100.0, return buckets_.getPercentileBucketIdx(pct / 100.0,
CountFromInterval(start, end)); CountFromInterval(start, end));
} }
...@@ -133,7 +133,7 @@ void TimeseriesHistogram<T, CT, C>::clear() { ...@@ -133,7 +133,7 @@ void TimeseriesHistogram<T, CT, C>::clear() {
} }
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
void TimeseriesHistogram<T, CT, C>::update(TimeType now) { void TimeseriesHistogram<T, CT, C>::update(TimePoint now) {
for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
buckets_.getByIndex(i).update(now); buckets_.getByIndex(i).update(now);
} }
...@@ -158,8 +158,8 @@ std::string TimeseriesHistogram<T, CT, C>::getString(int level) const { ...@@ -158,8 +158,8 @@ std::string TimeseriesHistogram<T, CT, C>::getString(int level) const {
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
std::string TimeseriesHistogram<T, CT, C>::getString( std::string TimeseriesHistogram<T, CT, C>::getString(
TimeType start, TimePoint start,
TimeType end) const { TimePoint end) const {
std::string result; std::string result;
for (size_t i = 0; i < buckets_.getNumBuckets(); i++) { for (size_t i = 0; i < buckets_.getNumBuckets(); i++) {
...@@ -191,8 +191,8 @@ template <class T, class CT, class C> ...@@ -191,8 +191,8 @@ template <class T, class CT, class C>
void TimeseriesHistogram<T, CT, C>::computeAvgData( void TimeseriesHistogram<T, CT, C>::computeAvgData(
ValueType* total, ValueType* total,
int64_t* nsamples, int64_t* nsamples,
TimeType start, TimePoint start,
TimeType end) const { TimePoint end) const {
for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) {
const auto& levelObj = buckets_.getByIndex(b).getLevel(start); const auto& levelObj = buckets_.getByIndex(b).getLevel(start);
*total += levelObj.sum(start, end); *total += levelObj.sum(start, end);
...@@ -203,7 +203,7 @@ void TimeseriesHistogram<T, CT, C>::computeAvgData( ...@@ -203,7 +203,7 @@ void TimeseriesHistogram<T, CT, C>::computeAvgData(
template <typename T, typename CT, typename C> template <typename T, typename CT, typename C>
void TimeseriesHistogram<T, CT, C>::computeRateData( void TimeseriesHistogram<T, CT, C>::computeRateData(
ValueType* total, ValueType* total,
TimeType* elapsed, Duration* elapsed,
int level) const { int level) const {
for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) {
const auto& levelObj = buckets_.getByIndex(b).getLevel(level); const auto& levelObj = buckets_.getByIndex(b).getLevel(level);
...@@ -215,9 +215,9 @@ void TimeseriesHistogram<T, CT, C>::computeRateData( ...@@ -215,9 +215,9 @@ void TimeseriesHistogram<T, CT, C>::computeRateData(
template <class T, class CT, class C> template <class T, class CT, class C>
void TimeseriesHistogram<T, CT, C>::computeRateData( void TimeseriesHistogram<T, CT, C>::computeRateData(
ValueType* total, ValueType* total,
TimeType* elapsed, Duration* elapsed,
TimeType start, TimePoint start,
TimeType end) const { TimePoint end) const {
for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) {
const auto& level = buckets_.getByIndex(b).getLevel(start); const auto& level = buckets_.getByIndex(b).getLevel(start);
*total += level.sum(start, end); *total += level.sum(start, end);
......
...@@ -65,10 +65,6 @@ class TimeseriesHistogram { ...@@ -65,10 +65,6 @@ class TimeseriesHistogram {
using Clock = CT; using Clock = CT;
using Duration = typename Clock::duration; using Duration = typename Clock::duration;
using TimePoint = typename Clock::time_point; 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.
...@@ -128,7 +124,7 @@ class TimeseriesHistogram { ...@@ -128,7 +124,7 @@ class TimeseriesHistogram {
} }
/* Total count of values added during the given interval (all buckets). */ /* Total count of values added during the given interval (all buckets). */
int64_t count(TimeType start, TimeType end) const { int64_t count(TimePoint start, TimePoint end) const {
int64_t total = 0; int64_t total = 0;
for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) {
total += buckets_.getByIndex(b).count(start, end); total += buckets_.getByIndex(b).count(start, end);
...@@ -146,7 +142,7 @@ class TimeseriesHistogram { ...@@ -146,7 +142,7 @@ class TimeseriesHistogram {
} }
/* Total sum of values added during the given interval (all buckets). */ /* Total sum of values added during the given interval (all buckets). */
ValueType sum(TimeType start, TimeType end) const { ValueType sum(TimePoint start, TimePoint end) const {
ValueType total = ValueType(); ValueType total = ValueType();
for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) { for (unsigned int b = 0; b < buckets_.getNumBuckets(); ++b) {
total += buckets_.getByIndex(b).sum(start, end); total += buckets_.getByIndex(b).sum(start, end);
...@@ -165,7 +161,7 @@ class TimeseriesHistogram { ...@@ -165,7 +161,7 @@ class TimeseriesHistogram {
/* Average of values added during the given interval (all buckets). */ /* Average of values added during the given interval (all buckets). */
template <typename ReturnType = double> template <typename ReturnType = double>
ReturnType avg(TimeType start, TimeType end) const { ReturnType avg(TimePoint start, TimePoint end) const {
auto total = ValueType(); auto total = ValueType();
int64_t nsamples = 0; int64_t nsamples = 0;
computeAvgData(&total, &nsamples, start, end); computeAvgData(&total, &nsamples, start, end);
...@@ -179,9 +175,9 @@ class TimeseriesHistogram { ...@@ -179,9 +175,9 @@ class TimeseriesHistogram {
template <typename ReturnType = double> template <typename ReturnType = double>
ReturnType rate(int level) const { ReturnType rate(int level) const {
auto total = ValueType(); auto total = ValueType();
TimeType elapsed(0); Duration elapsed(0);
computeRateData(&total, &elapsed, level); computeRateData(&total, &elapsed, level);
return folly::detail::rateHelper<ReturnType, TimeType, TimeType>( return folly::detail::rateHelper<ReturnType, Duration, Duration>(
total, elapsed); total, elapsed);
} }
...@@ -190,11 +186,11 @@ class TimeseriesHistogram { ...@@ -190,11 +186,11 @@ class TimeseriesHistogram {
* This is the sum of all values divided by the time interval (in seconds). * This is the sum of all values divided by the time interval (in seconds).
*/ */
template <typename ReturnType = double> template <typename ReturnType = double>
ReturnType rate(TimeType start, TimeType end) const { ReturnType rate(TimePoint start, TimePoint end) const {
auto total = ValueType(); auto total = ValueType();
TimeType elapsed(0); Duration elapsed(0);
computeRateData(&total, &elapsed, start, end); computeRateData(&total, &elapsed, start, end);
return folly::detail::rateHelper<ReturnType, TimeType, TimeType>( return folly::detail::rateHelper<ReturnType, Duration, Duration>(
total, elapsed); total, elapsed);
} }
...@@ -203,15 +199,15 @@ class TimeseriesHistogram { ...@@ -203,15 +199,15 @@ class TimeseriesHistogram {
* must call this directly before querying to ensure that the data in all * must call this directly before querying to ensure that the data in all
* buckets is decayed properly. * buckets is decayed properly.
*/ */
void update(TimeType now); void update(TimePoint now);
/* clear all the data from the histogram. */ /* clear all the data from the histogram. */
void clear(); void clear();
/* Add a value into the histogram with timestamp 'now' */ /* Add a value into the histogram with timestamp 'now' */
void addValue(TimeType now, const ValueType& value); void addValue(TimePoint now, const ValueType& value);
/* Add a value the given number of times with timestamp 'now' */ /* Add a value the given number of times with timestamp 'now' */
void addValue(TimeType now, const ValueType& value, int64_t times); void addValue(TimePoint now, const ValueType& value, int64_t times);
/* /*
* Add all of the values from the specified histogram. * Add all of the values from the specified histogram.
...@@ -223,7 +219,7 @@ class TimeseriesHistogram { ...@@ -223,7 +219,7 @@ class TimeseriesHistogram {
* Histogram that is updated frequently, and only add it to the global * Histogram that is updated frequently, and only add it to the global
* TimeseriesHistogram once a second. * TimeseriesHistogram once a second.
*/ */
void addValues(TimeType now, const folly::Histogram<ValueType>& values); void addValues(TimePoint now, const folly::Histogram<ValueType>& values);
/* /*
* Return an estimate of the value at the given percentile in the histogram * Return an estimate of the value at the given percentile in the histogram
...@@ -252,8 +248,8 @@ class TimeseriesHistogram { ...@@ -252,8 +248,8 @@ class TimeseriesHistogram {
* getPercentileEstimate(int pct, int level) for the explanation of the * getPercentileEstimate(int pct, int level) for the explanation of the
* estimation algorithm. * estimation algorithm.
*/ */
ValueType getPercentileEstimate(double pct, TimeType start, TimeType end) ValueType getPercentileEstimate(double pct, TimePoint start, TimePoint end)
const; const;
/* /*
* Return the bucket index that the given percentile falls into (in the * Return the bucket index that the given percentile falls into (in the
...@@ -266,14 +262,14 @@ class TimeseriesHistogram { ...@@ -266,14 +262,14 @@ class TimeseriesHistogram {
* given historical interval). This index can then be used to retrieve either * given historical interval). This index can then be used to retrieve either
* the bucket threshold, or other data from inside the bucket. * the bucket threshold, or other data from inside the bucket.
*/ */
int getPercentileBucketIdx(double pct, TimeType start, TimeType end) const; int getPercentileBucketIdx(double pct, TimePoint start, TimePoint end) const;
/* Get the bucket threshold for the bucket containing the given pct. */ /* Get the bucket threshold for the bucket containing the given pct. */
int getPercentileBucketMin(double pct, int level) const { int getPercentileBucketMin(double pct, int level) const {
return getBucketMin(getPercentileBucketIdx(pct, level)); return getBucketMin(getPercentileBucketIdx(pct, level));
} }
/* Get the bucket threshold for the bucket containing the given pct. */ /* Get the bucket threshold for the bucket containing the given pct. */
int getPercentileBucketMin(double pct, TimeType start, TimeType end) const { int getPercentileBucketMin(double pct, TimePoint start, TimePoint end) const {
return getBucketMin(getPercentileBucketIdx(pct, start, end)); return getBucketMin(getPercentileBucketIdx(pct, start, end));
} }
...@@ -288,7 +284,27 @@ class TimeseriesHistogram { ...@@ -288,7 +284,27 @@ class TimeseriesHistogram {
* Print out serialized data for all buckets in the historical interval. * Print out serialized data for all buckets in the historical interval.
* For format, please see getString(int level). * For format, please see getString(int level).
*/ */
std::string getString(TimeType start, TimeType end) const; std::string getString(TimePoint start, TimePoint end) const;
/*
* Legacy APIs that accept a Duration parameters rather than TimePoint.
*
* These treat the Duration as relative to the clock epoch.
* Prefer using the correct TimePoint-based APIs instead. These APIs will
* eventually be deprecated and removed.
*/
void update(Duration now) {
update(TimePoint(now));
}
void addValue(Duration now, const ValueType& value) {
addValue(TimePoint(now), value);
}
void addValue(Duration now, const ValueType& value, int64_t times) {
addValue(TimePoint(now), value, times);
}
void addValues(Duration now, const folly::Histogram<ValueType>& values) {
addValues(TimePoint(now), values);
}
private: private:
typedef ContainerType Bucket; typedef ContainerType Bucket;
...@@ -303,17 +319,16 @@ class TimeseriesHistogram { ...@@ -303,17 +319,16 @@ class TimeseriesHistogram {
int level_; int level_;
}; };
struct CountFromInterval { struct CountFromInterval {
explicit CountFromInterval(TimeType start, TimeType end) explicit CountFromInterval(TimePoint start, TimePoint end)
: start_(start), : start_(start), end_(end) {}
end_(end) {}
uint64_t operator()(const ContainerType& bucket) const { uint64_t operator()(const ContainerType& bucket) const {
return bucket.count(start_, end_); return bucket.count(start_, end_);
} }
private: private:
TimeType start_; TimePoint start_;
TimeType end_; TimePoint end_;
}; };
struct AvgFromLevel { struct AvgFromLevel {
...@@ -329,17 +344,16 @@ class TimeseriesHistogram { ...@@ -329,17 +344,16 @@ class TimeseriesHistogram {
template <typename ReturnType> template <typename ReturnType>
struct AvgFromInterval { struct AvgFromInterval {
explicit AvgFromInterval(TimeType start, TimeType end) explicit AvgFromInterval(TimePoint start, TimePoint end)
: start_(start), : start_(start), end_(end) {}
end_(end) {}
ReturnType operator()(const ContainerType& bucket) const { ReturnType operator()(const ContainerType& bucket) const {
return bucket.template avg<ReturnType>(start_, end_); return bucket.template avg<ReturnType>(start_, end_);
} }
private: private:
TimeType start_; TimePoint start_;
TimeType end_; TimePoint end_;
}; };
/* /*
...@@ -354,14 +368,14 @@ class TimeseriesHistogram { ...@@ -354,14 +368,14 @@ class TimeseriesHistogram {
void computeAvgData( void computeAvgData(
ValueType* total, ValueType* total,
int64_t* nsamples, int64_t* nsamples,
TimeType start, TimePoint start,
TimeType end) const; TimePoint end) const;
void computeRateData(ValueType* total, TimeType* elapsed, int level) const; void computeRateData(ValueType* total, Duration* elapsed, int level) const;
void computeRateData( void computeRateData(
ValueType* total, ValueType* total,
TimeType* elapsed, Duration* elapsed,
TimeType start, TimePoint start,
TimeType end) const; TimePoint end) const;
folly::detail::HistogramBuckets<ValueType, ContainerType> buckets_; folly::detail::HistogramBuckets<ValueType, ContainerType> buckets_;
bool haveNotSeenValue_; bool haveNotSeenValue_;
......
...@@ -25,6 +25,7 @@ using namespace std; ...@@ -25,6 +25,7 @@ using namespace std;
using namespace folly; using namespace folly;
using std::chrono::seconds; using std::chrono::seconds;
namespace {
namespace IntMTMHTS { namespace IntMTMHTS {
enum Levels { enum Levels {
MINUTE, MINUTE,
...@@ -54,6 +55,12 @@ namespace IntMHTS { ...@@ -54,6 +55,12 @@ namespace IntMHTS {
typedef std::mt19937 RandomInt32; typedef std::mt19937 RandomInt32;
using StatsClock = folly::LegacyStatsClock<std::chrono::seconds>;
StatsClock::time_point mkTimePoint(int value) {
return StatsClock::time_point(StatsClock::duration(value));
}
}
TEST(TimeseriesHistogram, Percentile) { TEST(TimeseriesHistogram, Percentile) {
RandomInt32 random(5); RandomInt32 random(5);
// [10, 109], 12 buckets including above and below // [10, 109], 12 buckets including above and below
...@@ -75,14 +82,13 @@ TEST(TimeseriesHistogram, Percentile) { ...@@ -75,14 +82,13 @@ TEST(TimeseriesHistogram, Percentile) {
} }
int maxVal = 120; int maxVal = 120;
h.addValue(seconds(0), 0); h.addValue(mkTimePoint(0), 0);
h.addValue(seconds(0), maxVal); h.addValue(mkTimePoint(0), maxVal);
for (int i = 0; i < 98; i++) { for (int i = 0; i < 98; i++) {
h.addValue(seconds(0), random() % maxVal); h.addValue(mkTimePoint(0), random() % maxVal);
} }
h.update(std::chrono::duration_cast<std::chrono::seconds>( h.update(mkTimePoint(1500000000));
std::chrono::system_clock::now().time_since_epoch()));
// bucket 0 stores everything below min, so its minimum // bucket 0 stores everything below min, so its minimum
// is the lowest possible number // is the lowest possible number
EXPECT_EQ(std::numeric_limits<int>::min(), EXPECT_EQ(std::numeric_limits<int>::min(),
...@@ -106,13 +112,13 @@ TEST(TimeseriesHistogram, String) { ...@@ -106,13 +112,13 @@ TEST(TimeseriesHistogram, String) {
IntMTMHTS::kDurations)); IntMTMHTS::kDurations));
int maxVal = 120; int maxVal = 120;
hist.addValue(seconds(0), 0); hist.addValue(mkTimePoint(0), 0);
hist.addValue(seconds(0), maxVal); hist.addValue(mkTimePoint(0), maxVal);
for (int i = 0; i < 98; i++) { for (int i = 0; i < 98; i++) {
hist.addValue(seconds(0), random() % maxVal); hist.addValue(mkTimePoint(0), random() % maxVal);
} }
hist.update(seconds(0)); hist.update(mkTimePoint(0));
const char* const kStringValues1[IntMTMHTS::NUM_LEVELS] = { const char* const kStringValues1[IntMTMHTS::NUM_LEVELS] = {
"-2147483648:12:4,10:8:13,20:8:24,30:6:34,40:13:46,50:8:54,60:7:64," "-2147483648:12:4,10:8:13,20:8:24,30:6:34,40:13:46,50:8:54,60:7:64,"
...@@ -159,7 +165,7 @@ TEST(TimeseriesHistogram, Clear) { ...@@ -159,7 +165,7 @@ TEST(TimeseriesHistogram, Clear) {
for (int now = 0; now < 3600; now++) { for (int now = 0; now < 3600; now++) {
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
hist.addValue(seconds(now), i, 2); // adds each item 2 times hist.addValue(mkTimePoint(now), i, 2); // adds each item 2 times
} }
} }
...@@ -197,11 +203,11 @@ TEST(TimeseriesHistogram, Basic) { ...@@ -197,11 +203,11 @@ TEST(TimeseriesHistogram, Basic) {
for (int now = 0; now < 3600; now++) { for (int now = 0; now < 3600; now++) {
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
hist.addValue(seconds(now), i); hist.addValue(mkTimePoint(now), i);
} }
} }
hist.update(seconds(3599)); hist.update(mkTimePoint(3599));
for (int pct = 1; pct <= 100; pct++) { for (int pct = 1; pct <= 100; pct++) {
int expected = (pct - 1) / 10 * 10; int expected = (pct - 1) / 10 * 10;
EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE)); EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE));
...@@ -250,20 +256,20 @@ TEST(TimeseriesHistogram, Basic) { ...@@ -250,20 +256,20 @@ TEST(TimeseriesHistogram, Basic) {
EXPECT_EQ(4950, hist.rate<double>(IntMTMHTS::HOUR)); EXPECT_EQ(4950, hist.rate<double>(IntMTMHTS::HOUR));
EXPECT_EQ(4950, hist.rate<double>(IntMTMHTS::ALLTIME)); EXPECT_EQ(4950, hist.rate<double>(IntMTMHTS::ALLTIME));
EXPECT_EQ(1000, hist.count(seconds(10), seconds(20))); EXPECT_EQ(1000, hist.count(mkTimePoint(10), mkTimePoint(20)));
EXPECT_EQ(49500, hist.sum(seconds(10), seconds(20))); EXPECT_EQ(49500, hist.sum(mkTimePoint(10), mkTimePoint(20)));
EXPECT_EQ(4950, hist.rate(seconds(10), seconds(20))); EXPECT_EQ(4950, hist.rate(mkTimePoint(10), mkTimePoint(20)));
EXPECT_EQ(49.5, hist.avg<double>(seconds(10), seconds(20))); EXPECT_EQ(49.5, hist.avg<double>(mkTimePoint(10), mkTimePoint(20)));
EXPECT_EQ(200, hist.count(seconds(3550), seconds(3552))); EXPECT_EQ(200, hist.count(mkTimePoint(3550), mkTimePoint(3552)));
EXPECT_EQ(9900, hist.sum(seconds(3550), seconds(3552))); EXPECT_EQ(9900, hist.sum(mkTimePoint(3550), mkTimePoint(3552)));
EXPECT_EQ(4950, hist.rate(seconds(3550), seconds(3552))); EXPECT_EQ(4950, hist.rate(mkTimePoint(3550), mkTimePoint(3552)));
EXPECT_EQ(49.5, hist.avg<double>(seconds(3550), seconds(3552))); EXPECT_EQ(49.5, hist.avg<double>(mkTimePoint(3550), mkTimePoint(3552)));
EXPECT_EQ(0, hist.count(seconds(4550), seconds(4552))); EXPECT_EQ(0, hist.count(mkTimePoint(4550), mkTimePoint(4552)));
EXPECT_EQ(0, hist.sum(seconds(4550), seconds(4552))); EXPECT_EQ(0, hist.sum(mkTimePoint(4550), mkTimePoint(4552)));
EXPECT_EQ(0, hist.rate(seconds(4550), seconds(4552))); EXPECT_EQ(0, hist.rate(mkTimePoint(4550), mkTimePoint(4552)));
EXPECT_EQ(0, hist.avg<double>(seconds(4550), seconds(4552))); EXPECT_EQ(0, hist.avg<double>(mkTimePoint(4550), mkTimePoint(4552)));
} }
// ----------------- // -----------------
...@@ -276,11 +282,11 @@ TEST(TimeseriesHistogram, Basic) { ...@@ -276,11 +282,11 @@ TEST(TimeseriesHistogram, Basic) {
for (int now = 0; now < 3600; now++) { for (int now = 0; now < 3600; now++) {
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
hist.addValue(seconds(now), i, 2); // adds each item 2 times hist.addValue(mkTimePoint(now), i, 2); // adds each item 2 times
} }
} }
hist.update(seconds(3599)); hist.update(mkTimePoint(3599));
for (int pct = 1; pct <= 100; pct++) { for (int pct = 1; pct <= 100; pct++) {
int expected = (pct - 1) / 10 * 10; int expected = (pct - 1) / 10 * 10;
EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE)); EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE));
...@@ -311,11 +317,11 @@ TEST(TimeseriesHistogram, Basic) { ...@@ -311,11 +317,11 @@ TEST(TimeseriesHistogram, Basic) {
for (int now = 0; now < 3600; now++) { for (int now = 0; now < 3600; now++) {
for (int i = 0; i < 50; i++) { for (int i = 0; i < 50; i++) {
hist.addValue(seconds(now), i * 2, 2); // adds each item 2 times hist.addValue(mkTimePoint(now), i * 2, 2); // adds each item 2 times
} }
} }
hist.update(seconds(3599)); hist.update(mkTimePoint(3599));
for (int pct = 1; pct <= 100; pct++) { for (int pct = 1; pct <= 100; pct++) {
int expected = (pct - 1) / 10 * 10; int expected = (pct - 1) / 10 * 10;
EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE)); EXPECT_EQ(expected, hist.getPercentileBucketMin(pct, IntMTMHTS::MINUTE));
...@@ -348,9 +354,9 @@ TEST(TimeseriesHistogram, Basic) { ...@@ -348,9 +354,9 @@ TEST(TimeseriesHistogram, Basic) {
} }
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
hist.addValue(seconds(3599), 200 + i); hist.addValue(mkTimePoint(3599), 200 + i);
} }
hist.update(seconds(3599)); hist.update(mkTimePoint(3599));
EXPECT_EQ(100, EXPECT_EQ(100,
hist.getBucket(hist.getNumBuckets() - 1).count( hist.getBucket(hist.getNumBuckets() - 1).count(
IntMTMHTS::ALLTIME)); IntMTMHTS::ALLTIME));
...@@ -364,27 +370,26 @@ TEST(TimeseriesHistogram, QueryByInterval) { ...@@ -364,27 +370,26 @@ TEST(TimeseriesHistogram, QueryByInterval) {
60, IntMHTS::NUM_LEVELS, 60, IntMHTS::NUM_LEVELS,
IntMHTS::kDurations)); IntMHTS::kDurations));
mhts.update(seconds(0)); mhts.update(mkTimePoint(0));
int curTime; int curTime;
for (curTime = 0; curTime < 7200; curTime++) { for (curTime = 0; curTime < 7200; curTime++) {
mhts.addValue(seconds(curTime), 1); mhts.addValue(mkTimePoint(curTime), 1);
} }
for (curTime = 7200; curTime < 7200 + 3540; curTime++) { for (curTime = 7200; curTime < 7200 + 3540; curTime++) {
mhts.addValue(seconds(curTime), 10); mhts.addValue(mkTimePoint(curTime), 10);
} }
for (curTime = 7200 + 3540; curTime < 7200 + 3600; curTime++) { for (curTime = 7200 + 3540; curTime < 7200 + 3600; curTime++) {
mhts.addValue(seconds(curTime), 100); mhts.addValue(mkTimePoint(curTime), 100);
} }
mhts.update(seconds(7200 + 3600 - 1)); mhts.update(mkTimePoint(7200 + 3600 - 1));
struct TimeInterval { struct TimeInterval {
TimeInterval(int s, int e) TimeInterval(int s, int e) : start(mkTimePoint(s)), end(mkTimePoint(e)) {}
: start(s), end(e) {}
std::chrono::seconds start; StatsClock::time_point start;
std::chrono::seconds end; StatsClock::time_point end;
}; };
TimeInterval intervals[12] = { TimeInterval intervals[12] = {
{ curTime - 60, curTime }, { curTime - 60, curTime },
...@@ -442,10 +447,14 @@ TEST(TimeseriesHistogram, QueryByInterval) { ...@@ -442,10 +447,14 @@ TEST(TimeseriesHistogram, QueryByInterval) {
// 3 levels // 3 levels
for (int i = 1; i <= 100; i++) { for (int i = 1; i <= 100; i++) {
EXPECT_EQ(96, mhts.getPercentileBucketMin(i, 0)); EXPECT_EQ(96, mhts.getPercentileBucketMin(i, 0));
EXPECT_EQ(96, mhts.getPercentileBucketMin(i, seconds(curTime - 60), EXPECT_EQ(
seconds(curTime))); 96,
EXPECT_EQ(8, mhts.getPercentileBucketMin(i, seconds(curTime - 3540), mhts.getPercentileBucketMin(
seconds(curTime - 60))); i, mkTimePoint(curTime - 60), mkTimePoint(curTime)));
EXPECT_EQ(
8,
mhts.getPercentileBucketMin(
i, mkTimePoint(curTime - 3540), mkTimePoint(curTime - 60)));
} }
EXPECT_EQ(8, mhts.getPercentileBucketMin(1, 1)); EXPECT_EQ(8, mhts.getPercentileBucketMin(1, 1));
...@@ -477,9 +486,9 @@ TEST(TimeseriesHistogram, QueryByInterval) { ...@@ -477,9 +486,9 @@ TEST(TimeseriesHistogram, QueryByInterval) {
// Some of the older intervals that fall in the alltime bucket // Some of the older intervals that fall in the alltime bucket
// are off by 1 or 2 in their estimated counts. // are off by 1 or 2 in their estimated counts.
size_t tolerance = 0; size_t tolerance = 0;
if (itv.start <= seconds(curTime - 7200)) { if (itv.start <= mkTimePoint(curTime - 7200)) {
tolerance = 2; tolerance = 2;
} else if (itv.start <= seconds(curTime - 3000)) { } else if (itv.start <= mkTimePoint(curTime - 3000)) {
tolerance = 1; tolerance = 1;
} }
size_t actualCount = (itv.end - itv.start).count(); size_t actualCount = (itv.end - itv.start).count();
...@@ -500,9 +509,9 @@ TEST(TimeseriesHistogram, SingleUniqueValue) { ...@@ -500,9 +509,9 @@ TEST(TimeseriesHistogram, SingleUniqueValue) {
const int kNumIters = 1000; const int kNumIters = 1000;
for (int jj = 0; jj < kNumIters; ++jj) { for (int jj = 0; jj < kNumIters; ++jj) {
h.addValue(seconds(time(nullptr)), value); h.addValue(mkTimePoint(1), value);
} }
h.update(seconds(time(nullptr))); h.update(mkTimePoint(1));
// since we've only added one unique value, all percentiles should // since we've only added one unique value, all percentiles should
// be that value // be that value
EXPECT_EQ(h.getPercentileEstimate(10, 0), value); EXPECT_EQ(h.getPercentileEstimate(10, 0), value);
...@@ -512,9 +521,9 @@ TEST(TimeseriesHistogram, SingleUniqueValue) { ...@@ -512,9 +521,9 @@ TEST(TimeseriesHistogram, SingleUniqueValue) {
// Things get trickier if there are multiple unique values. // Things get trickier if there are multiple unique values.
const int kNewValue = 750; const int kNewValue = 750;
for (int kk = 0; kk < 2*kNumIters; ++kk) { for (int kk = 0; kk < 2*kNumIters; ++kk) {
h.addValue(seconds(time(nullptr)), kNewValue); h.addValue(mkTimePoint(1), kNewValue);
} }
h.update(seconds(time(nullptr))); h.update(mkTimePoint(1));
EXPECT_NEAR(h.getPercentileEstimate(50, 0), kNewValue+5, 5); EXPECT_NEAR(h.getPercentileEstimate(50, 0), kNewValue+5, 5);
if (value >= 0 && value <= 1000) { if (value >= 0 && value <= 1000) {
// only do further testing if value is within our bucket range, // only do further testing if value is within our bucket range,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment