Commit 4a7f5a25 authored by Adam Simpkins's avatar Adam Simpkins Committed by Tudor Bosman

Add BucketedTimeSeries to folly

Summary:
Add the BucketedTimeSeries class to folly.  This tracks time series
counter data, using a circular buffer of buckets to expire old data
points as time progresses.

It supports querying the overall sum, count, average, and rate for the
duration of the time series, as well as estimating these values for
portions of the overall duration.

Test Plan: Unit tests included.

Reviewed By: andrei.alexandrescu@fb.com

FB internal diff: D527040
parent 5df0c971
......@@ -295,12 +295,38 @@ void doNotOptimizeAway(T&& datum) {
* 1000000 for initialSize, and the iteration count for n.
*/
#define BENCHMARK_PARAM(name, param) \
BENCHMARK_NAMED_PARAM(name, param, param)
/*
* Like BENCHMARK_PARAM(), but allows a custom name to be specified for each
* parameter, rather than using the parameter value.
*
* Useful when the parameter value is not a valid token for string pasting,
* of when you want to specify multiple parameter arguments.
*
* For example:
*
* void addValue(uint n, int64_t bucketSize, int64_t min, int64_t max) {
* Histogram<int64_t> hist(bucketSize, min, max);
* int64_t num = min;
* FOR_EACH_RANGE (i, 0, n) {
* hist.addValue(num);
* ++num;
* if (num > max) { num = min; }
* }
* }
*
* BENCHMARK_NAMED_PARAM(addValue, 0_to_100, 1, 0, 100)
* BENCHMARK_NAMED_PARAM(addValue, 0_to_1000, 10, 0, 1000)
* BENCHMARK_NAMED_PARAM(addValue, 5k_to_20k, 250, 5000, 20000)
*/
#define BENCHMARK_NAMED_PARAM(name, param_name, ...) \
BENCHMARK_IMPL( \
FB_CONCATENATE(name, FB_CONCATENATE(_, param)), \
FB_STRINGIZE(name) "(" FB_STRINGIZE(param) ")", \
FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \
FB_STRINGIZE(name) "(" FB_STRINGIZE(param_name) ")", \
unsigned, \
iters) { \
name(iters, param); \
name(iters, ## __VA_ARGS__); \
}
/**
......@@ -338,12 +364,18 @@ void doNotOptimizeAway(T&& datum) {
* A combination of BENCHMARK_RELATIVE and BENCHMARK_PARAM.
*/
#define BENCHMARK_RELATIVE_PARAM(name, param) \
BENCHMARK_RELATIVE_NAMED_PARAM(name, param, param)
/**
* A combination of BENCHMARK_RELATIVE and BENCHMARK_NAMED_PARAM.
*/
#define BENCHMARK_RELATIVE_NAMED_PARAM(name, param_name, ...) \
BENCHMARK_IMPL( \
FB_CONCATENATE(name, FB_CONCATENATE(_, param)), \
"%" FB_STRINGIZE(name) "(" FB_STRINGIZE(param) ")", \
FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \
"%" FB_STRINGIZE(name) "(" FB_STRINGIZE(param_name) ")", \
unsigned, \
iters) { \
name(iters, param); \
name(iters, ## __VA_ARGS__); \
}
/**
......
......@@ -18,12 +18,13 @@
#define FOLLY_HISTOGRAM_H_
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
#include <vector>
#include <stdexcept>
#include "folly/detail/Stats.h"
namespace folly {
namespace detail {
......@@ -223,36 +224,7 @@ template <typename T>
class Histogram {
public:
typedef T ValueType;
struct Bucket {
Bucket()
: sum(0),
count(0) {}
void clear() {
sum = 0;
count = 0;
}
Bucket& merge(const Bucket &bucket) {
if (this != &bucket) {
sum += bucket.sum;
count += bucket.count;
}
return *this;
}
Bucket& operator=(const Bucket& bucket) {
if (this != &bucket) {
sum = bucket.sum;
count = bucket.count;
}
return *this;
}
ValueType sum;
uint64_t count;
};
typedef detail::Bucket<T> Bucket;
Histogram(ValueType bucketSize, ValueType min, ValueType max)
: buckets_(bucketSize, min, max, Bucket()) {}
......@@ -298,7 +270,7 @@ class Histogram {
}
for (int i = 0; i < buckets_.getNumBuckets(); i++) {
buckets_.getByIndex(i).merge(hist.buckets_.getByIndex(i));
buckets_.getByIndex(i) += hist.buckets_.getByIndex(i);
}
}
......
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_DETAIL_STATS_H_
#define FOLLY_DETAIL_STATS_H_
#include <cstdint>
namespace folly { namespace detail {
template<typename T>
struct Bucket {
public:
typedef T ValueType;
Bucket()
: sum(ValueType()),
count(0) {}
void clear() {
sum = ValueType();
count = 0;
}
void add(const ValueType& s, uint64_t c) {
// TODO: It would be nice to handle overflow here.
sum += s;
count += c;
}
Bucket& operator+=(const Bucket& o) {
add(o.sum, o.count);
return *this;
}
Bucket& operator-=(const Bucket& o) {
// TODO: It would be nice to handle overflow here.
sum -= o.sum;
count -= o.count;
return *this;
}
template <typename ReturnType>
ReturnType avg() const {
return (count ?
static_cast<ReturnType>(sum) / count :
ReturnType(0));
}
ValueType sum;
uint64_t count;
};
}} // folly::detail
#endif // FOLLY_DETAIL_STATS_H_
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "folly/stats/BucketedTimeSeries.h"
#include "folly/stats/BucketedTimeSeries-defs.h"
#include <glog/logging.h>
#include "folly/Benchmark.h"
using std::chrono::seconds;
using folly::BenchmarkSuspender;
using folly::BucketedTimeSeries;
void addValue(unsigned int iters,
seconds duration, size_t numBuckets,
size_t callsPerSecond) {
BenchmarkSuspender suspend;
BucketedTimeSeries<int64_t> ts(numBuckets, duration);
suspend.dismiss();
seconds currentTime(1342000000);
size_t timeCounter = 0;
for (unsigned int n = 0; n < iters; ++n, ++timeCounter) {
if (timeCounter >= callsPerSecond) {
timeCounter = 0;
++currentTime;
}
ts.addValue(currentTime, n);
}
}
BENCHMARK_NAMED_PARAM(addValue, AllTime_1perSec, seconds(0), 60, 1);
BENCHMARK_NAMED_PARAM(addValue, 3600x60_1perSec, seconds(3600), 60, 1);
BENCHMARK_NAMED_PARAM(addValue, 600x60_1perSec, seconds(600), 60, 1);
BENCHMARK_NAMED_PARAM(addValue, 60x60_1perSec, seconds(60), 60, 1);
BENCHMARK_NAMED_PARAM(addValue, 100x10_1perSec, seconds(100), 10, 1);
BENCHMARK_NAMED_PARAM(addValue, 71x5_1perSec, seconds(71), 5, 1);
BENCHMARK_NAMED_PARAM(addValue, 1x1_1perSec, seconds(1), 1, 1);
BENCHMARK_DRAW_LINE()
BENCHMARK_NAMED_PARAM(addValue, AllTime_10perSec, seconds(0), 60, 10);
BENCHMARK_NAMED_PARAM(addValue, 3600x60_10perSec, seconds(3600), 60, 10);
BENCHMARK_NAMED_PARAM(addValue, 600x60_10perSec, seconds(600), 60, 10);
BENCHMARK_NAMED_PARAM(addValue, 60x60_10perSec, seconds(60), 60, 10);
BENCHMARK_NAMED_PARAM(addValue, 100x10_10perSec, seconds(100), 10, 10);
BENCHMARK_NAMED_PARAM(addValue, 71x5_10perSec, seconds(71), 5, 10);
BENCHMARK_NAMED_PARAM(addValue, 1x1_10perSec, seconds(1), 1, 10);
BENCHMARK_DRAW_LINE()
BENCHMARK_NAMED_PARAM(addValue, AllTime_100perSec, seconds(0), 60, 100);
BENCHMARK_NAMED_PARAM(addValue, 3600x60_100perSec, seconds(3600), 60, 100);
BENCHMARK_NAMED_PARAM(addValue, 600x60_100perSec, seconds(600), 60, 100);
BENCHMARK_NAMED_PARAM(addValue, 60x60_100perSec, seconds(60), 60, 100);
BENCHMARK_NAMED_PARAM(addValue, 100x10_100perSec, seconds(100), 10, 100);
BENCHMARK_NAMED_PARAM(addValue, 71x5_100perSec, seconds(71), 5, 100);
BENCHMARK_NAMED_PARAM(addValue, 1x1_100perSec, seconds(1), 1, 100);
int main(int argc, char *argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
}
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