Commit 8b030a19 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot 9

a simple first step towards using clocks properly in the stats code

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
parent 9637519e
......@@ -22,12 +22,11 @@
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()) {
......@@ -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);
}
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);
}
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;
......@@ -98,8 +99,8 @@ bool BucketedTimeSeries<VT, TT>::addValueAggregated(TimeType now,
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;
......@@ -121,8 +122,8 @@ size_t BucketedTimeSeries<VT, TT>::update(TimeType 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
......@@ -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();
}
......@@ -184,9 +185,8 @@ void BucketedTimeSeries<VT, TT>::clear() {
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);
}
......@@ -203,8 +203,9 @@ TT BucketedTimeSeries<VT, TT>::getEarliestTime() const {
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;
......@@ -216,8 +217,8 @@ TT BucketedTimeSeries<VT, TT>::getEarliestTimeNonEmpty() const {
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);
}
......@@ -226,8 +227,10 @@ TT BucketedTimeSeries<VT, TT>::elapsed() const {
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);
}
......@@ -237,8 +240,8 @@ TT BucketedTimeSeries<VT, TT>::elapsed(TimeType start, TimeType end) const {
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,
......@@ -251,8 +254,8 @@ VT BucketedTimeSeries<VT, TT>::sum(TimeType start, TimeType end) const {
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,
......@@ -265,9 +268,9 @@ uint64_t BucketedTimeSeries<VT, TT>::count(TimeType start, TimeType end) const {
return sample_count;
}
template <typename VT, typename TT>
template <typename VT, typename CT>
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,
......@@ -304,8 +307,8 @@ ReturnType BucketedTimeSeries<VT, TT>::avg(TimeType start, TimeType end) const {
* 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());
......@@ -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.
*/
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());
......@@ -349,9 +354,9 @@ void BucketedTimeSeries<VT, TT>::getBucketInfo(
*nextBucketStart = nextBucketStartMod + durationStart;
}
template <typename VT, typename TT>
template <typename VT, typename CT>
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;
......@@ -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.
*/
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_
......@@ -442,10 +450,12 @@ VT BucketedTimeSeries<VT, TT>::rangeAdjust(
(nextBucketStart - bucketStart);
}
template <typename VT, typename TT>
template <typename VT, typename CT>
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) {
......
......@@ -23,6 +23,22 @@
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
......@@ -44,12 +60,18 @@ namespace folly {
*
* 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:
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.
......@@ -61,7 +83,7 @@ class BucketedTimeSeries {
* 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'
......
......@@ -21,30 +21,28 @@
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) {
......@@ -54,7 +52,7 @@ MultiLevelTimeSeries<VT, TT>::MultiLevelTimeSeries(
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);
......@@ -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);
}
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);
}
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;
......@@ -91,16 +91,16 @@ void MultiLevelTimeSeries<VT, TT>::addValueAggregated(TimeType now,
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);
}
}
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) {
......@@ -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();
}
......
......@@ -49,12 +49,18 @@ namespace folly {
*
* 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:
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.
......
......@@ -23,34 +23,37 @@
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);
}
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);
}
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());
......@@ -68,9 +71,9 @@ void TimeseriesHistogram<T, TT, C>::addValues(
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;
......@@ -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_;
}
......@@ -93,10 +96,11 @@ T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
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_;
}
......@@ -106,38 +110,37 @@ T TimeseriesHistogram<T, TT, C>::getPercentileEstimate(double pct,
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));
}
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));
}
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();
}
}
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);
}
}
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++) {
......@@ -153,9 +156,10 @@ std::string TimeseriesHistogram<T, TT, C>::getString(int level) const {
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++) {
......@@ -171,8 +175,8 @@ std::string TimeseriesHistogram<T, TT, C>::getString(TimeType start,
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 {
......@@ -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,
......@@ -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 {
......@@ -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,
......
......@@ -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).
*/
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:
// 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.
......
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