| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you 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 <cstdint> |
| |
| #include <gtest/gtest.h> |
| |
| #include "kudu/util/hdr_histogram.h" |
| #include "kudu/util/test_util.h" |
| #include "kudu/util/test_macros.h" |
| |
| namespace kudu { |
| |
| static const int kSigDigits = 2; |
| |
| class HdrHistogramTest : public KuduTest { |
| }; |
| |
| TEST_F(HdrHistogramTest, SimpleTest) { |
| uint64_t highest_val = 10000LU; |
| |
| HdrHistogram hist(highest_val, kSigDigits); |
| ASSERT_EQ(0, hist.CountInBucketForValue(1)); |
| hist.Increment(1); |
| ASSERT_EQ(1, hist.CountInBucketForValue(1)); |
| hist.IncrementBy(1, 3); |
| ASSERT_EQ(4, hist.CountInBucketForValue(1)); |
| hist.Increment(10); |
| ASSERT_EQ(1, hist.CountInBucketForValue(10)); |
| hist.Increment(20); |
| ASSERT_EQ(1, hist.CountInBucketForValue(20)); |
| ASSERT_EQ(0, hist.CountInBucketForValue(1000)); |
| hist.Increment(1000); |
| hist.Increment(1001); |
| ASSERT_EQ(2, hist.CountInBucketForValue(1000)); |
| |
| ASSERT_EQ(1 + 1 * 3 + 10 + 20 + 1000 + 1001, |
| hist.TotalSum()); |
| } |
| |
| TEST_F(HdrHistogramTest, TestCoordinatedOmission) { |
| uint64_t interval = 1000; |
| int loop_iters = 100; |
| int64_t normal_value = 10; |
| HdrHistogram hist(1000000LU, kSigDigits); |
| for (int i = 1; i <= loop_iters; i++) { |
| // Simulate a periodic "large value" that would exhibit coordinated |
| // omission were this loop to sleep on 'interval'. |
| int64_t value = (i % normal_value == 0) ? interval * 10 : normal_value; |
| |
| hist.IncrementWithExpectedInterval(value, interval); |
| } |
| ASSERT_EQ(loop_iters - (loop_iters / normal_value), |
| hist.CountInBucketForValue(normal_value)); |
| for (int i = interval; i <= interval * 10; i += interval) { |
| ASSERT_EQ(loop_iters / normal_value, hist.CountInBucketForValue(i)); |
| } |
| } |
| |
| static const int kExpectedSum = |
| 10 * 80 + 100 * 10 + 1000 * 5 + 10000 * 3 + 100000 * 1 + 1000000 * 1; |
| static const int kExpectedMax = 1000000; |
| static const int kExpectedCount = 100; |
| static const int kExpectedMin = 10; |
| static void load_percentiles(HdrHistogram* hist) { |
| hist->IncrementBy(10, 80); |
| hist->IncrementBy(100, 10); |
| hist->IncrementBy(1000, 5); |
| hist->IncrementBy(10000, 3); |
| hist->IncrementBy(100000, 1); |
| hist->IncrementBy(1000000, 1); |
| } |
| |
| static void validate_percentiles(HdrHistogram* hist, uint64_t specified_max) { |
| double expected_mean = |
| static_cast<double>(kExpectedSum) / (80 + 10 + 5 + 3 + 1 + 1); |
| |
| ASSERT_EQ(kExpectedMin, hist->MinValue()); |
| ASSERT_EQ(kExpectedMax, hist->MaxValue()); |
| ASSERT_EQ(kExpectedSum, hist->TotalSum()); |
| ASSERT_NEAR(expected_mean, hist->MeanValue(), 0.001); |
| ASSERT_EQ(kExpectedCount, hist->TotalCount()); |
| ASSERT_EQ(10, hist->ValueAtPercentile(80)); |
| ASSERT_EQ(kExpectedCount, hist->ValueAtPercentile(90)); |
| ASSERT_EQ(hist->LowestEquivalentValue(specified_max), hist->ValueAtPercentile(99)); |
| ASSERT_EQ(hist->LowestEquivalentValue(specified_max), hist->ValueAtPercentile(99.99)); |
| ASSERT_EQ(hist->LowestEquivalentValue(specified_max), hist->ValueAtPercentile(100)); |
| } |
| |
| TEST_F(HdrHistogramTest, PercentileAndCopyTest) { |
| uint64_t specified_max = 10000; |
| HdrHistogram hist(specified_max, kSigDigits); |
| load_percentiles(&hist); |
| NO_FATALS(validate_percentiles(&hist, specified_max)); |
| |
| HdrHistogram copy(hist); |
| NO_FATALS(validate_percentiles(©, specified_max)); |
| |
| ASSERT_EQ(hist.TotalSum(), copy.TotalSum()); |
| } |
| |
| void PopulateHistogram(HdrHistogram* histogram, uint64_t low, uint64_t high) { |
| for (uint64_t i = low; i <= high; i++) { |
| histogram->Increment(i); |
| } |
| } |
| |
| TEST_F(HdrHistogramTest, MergeTest) { |
| uint64_t highest_val = 10000LU; |
| |
| HdrHistogram hist(highest_val, kSigDigits); |
| HdrHistogram other(highest_val, kSigDigits); |
| |
| PopulateHistogram(&hist, 1, 100); |
| PopulateHistogram(&other, 101, 250); |
| HdrHistogram old(hist); |
| hist.MergeFrom(other); |
| |
| ASSERT_EQ(hist.TotalCount(), old.TotalCount() + other.TotalCount()); |
| ASSERT_EQ(hist.TotalSum(), old.TotalSum() + other.TotalSum()); |
| ASSERT_EQ(hist.MinValue(), 1); |
| ASSERT_EQ(hist.MaxValue(), 250); |
| ASSERT_NEAR(hist.MeanValue(), (1 + 250) / 2.0, 1e3); |
| ASSERT_EQ(hist.ValueAtPercentile(100.0), 250); |
| ASSERT_NEAR(hist.ValueAtPercentile(99.0), 250 * 99.0 / 100, 1e3); |
| ASSERT_NEAR(hist.ValueAtPercentile(95.0), 250 * 95.0 / 100, 1e3); |
| ASSERT_NEAR(hist.ValueAtPercentile(50.0), 250 * 50.0 / 100, 1e3); |
| } |
| |
| } // namespace kudu |