X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Ftest%2FTimeseriesTest.cpp;h=c052b7067919be42bfd7949dbdd16914f462fb4e;hp=84b64b1412525efa3e45ab284db2044894a4cfea;hb=14223eae3f3cc0059f2d129ceec84b48506a6434;hpb=4f802227dd2f0faf82006dca10189e4af25699fa diff --git a/folly/test/TimeseriesTest.cpp b/folly/test/TimeseriesTest.cpp index 84b64b14..c052b706 100644 --- a/folly/test/TimeseriesTest.cpp +++ b/folly/test/TimeseriesTest.cpp @@ -19,6 +19,8 @@ #include #include +#include "folly/Foreach.h" + using std::chrono::seconds; using std::string; using std::vector; @@ -319,6 +321,116 @@ TEST(BucketedTimeSeries, rate) { EXPECT_NEAR(1.5, ts.countRate(), 0.005); } +TEST(BucketedTimeSeries, avgTypeConversion) { + // The average code has many different code paths to decide what type of + // division to perform (floating point, signed integer, unsigned integer). + // Test the various code paths. + + { + // Simple sanity tests for small positive integer values + BucketedTimeSeries ts(60, seconds(600)); + ts.addValue(seconds(0), 4, 100); + ts.addValue(seconds(0), 10, 200); + ts.addValue(seconds(0), 16, 100); + + EXPECT_DOUBLE_EQ(ts.avg(), 10.0); + EXPECT_DOUBLE_EQ(ts.avg(), 10.0); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + } + + { + // Test signed integer types with negative values + BucketedTimeSeries ts(60, seconds(600)); + ts.addValue(seconds(0), -100); + ts.addValue(seconds(0), -200); + ts.addValue(seconds(0), -300); + ts.addValue(seconds(0), -200, 65535); + + EXPECT_DOUBLE_EQ(ts.avg(), -200.0); + EXPECT_DOUBLE_EQ(ts.avg(), -200.0); + EXPECT_EQ(ts.avg(), -200); + EXPECT_EQ(ts.avg(), -200); + EXPECT_EQ(ts.avg(), -200); + } + + { + // Test uint64_t values that would overflow int64_t + BucketedTimeSeries ts(60, seconds(600)); + ts.addValueAggregated(seconds(0), + std::numeric_limits::max(), + std::numeric_limits::max()); + + EXPECT_DOUBLE_EQ(ts.avg(), 1.0); + EXPECT_DOUBLE_EQ(ts.avg(), 1.0); + EXPECT_EQ(ts.avg(), 1); + EXPECT_EQ(ts.avg(), 1); + EXPECT_EQ(ts.avg(), 1); + } + + { + // Test doubles with small-ish values that will fit in integer types + BucketedTimeSeries ts(60, seconds(600)); + ts.addValue(seconds(0), 4.0, 100); + ts.addValue(seconds(0), 10.0, 200); + ts.addValue(seconds(0), 16.0, 100); + + EXPECT_DOUBLE_EQ(ts.avg(), 10.0); + EXPECT_DOUBLE_EQ(ts.avg(), 10.0); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + EXPECT_EQ(ts.avg(), 10); + } + + { + // Test doubles with huge values + BucketedTimeSeries ts(60, seconds(600)); + ts.addValue(seconds(0), 1e19, 100); + ts.addValue(seconds(0), 2e19, 200); + ts.addValue(seconds(0), 3e19, 100); + + EXPECT_DOUBLE_EQ(ts.avg(), 2e19); + EXPECT_NEAR(ts.avg(), 2e19, 1e11); + } + + { + // Test doubles where the sum adds up larger than a uint64_t, + // but the average fits in an int64_t + BucketedTimeSeries ts(60, seconds(600)); + uint64_t value = 0x3fffffffffffffff; + FOR_EACH_RANGE(i, 0, 16) { + ts.addValue(seconds(0), value); + } + + EXPECT_DOUBLE_EQ(ts.avg(), value); + EXPECT_DOUBLE_EQ(ts.avg(), value); + EXPECT_DOUBLE_EQ(ts.avg(), value); + EXPECT_DOUBLE_EQ(ts.avg(), value); + } + + { + // Test BucketedTimeSeries with a smaller integer type + BucketedTimeSeries ts(60, seconds(600)); + FOR_EACH_RANGE(i, 0, 101) { + ts.addValue(seconds(0), i); + } + + EXPECT_DOUBLE_EQ(ts.avg(), 50.0); + EXPECT_DOUBLE_EQ(ts.avg(), 50.0); + EXPECT_DOUBLE_EQ(ts.avg(), 50); + EXPECT_DOUBLE_EQ(ts.avg(), 50); + EXPECT_DOUBLE_EQ(ts.avg(), 50); + EXPECT_DOUBLE_EQ(ts.avg(), 50); + } +} + TEST(BucketedTimeSeries, forEachBucket) { typedef BucketedTimeSeries::Bucket Bucket; struct BucketInfo {