mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-25 22:44:05 +00:00
6924869867
Summary: Made SystemClock into a Customizable class, complete with CreateFromString. Cleaned up some of the existing SystemClock implementations that were redundant (NoSleep was the same as the internal one for MockEnv). Changed MockEnv construction to allow Clock to be passed to the Memory/MockFileSystem. Pull Request resolved: https://github.com/facebook/rocksdb/pull/8636 Reviewed By: zhichao-cao Differential Revision: D30483360 Pulled By: mrambacher fbshipit-source-id: cd0e3a876c39f8c98fe13374c06e8edbd5b9f2a1
234 lines
7.6 KiB
C++
234 lines
7.6 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
//
|
|
#include "monitoring/histogram.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include "monitoring/histogram_windowing.h"
|
|
#include "rocksdb/system_clock.h"
|
|
#include "test_util/mock_time_env.h"
|
|
#include "test_util/testharness.h"
|
|
#include "util/random.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
class HistogramTest : public testing::Test {};
|
|
|
|
namespace {
|
|
const double kIota = 0.1;
|
|
const HistogramBucketMapper bucketMapper;
|
|
std::shared_ptr<MockSystemClock> clock =
|
|
std::make_shared<MockSystemClock>(SystemClock::Default());
|
|
}
|
|
|
|
void PopulateHistogram(Histogram& histogram,
|
|
uint64_t low, uint64_t high, uint64_t loop = 1) {
|
|
Random rnd(test::RandomSeed());
|
|
for (; loop > 0; loop--) {
|
|
for (uint64_t i = low; i <= high; i++) {
|
|
histogram.Add(i);
|
|
// sleep a random microseconds [0-10)
|
|
clock->SleepForMicroseconds(rnd.Uniform(10));
|
|
}
|
|
}
|
|
// make sure each data population at least take some time
|
|
clock->SleepForMicroseconds(1);
|
|
}
|
|
|
|
void BasicOperation(Histogram& histogram) {
|
|
PopulateHistogram(histogram, 1, 110, 10); // fill up to bucket [70, 110)
|
|
|
|
HistogramData data;
|
|
histogram.Data(&data);
|
|
|
|
ASSERT_LE(fabs(histogram.Percentile(100.0) - 110.0), kIota);
|
|
ASSERT_LE(fabs(data.percentile99 - 108.9), kIota); // 99 * 110 / 100
|
|
ASSERT_LE(fabs(data.percentile95 - 104.5), kIota); // 95 * 110 / 100
|
|
ASSERT_LE(fabs(data.median - 55.0), kIota); // 50 * 110 / 100
|
|
ASSERT_EQ(data.average, 55.5); // (1 + 110) / 2
|
|
}
|
|
|
|
void MergeHistogram(Histogram& histogram, Histogram& other) {
|
|
PopulateHistogram(histogram, 1, 100);
|
|
PopulateHistogram(other, 101, 250);
|
|
histogram.Merge(other);
|
|
|
|
HistogramData data;
|
|
histogram.Data(&data);
|
|
|
|
ASSERT_LE(fabs(histogram.Percentile(100.0) - 250.0), kIota);
|
|
ASSERT_LE(fabs(data.percentile99 - 247.5), kIota); // 99 * 250 / 100
|
|
ASSERT_LE(fabs(data.percentile95 - 237.5), kIota); // 95 * 250 / 100
|
|
ASSERT_LE(fabs(data.median - 125.0), kIota); // 50 * 250 / 100
|
|
ASSERT_EQ(data.average, 125.5); // (1 + 250) / 2
|
|
}
|
|
|
|
void EmptyHistogram(Histogram& histogram) {
|
|
ASSERT_EQ(histogram.min(), bucketMapper.LastValue());
|
|
ASSERT_EQ(histogram.max(), 0);
|
|
ASSERT_EQ(histogram.num(), 0);
|
|
ASSERT_EQ(histogram.Median(), 0.0);
|
|
ASSERT_EQ(histogram.Percentile(85.0), 0.0);
|
|
ASSERT_EQ(histogram.Average(), 0.0);
|
|
ASSERT_EQ(histogram.StandardDeviation(), 0.0);
|
|
}
|
|
|
|
void ClearHistogram(Histogram& histogram) {
|
|
for (uint64_t i = 1; i <= 100; i++) {
|
|
histogram.Add(i);
|
|
}
|
|
histogram.Clear();
|
|
ASSERT_TRUE(histogram.Empty());
|
|
ASSERT_EQ(histogram.Median(), 0);
|
|
ASSERT_EQ(histogram.Percentile(85.0), 0);
|
|
ASSERT_EQ(histogram.Average(), 0);
|
|
}
|
|
|
|
TEST_F(HistogramTest, BasicOperation) {
|
|
HistogramImpl histogram;
|
|
BasicOperation(histogram);
|
|
|
|
HistogramWindowingImpl histogramWindowing;
|
|
BasicOperation(histogramWindowing);
|
|
}
|
|
|
|
TEST_F(HistogramTest, BoundaryValue) {
|
|
HistogramImpl histogram;
|
|
// - both should be in [0, 1] bucket because we place values on bucket
|
|
// boundaries in the lower bucket.
|
|
// - all points are in [0, 1] bucket, so p50 will be 0.5
|
|
// - the test cannot be written with a single point since histogram won't
|
|
// report percentiles lower than the min or greater than the max.
|
|
histogram.Add(0);
|
|
histogram.Add(1);
|
|
|
|
ASSERT_LE(fabs(histogram.Percentile(50.0) - 0.5), kIota);
|
|
}
|
|
|
|
TEST_F(HistogramTest, MergeHistogram) {
|
|
HistogramImpl histogram;
|
|
HistogramImpl other;
|
|
MergeHistogram(histogram, other);
|
|
|
|
HistogramWindowingImpl histogramWindowing;
|
|
HistogramWindowingImpl otherWindowing;
|
|
MergeHistogram(histogramWindowing, otherWindowing);
|
|
}
|
|
|
|
TEST_F(HistogramTest, EmptyHistogram) {
|
|
HistogramImpl histogram;
|
|
EmptyHistogram(histogram);
|
|
|
|
HistogramWindowingImpl histogramWindowing;
|
|
EmptyHistogram(histogramWindowing);
|
|
}
|
|
|
|
TEST_F(HistogramTest, ClearHistogram) {
|
|
HistogramImpl histogram;
|
|
ClearHistogram(histogram);
|
|
|
|
HistogramWindowingImpl histogramWindowing;
|
|
ClearHistogram(histogramWindowing);
|
|
}
|
|
|
|
TEST_F(HistogramTest, HistogramWindowingExpire) {
|
|
uint64_t num_windows = 3;
|
|
int micros_per_window = 1000000;
|
|
uint64_t min_num_per_window = 0;
|
|
|
|
HistogramWindowingImpl
|
|
histogramWindowing(num_windows, micros_per_window, min_num_per_window);
|
|
histogramWindowing.TEST_UpdateClock(clock);
|
|
PopulateHistogram(histogramWindowing, 1, 1, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 100);
|
|
ASSERT_EQ(histogramWindowing.min(), 1);
|
|
ASSERT_EQ(histogramWindowing.max(), 1);
|
|
ASSERT_EQ(histogramWindowing.Average(), 1);
|
|
|
|
PopulateHistogram(histogramWindowing, 2, 2, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 200);
|
|
ASSERT_EQ(histogramWindowing.min(), 1);
|
|
ASSERT_EQ(histogramWindowing.max(), 2);
|
|
ASSERT_EQ(histogramWindowing.Average(), 1.5);
|
|
|
|
PopulateHistogram(histogramWindowing, 3, 3, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 300);
|
|
ASSERT_EQ(histogramWindowing.min(), 1);
|
|
ASSERT_EQ(histogramWindowing.max(), 3);
|
|
ASSERT_EQ(histogramWindowing.Average(), 2.0);
|
|
|
|
// dropping oldest window with value 1, remaining 2 ~ 4
|
|
PopulateHistogram(histogramWindowing, 4, 4, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 300);
|
|
ASSERT_EQ(histogramWindowing.min(), 2);
|
|
ASSERT_EQ(histogramWindowing.max(), 4);
|
|
ASSERT_EQ(histogramWindowing.Average(), 3.0);
|
|
|
|
// dropping oldest window with value 2, remaining 3 ~ 5
|
|
PopulateHistogram(histogramWindowing, 5, 5, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 300);
|
|
ASSERT_EQ(histogramWindowing.min(), 3);
|
|
ASSERT_EQ(histogramWindowing.max(), 5);
|
|
ASSERT_EQ(histogramWindowing.Average(), 4.0);
|
|
}
|
|
|
|
TEST_F(HistogramTest, HistogramWindowingMerge) {
|
|
uint64_t num_windows = 3;
|
|
int micros_per_window = 1000000;
|
|
uint64_t min_num_per_window = 0;
|
|
|
|
HistogramWindowingImpl
|
|
histogramWindowing(num_windows, micros_per_window, min_num_per_window);
|
|
HistogramWindowingImpl
|
|
otherWindowing(num_windows, micros_per_window, min_num_per_window);
|
|
histogramWindowing.TEST_UpdateClock(clock);
|
|
otherWindowing.TEST_UpdateClock(clock);
|
|
|
|
PopulateHistogram(histogramWindowing, 1, 1, 100);
|
|
PopulateHistogram(otherWindowing, 1, 1, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
|
|
PopulateHistogram(histogramWindowing, 2, 2, 100);
|
|
PopulateHistogram(otherWindowing, 2, 2, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
|
|
PopulateHistogram(histogramWindowing, 3, 3, 100);
|
|
PopulateHistogram(otherWindowing, 3, 3, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
|
|
histogramWindowing.Merge(otherWindowing);
|
|
ASSERT_EQ(histogramWindowing.num(), 600);
|
|
ASSERT_EQ(histogramWindowing.min(), 1);
|
|
ASSERT_EQ(histogramWindowing.max(), 3);
|
|
ASSERT_EQ(histogramWindowing.Average(), 2.0);
|
|
|
|
// dropping oldest window with value 1, remaining 2 ~ 4
|
|
PopulateHistogram(histogramWindowing, 4, 4, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 500);
|
|
ASSERT_EQ(histogramWindowing.min(), 2);
|
|
ASSERT_EQ(histogramWindowing.max(), 4);
|
|
|
|
// dropping oldest window with value 2, remaining 3 ~ 5
|
|
PopulateHistogram(histogramWindowing, 5, 5, 100);
|
|
clock->SleepForMicroseconds(micros_per_window);
|
|
ASSERT_EQ(histogramWindowing.num(), 400);
|
|
ASSERT_EQ(histogramWindowing.min(), 3);
|
|
ASSERT_EQ(histogramWindowing.max(), 5);
|
|
}
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|