25 #include <glog/logging.h> 33 using std::chrono::seconds;
44 std::ostream& operator<<(std::ostream& os, std::chrono::seconds
s) {
49 os << tp.time_since_epoch().count();
60 TestData(
int d,
int b, std::initializer_list<int> starts)
61 : duration(d), numBuckets(b) {
62 bucketStarts.reserve(starts.size());
63 for (
int s : starts) {
64 bucketStarts.push_back(mkTimePoint(
s));
69 vector<TimePoint> bucketStarts;
71 vector<TestData> testData = {
73 {71, 4, {0, 18, 36, 54}},
75 {100, 10, {0, 10, 20, 30, 40, 50, 60, 70, 80, 90}},
77 {10, 10, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
86 for (
const auto&
data : testData) {
89 for (
uint32_t n = 0; n < 10000; n += 1234) {
90 seconds offset(n *
data.duration);
93 auto bucketStart =
data.bucketStarts[idx];
95 if (idx + 1 <
data.numBuckets) {
96 nextBucketStart =
data.bucketStarts[idx + 1];
101 TimePoint expectedStart = offset + bucketStart;
102 TimePoint expectedNextStart = offset + nextBucketStart;
104 expectedStart + (expectedNextStart - expectedStart) / 2;
106 vector<std::pair<string, TimePoint>> timePoints = {
107 {
"expectedStart", expectedStart},
108 {
"midpoint", midpoint},
109 {
"expectedEnd", expectedNextStart - seconds(1)},
112 for (
const auto& point : timePoints) {
115 <<
data.duration <<
"x" <<
data.numBuckets <<
": " << point.first
116 <<
"=" << point.second;
123 expectedStart, &returnedIdx, &returnedStart, &returnedNextStart);
125 <<
data.duration <<
"x" <<
data.numBuckets <<
": " << point.first
126 <<
"=" << point.second;
128 <<
data.duration <<
"x" <<
data.numBuckets <<
": " << point.first
129 <<
"=" << point.second;
130 EXPECT_EQ(expectedNextStart, returnedNextStart)
131 <<
data.duration <<
"x" <<
data.numBuckets <<
": " << point.first
132 <<
"=" << point.second;
141 CHECK_EQ(0, offset % 10);
149 for (
int n = 5; n <= 95; n += 10) {
150 ts.
addValue(seconds(n + offset), 6);
160 ts.
update(seconds(110 + offset));
168 ts.
update(seconds(151 + offset));
177 ts.
update(seconds(193 + offset));
186 ts.
update(seconds(197 + offset));
195 ts.
update(seconds(230 + offset));
277 seconds
start(239218);
278 ts.
addValue(start + seconds(0), 200);
282 ts.
addValue(start + seconds(10), 200);
334 for (
size_t n = 0; n < 600; n += 2) {
390 ts.
addValue(seconds(0), -200, 65535);
475 long double expected = 1000.0L / 7.0L;
489 long double expected = 1000.0L / 7.0L;
502 : bucket(b),
start(s), nextStart(ns) {}
504 const BucketSeries* bucket;
509 for (
const auto&
data : testData) {
512 vector<BucketInfo>
info;
513 auto fn = [&](
const BucketSeries& bucket,
516 info.emplace_back(&bucket, bucketStart, bucketEnd);
524 CHECK_EQ(
data.numBuckets, info.size());
528 size_t bucketIdx = 1;
529 seconds offset = -
data.duration;
530 for (
size_t n = 0; n <
data.numBuckets; ++n) {
531 if (bucketIdx >=
data.numBuckets) {
533 offset +=
data.duration;
536 EXPECT_EQ(
data.bucketStarts[bucketIdx] + offset, info[infoIdx].start)
537 <<
data.duration <<
"x" <<
data.numBuckets
538 <<
": bucketIdx=" << bucketIdx <<
", infoIdx=" << infoIdx;
540 size_t nextBucketIdx = bucketIdx + 1;
541 seconds nextOffset = offset;
542 if (nextBucketIdx >=
data.numBuckets) {
544 nextOffset +=
data.duration;
547 data.bucketStarts[nextBucketIdx] + nextOffset,
548 info[infoIdx].nextStart)
549 <<
data.duration <<
"x" <<
data.numBuckets
550 <<
": bucketIdx=" << bucketIdx <<
", infoIdx=" << infoIdx;
562 for (
int i = 0;
i < 8;
i++) {
575 const int kNumBuckets = 3;
576 const int kDuration = 6;
579 for (
unsigned int i = 0;
i < kDuration; ++
i) {
589 double expectedSums1[kDuration + 1][kDuration + 1] = {
590 {0, 4.5, 9, 11.5, 14, 14.5, 15},
591 {0, 4.5, 7, 9.5, 10, 10.5, -1},
592 {0, 2.5, 5, 5.5, 6, -1, -1},
593 {0, 2.5, 3, 3.5, -1, -1, -1},
594 {0, 0.5, 1, -1, -1, -1, -1},
595 {0, 0.5, -1, -1, -1, -1, -1},
596 {0, -1, -1, -1, -1, -1, -1},
598 int expectedCounts1[kDuration + 1][kDuration + 1] = {
599 {0, 1, 2, 3, 4, 5, 6},
600 {0, 1, 2, 3, 4, 5, -1},
601 {0, 1, 2, 3, 4, -1, -1},
602 {0, 1, 2, 3, -1, -1, -1},
603 {0, 1, 2, -1, -1, -1, -1},
604 {0, 1, -1, -1, -1, -1, -1},
605 {0, -1, -1, -1, -1, -1, -1},
610 for (
int i = 0;
i <= kDuration + 1;
i++) {
611 for (
int j = 0; j <= kDuration -
i; j++) {
614 double expectedSum = expectedSums1[
i][j];
616 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
619 uint64_t expectedCount = expectedCounts1[
i][j];
621 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
624 double expectedAvg = expectedCount ? expectedSum / expectedCount : 0;
626 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
629 double expectedRate = j ? expectedSum / j : 0;
631 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
638 for (
unsigned int i = kDuration;
i < kDuration + 3; ++
i) {
648 double expectedSums2[kDuration + 1][kDuration + 1] = {
649 {0, 8, 14.5, 21, 25.5, 30, 30},
650 {0, 6.5, 13, 17.5, 22, 22, -1},
651 {0, 6.5, 11, 15.5, 15.5, -1, -1},
652 {0, 4.5, 9, 9, -1, -1, -1},
653 {0, 4.5, 4.5, -1, -1, -1, -1},
654 {0, 0, -1, -1, -1, -1, -1},
655 {0, -1, -1, -1, -1, -1, -1},
657 int expectedCounts2[kDuration + 1][kDuration + 1] = {
658 {0, 1, 2, 3, 4, 5, 5},
659 {0, 1, 2, 3, 4, 4, -1},
660 {0, 1, 2, 3, 3, -1, -1},
661 {0, 1, 2, 2, -1, -1, -1},
662 {0, 1, 1, -1, -1, -1, -1},
663 {0, 0, -1, -1, -1, -1, -1},
664 {0, -1, -1, -1, -1, -1, -1},
669 for (
int i = 0;
i <= kDuration + 1;
i++) {
670 for (
int j = 0; j <= kDuration -
i; j++) {
673 double expectedSum = expectedSums2[
i][j];
675 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
678 uint64_t expectedCount = expectedCounts2[
i][j];
680 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
683 double expectedAvg = expectedCount ? expectedSum / expectedCount : 0;
685 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
690 seconds expectedInterval = dataEnd - dataStart;
692 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
695 double expectedRate =
696 expectedInterval.count() ? expectedSum / expectedInterval.count() : 0;
698 <<
"i=" << i <<
", j=" << j <<
", interval=[" << start <<
", " << end
705 const int kNumBuckets = 5;
706 const seconds kDuration(10);
714 const double kFixedRate = 10.0;
756 const int kNumBuckets = 5;
757 const seconds kDuration(10);
761 for (
TimePoint i = mkTimePoint(0);
i < mkTimePoint(10);
i += seconds(1)) {
778 for (
TimePoint i = mkTimePoint(10);
i < mkTimePoint(14);
i += seconds(1)) {
802 auto verify = [](
auto timeSeries) {
831 for (
int n = 5; n <= 95; n += 10) {
858 for (
auto it1 = ts.
buckets().begin(), it2 = newTs.
buckets().begin();
873 std::vector<Bucket> buckets(10);
875 buckets[0].count = 1;
878 mkTimePoint(1), mkTimePoint(0),
Duration(10), buckets);
880 std::invalid_argument);
888 std::vector<Bucket>(10)),
889 std::invalid_argument);
903 TEST(MinuteHourTimeSeries, Basic) {
934 for (
int i = 0;
i < 299; ++
i) {
955 for (
int i = 0;
i < 3600 * 3 - 300; ++
i) {
976 for (
int i = 0;
i < 3600; ++
i) {
995 for (
int i = 0;
i < 1800; ++
i) {
1005 for (
int i = 0;
i < 60; ++
i) {
1014 3600 * 3 * 10 + 3600 * 100 + 1800 * 120 + 60 * 1000);
1020 TEST(MinuteHourTimeSeries, QueryByInterval) {
1025 for (curTime = mkTimePoint(0); curTime < mkTimePoint(7200);
1026 curTime += seconds(1)) {
1029 for (curTime = mkTimePoint(7200); curTime < mkTimePoint(7200 + 3540);
1030 curTime += seconds(1)) {
1033 for (curTime = mkTimePoint(7200 + 3540); curTime < mkTimePoint(7200 + 3600);
1034 curTime += seconds(1)) {
1039 struct TimeInterval {
1043 TimeInterval intervals[12] = {
1044 {curTime - seconds(60), curTime},
1045 {curTime - seconds(3600), curTime},
1046 {curTime - seconds(7200), curTime},
1047 {curTime - seconds(3600), curTime - seconds(60)},
1048 {curTime - seconds(7200), curTime - seconds(60)},
1049 {curTime - seconds(7200), curTime - seconds(3600)},
1050 {curTime - seconds(50), curTime - seconds(20)},
1051 {curTime - seconds(3020), curTime - seconds(20)},
1052 {curTime - seconds(7200), curTime - seconds(20)},
1053 {curTime - seconds(3000), curTime - seconds(1000)},
1054 {curTime - seconds(7200), curTime - seconds(1000)},
1055 {curTime - seconds(7200), curTime - seconds(3600)},
1058 int expectedSums[12] = {
1073 int expectedCounts[12] = {
1088 for (
int i = 0;
i < 12; ++
i) {
1089 TimeInterval interval = intervals[
i];
1091 int s = mhts.
sum(interval.start, interval.end);
1094 int c = mhts.
count(interval.start, interval.end);
1097 int a = mhts.
avg<
int>(interval.start, interval.end);
1098 EXPECT_EQ(expectedCounts[i] ? (expectedSums[i] / expectedCounts[i]) : 0, a);
1100 int r = mhts.
rate<
int>(interval.start, interval.end);
1102 expectedSums[
i] / (interval.end - interval.start).
count();
1107 TEST(MultiLevelTimeSeries, Basic) {
1110 60, {seconds(60), seconds(3600), seconds(0)});
1125 EXPECT_EQ(mhts.getLevelByDuration(seconds(60)).elapsed().count(), 0);
1126 EXPECT_EQ(mhts.getLevelByDuration(seconds(3600)).elapsed().count(), 0);
1127 EXPECT_EQ(mhts.getLevelByDuration(seconds(0)).elapsed().count(), 0);
1129 seconds cur_time(0);
1131 mhts.addValue(cur_time++, 10);
1134 EXPECT_EQ(mhts.getLevelByDuration(seconds(60)).elapsed().count(), 1);
1135 EXPECT_EQ(mhts.getLevelByDuration(seconds(3600)).elapsed().count(), 1);
1136 EXPECT_EQ(mhts.getLevelByDuration(seconds(0)).elapsed().count(), 1);
1138 for (
int i = 0;
i < 299; ++
i) {
1139 mhts.addValue(cur_time++, 10);
1143 EXPECT_EQ(mhts.getLevelByDuration(seconds(60)).elapsed().count(), 60);
1144 EXPECT_EQ(mhts.getLevelByDuration(seconds(3600)).elapsed().count(), 300);
1145 EXPECT_EQ(mhts.getLevelByDuration(seconds(0)).elapsed().count(), 300);
1148 EXPECT_EQ(mhts.sum(seconds(3600)), 300 * 10);
1149 EXPECT_EQ(mhts.sum(seconds(0)), 300 * 10);
1156 EXPECT_EQ(mhts.rate(seconds(3600)), 10);
1159 for (
int i = 0;
i < 3600 * 3 - 300; ++
i) {
1160 mhts.addValue(cur_time++, 10);
1164 EXPECT_EQ(mhts.getLevelByDuration(seconds(60)).elapsed().count(), 60);
1165 EXPECT_EQ(mhts.getLevelByDuration(seconds(3600)).elapsed().count(), 3600);
1166 EXPECT_EQ(mhts.getLevelByDuration(seconds(0)).elapsed().count(), 3600 * 3);
1169 EXPECT_EQ(mhts.sum(seconds(3600)), 3600 * 10);
1170 EXPECT_EQ(mhts.sum(seconds(0)), 3600 * 3 * 10);
1177 EXPECT_EQ(mhts.rate(seconds(3600)), 10);
1180 for (
int i = 0;
i < 3600; ++
i) {
1181 mhts.addValue(cur_time++, 100);
1185 EXPECT_EQ(mhts.sum(seconds(60)), 60 * 100);
1186 EXPECT_EQ(mhts.sum(seconds(3600)), 3600 * 100);
1187 EXPECT_EQ(mhts.sum(seconds(0)), 3600 * 3 * 10 + 3600 * 100);
1190 EXPECT_EQ(mhts.avg(seconds(3600)), 100);
1192 EXPECT_EQ(mhts.avg<
int>(seconds(0)), 32);
1195 EXPECT_EQ(mhts.rate(seconds(3600)), 100);
1197 EXPECT_EQ(mhts.rate<
int>(seconds(0)), 32);
1199 for (
int i = 0;
i < 1800; ++
i) {
1200 mhts.addValue(cur_time++, 120);
1204 EXPECT_EQ(mhts.sum(seconds(60)), 60 * 120);
1205 EXPECT_EQ(mhts.sum(seconds(3600)), 1800 * 100 + 1800 * 120);
1206 EXPECT_EQ(mhts.sum(seconds(0)), 3600 * 3 * 10 + 3600 * 100 + 1800 * 120);
1208 for (
int i = 0;
i < 60; ++
i) {
1209 mhts.addValue(cur_time++, 1000);
1213 EXPECT_EQ(mhts.sum(seconds(60)), 60 * 1000);
1214 EXPECT_EQ(mhts.sum(seconds(3600)), 1740 * 100 + 1800 * 120 + 60 * 1000);
1216 mhts.sum(seconds(0)),
1217 3600 * 3 * 10 + 3600 * 100 + 1800 * 120 + 60 * 1000);
1223 TEST(MultiLevelTimeSeries, QueryByInterval) {
1225 60, {seconds(60), seconds(3600), seconds(0)});
1228 for (curTime = mkTimePoint(0); curTime < mkTimePoint(7200);
1229 curTime += seconds(1)) {
1232 for (curTime = mkTimePoint(7200); curTime < mkTimePoint(7200 + 3540);
1233 curTime += seconds(1)) {
1234 mhts.addValue(curTime, 10);
1236 for (curTime = mkTimePoint(7200 + 3540); curTime < mkTimePoint(7200 + 3600);
1237 curTime += seconds(1)) {
1238 mhts.addValue(curTime, 100);
1242 struct TimeInterval {
1247 std::array<TimeInterval, 12> intervals = {{
1248 {curTime - seconds(60), curTime},
1249 {curTime - seconds(3600), curTime},
1250 {curTime - seconds(7200), curTime},
1251 {curTime - seconds(3600), curTime - seconds(60)},
1252 {curTime - seconds(7200), curTime - seconds(60)},
1253 {curTime - seconds(7200), curTime - seconds(3600)},
1254 {curTime - seconds(50), curTime - seconds(20)},
1255 {curTime - seconds(3020), curTime - seconds(20)},
1256 {curTime - seconds(7200), curTime - seconds(20)},
1257 {curTime - seconds(3000), curTime - seconds(1000)},
1258 {curTime - seconds(7200), curTime - seconds(1000)},
1259 {curTime - seconds(7200), curTime - seconds(3600)},
1262 std::array<int, 12> expectedSums = {{6000,
1275 std::array<int, 12> expectedCounts = {
1276 {60, 3600, 7200, 3540, 7140, 3600, 30, 3000, 7180, 2000, 6200, 3600}};
1278 for (
size_t i = 0;
i < intervals.size(); ++
i) {
1279 TimeInterval interval = intervals[
i];
1281 int s = mhts.sum(interval.start, interval.end);
1284 int c = mhts.count(interval.start, interval.end);
1287 int a = mhts.avg<
int>(interval.start, interval.end);
1288 EXPECT_EQ(expectedCounts[i] ? (expectedSums[i] / expectedCounts[i]) : 0, a);
1290 int r = mhts.rate<
int>(interval.start, interval.end);
1292 expectedSums[
i] / (interval.end - interval.start).
count();
void testUpdate100x10(size_t offset)
#define EXPECT_THROW(statement, expected_exception)
const seconds kMinuteHourDurations[]
#define EXPECT_EQ(val1, val2)
Duration duration() const
const Bucket & getBucketByIndex(size_t idx) const
ReturnType countRate() const
TimePoint getLatestTime() const
ReturnType avg(size_t level) const
#define FOR_EACH_RANGE(i, begin, end)
bool addValueAggregated(TimePoint now, const ValueType &total, uint64_t nsamples)
TimePoint latestTime() const
ValueType sum(size_t level) const
void getBucketInfo(TimePoint time, size_t *bucketIdx, TimePoint *bucketStart, TimePoint *nextBucketStart) const
uint64_t count(size_t level) const
auto end(TestAdlIterable &instance)
const ValueType & sum() const
ReturnType rate(size_t level) const
const Level & getLevel(size_t level) const
static const char *const value
#define EXPECT_NEAR(val1, val2, abs_error)
#define EXPECT_TRUE(condition)
TimePoint firstTime() const
StatsClock::duration Duration
#define EXPECT_DOUBLE_EQ(val1, val2)
void addValue(TimePoint now, const ValueType &val)
bool addValue(TimePoint now, const ValueType &val)
size_t getBucketIdx(TimePoint time) const
size_t update(TimePoint now)
const std::vector< Bucket > & buckets() const
TEST(BucketedTimeSeries, getBucketInfo)
#define EXPECT_FALSE(condition)
TimePoint getEarliestTime() const
static constexpr uint64_t data[1]
StatsClock::time_point TimePoint
std::chrono::time_point< LegacyStatsClock, TT > time_point
void forEachBucket(Function fn) const