Skip to content

Commit

Permalink
MB-41510: Fix TSAN failure due to lock order inversion
Browse files Browse the repository at this point in the history
Fix TSAN failures in module_tests/hdrhistogram_test.cc, due to
theoretical deadlock that could occur when using two iterators that hold
read locks on different HdrHistograms (this isn't the case now bug could
be if the code was modified). To avoid this WARNING, ensure in our
HdrHistogramTests that we never hold multiple HdrHistogram::Iterators in
the same scope.

Example TSAN Failure:
  WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) (pid=16448)
  Cycle in lock order graph: M732257135894671160 (0x000000000000) => M730849761011117904 (0x000000000000) => M732257135894671160

  Mutex M730849761011117904 acquired here while holding mutex M732257135894671160 in main thread:
    #0 AnnotateRWLockAcquired <null> (ep-engine_ep_unit_tests+0x64007b)
    #1 folly::detail::annotate_rwlock_acquired_impl(void const volatile*, folly::annotate_rwlock_level, char const*, int) /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/synchronization/SanitizeThread.cpp:99 (ep-engine_ep_unit_tests+0x162f6be)
    #2 annotate_rwlock_acquired /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/synchronization/SanitizeThread.h:111 (ep-engine_ep_unit_tests+0x15a9881)
    #3 folly::SharedMutexImpl<false, void, std::atomic, false, true>::annotateAcquired(folly::annotate_rwlock_level) /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/SharedMutex.h:740 (ep-engine_ep_unit_tests+0x15a9881)
    #4 folly::SharedMutexImpl<false, void, std::atomic, false, true>::lock() /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/SharedMutex.h:372 (ep-engine_ep_unit_tests+0x15a9881)
    #5 folly::detail::LockTraitsImpl<folly::SharedMutexImpl<false, void, std::atomic, false, true>, (folly::detail::MutexLevel)0, false>::lock(folly::SharedMutexImpl<false, void, std::atomic, false, true>&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/LockTraits.h:124:11 (ep-engine_ep_unit_tests+0x717b75)
    #6 std::integral_constant<bool, true> folly::LockPolicyExclusive::lock<folly::SharedMutexImpl<false, void, std::atomic, false, true> >(folly::SharedMutexImpl<false, void, std::atomic, false, true>&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/LockTraits.h:479:5 (ep-engine_ep_unit_tests+0x717b45)
    #7 folly::LockedPtrBase<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >, folly::SharedMutexImpl<false, void, std::atomic, false, true>, folly::LockPolicyExclusive>::LockedPtrBase(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1097:10 (ep-engine_ep_unit_tests+0x158cb02)
    #8 folly::LockedPtr<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >, folly::LockPolicyExclusive>::LockedPtr(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1402:50 (ep-engine_ep_unit_tests+0x158caae)
    #9 folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >::contextualLock() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:653:12 (ep-engine_ep_unit_tests+0x158ceae)
    #10 std::tuple<std::conditional<std::is_const<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > >::value, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >::ConstLockedPtr, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >::LockedPtr>::type, std::conditional<std::is_const<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const>::value, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const::ConstLockedPtr, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const::LockedPtr>::type> folly::acquireLocked<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const>(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >&, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1741:18 (ep-engine_ep_unit_tests+0x158ccda)
    #11 std::pair<std::conditional<std::is_const<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > >::value, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >::ConstLockedPtr, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >::LockedPtr>::type, std::conditional<std::is_const<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const>::value, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const::ConstLockedPtr, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const::LockedPtr>::type> folly::acquireLockedPair<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const>(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >&, folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1753:21 (ep-engine_ep_unit_tests+0x158bbf9)
    #12 HdrHistogram::operator+=(HdrHistogram const&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/utilities/hdrhistogram.cc:67:21 (ep-engine_ep_unit_tests+0x158a3bf)
    #13 HdrHistogramTest_aggregationTest_Test::TestBody() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/engines/ep/tests/module_tests/hdrhistogram_test.cc:317:18 (ep-engine_ep_unit_tests+0x13479b1)
    #14 void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2433:10 (ep-engine_ep_unit_tests+0x1567683)
    #15 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2469:14 (ep-engine_ep_unit_tests+0x1553012)
    #16 testing::Test::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2508:5 (ep-engine_ep_unit_tests+0x153b87c)
    #17 testing::TestInfo::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2684:11 (ep-engine_ep_unit_tests+0x153c26a)
    #18 testing::TestSuite::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2816:28 (ep-engine_ep_unit_tests+0x153c841)
    #19 testing::internal::UnitTestImpl::RunAllTests() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:5338:44 (ep-engine_ep_unit_tests+0x1545a21)
    #20 bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2433:10 (ep-engine_ep_unit_tests+0x156aa43)
    #21 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2469:14 (ep-engine_ep_unit_tests+0x15551e2)
    #22 testing::UnitTest::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:4925:10 (ep-engine_ep_unit_tests+0x15455d7)
    #23 RUN_ALL_TESTS() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/include/gtest/gtest.h:2473:46 (ep-engine_ep_unit_tests+0x1079927)
    #24 main /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/engines/ep/tests/module_tests/ep_unit_tests_main.cc:175:16 (ep-engine_ep_unit_tests+0x107978e)

    Hint: use TSAN_OPTIONS=second_deadlock_stack=1 to get more informative warning message

  Mutex M732257135894671160 acquired here while holding mutex M730849761011117904 in main thread:
    #0 AnnotateRWLockAcquired <null> (ep-engine_ep_unit_tests+0x64007b)
    #1 folly::detail::annotate_rwlock_acquired_impl(void const volatile*, folly::annotate_rwlock_level, char const*, int) /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/synchronization/SanitizeThread.cpp:99 (ep-engine_ep_unit_tests+0x162f6be)
    #2 annotate_rwlock_acquired /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/synchronization/SanitizeThread.h:111 (ep-engine_ep_unit_tests+0x15ad433)
    #3 folly::SharedMutexImpl<false, void, std::atomic, false, true>::annotateAcquired(folly::annotate_rwlock_level) /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/SharedMutex.h:740 (ep-engine_ep_unit_tests+0x15ad433)
    #4 folly::SharedMutexImpl<false, void, std::atomic, false, true>::lock_shared() /home/couchbase/jenkins/workspace/cbdeps-platform-build-old/deps/packages/build/folly/follytsan-prefix/src/follytsan/folly/SharedMutex.h:414 (ep-engine_ep_unit_tests+0x15ad433)
    #5 folly::detail::LockTraitsImpl<folly::SharedMutexImpl<false, void, std::atomic, false, true>, (folly::detail::MutexLevel)1, false>::lock_shared(folly::SharedMutexImpl<false, void, std::atomic, false, true>&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/LockTraits.h:157:11 (ep-engine_ep_unit_tests+0x703215)
    #6 std::integral_constant<bool, true> folly::LockPolicyShared::lock<folly::SharedMutexImpl<false, void, std::atomic, false, true> >(folly::SharedMutexImpl<false, void, std::atomic, false, true>&) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/LockTraits.h:499:5 (ep-engine_ep_unit_tests+0x7031c5)
    #7 folly::LockedPtrBase<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const, folly::SharedMutexImpl<false, void, std::atomic, false, true>, folly::LockPolicyShared>::LockedPtrBase(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1097:10 (ep-engine_ep_unit_tests+0x915242)
    #8 folly::LockedPtr<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const, folly::LockPolicyShared>::LockedPtr(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:1402:50 (ep-engine_ep_unit_tests+0x9151ee)
    #9 folly::SynchronizedBase<folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> >, (folly::detail::MutexLevel)1>::rlock() const /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/tlm/deps/folly.exploded/include/folly/Synchronized.h:144:12 (ep-engine_ep_unit_tests+0x91502e)
    #10 HdrHistogram::Iterator::Iterator(folly::Synchronized<std::unique_ptr<hdr_histogram, HdrHistogram::HdrDeleter>, folly::SharedMutexImpl<false, void, std::atomic, false, true> > const&, HdrHistogram::Iterator::IterMode) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/utilities/hdrhistogram.h:89:66 (ep-engine_ep_unit_tests+0x158be71)
    #11 HdrHistogram::makeLinearIterator(long) const /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/utilities/hdrhistogram.cc:162:28 (ep-engine_ep_unit_tests+0x158aafb)
    #12 HdrHistogramTest_aggregationTest_Test::TestBody() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/engines/ep/tests/module_tests/hdrhistogram_test.cc:322:26 (ep-engine_ep_unit_tests+0x13479e2)
    #13 void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2433:10 (ep-engine_ep_unit_tests+0x1567683)
    #14 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2469:14 (ep-engine_ep_unit_tests+0x1553012)
    #15 testing::Test::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2508:5 (ep-engine_ep_unit_tests+0x153b87c)
    #16 testing::TestInfo::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2684:11 (ep-engine_ep_unit_tests+0x153c26a)
    #17 testing::TestSuite::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2816:28 (ep-engine_ep_unit_tests+0x153c841)
    #18 testing::internal::UnitTestImpl::RunAllTests() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:5338:44 (ep-engine_ep_unit_tests+0x1545a21)
    #19 bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2433:10 (ep-engine_ep_unit_tests+0x156aa43)
    #20 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:2469:14 (ep-engine_ep_unit_tests+0x15551e2)
    #21 testing::UnitTest::Run() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/src/gtest.cc:4925:10 (ep-engine_ep_unit_tests+0x15455d7)
    #22 RUN_ALL_TESTS() /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../third_party/googletest/googletest/include/gtest/gtest.h:2473:46 (ep-engine_ep_unit_tests+0x1079927)
    #23 main /home/couchbase/jenkins/workspace/kv_engine.threadsanitizer_master/build/../kv_engine/engines/ep/tests/module_tests/ep_unit_tests_main.cc:175:16 (ep-engine_ep_unit_tests+0x107978e)

Change-Id: I7c3e9369065e5344333c410602267835f9bcc7e1
Reviewed-on: http://review.couchbase.org/c/kv_engine/+/137745
Reviewed-by: Dave Rigby <[email protected]>
Tested-by: Build Bot <[email protected]>
  • Loading branch information
rdemellow committed Oct 8, 2020
1 parent 5cf5a80 commit 8ee8c85
Showing 1 changed file with 74 additions and 69 deletions.
143 changes: 74 additions & 69 deletions engines/ep/tests/module_tests/hdrhistogram_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
#include <thread>
#include <utility>

static std::vector<std::pair<uint64_t, uint64_t>> getValuesOnePerBucket(
HdrHistogram& histo) {
std::vector<std::pair<uint64_t, uint64_t>> values;
auto iter = histo.makeLinearIterator(/* valueUnitsPerBucket */ 1);
while (auto pair = iter.getNextValueAndCount()) {
values.push_back(*pair);
}
return values;
}

/*
* Unit tests for the HdrHistogram
*/
Expand Down Expand Up @@ -76,13 +86,11 @@ TEST(HdrHistogramTest, linearIteratorTest) {
histogram.addValue(ii);
}

// Need to create the iterator after we have added the data
HdrHistogram::Iterator iter{
histogram.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
uint64_t valueCount = 0;
while (auto result = iter.getNextValueAndCount()) {
EXPECT_EQ(valueCount, result->first);
++valueCount;
auto values = getValuesOnePerBucket(histogram);
EXPECT_EQ(256, values.size());
for (auto& result : values) {
EXPECT_EQ(valueCount++, result.first);
}
}

Expand Down Expand Up @@ -159,11 +167,12 @@ TEST(HdrHistogramTest, addValueAndCountTest) {
HdrHistogram histogram{0, 255, 3};

histogram.addValueAndCount(0, 100);
// Need to create the iterator after we have added the data
HdrHistogram::Iterator iter{histogram.makeLinearIterator(1)};
while (auto result = iter.getNextValueAndCount()) {
EXPECT_EQ(0, result->first);
EXPECT_EQ(100, result->second);

auto values = getValuesOnePerBucket(histogram);
EXPECT_EQ(1, values.size());
for (auto& result : values) {
EXPECT_EQ(0, result.first);
EXPECT_EQ(100, result.second);
}
}

Expand Down Expand Up @@ -284,14 +293,12 @@ TEST(HdrHistogramTest, addValueParallel) {
ASSERT_EQ(maxVal - 1, histogram.getMaxValue());
ASSERT_EQ(0, histogram.getMinValue());

HdrHistogram::Iterator iter{
histogram.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
uint64_t valueCount = 0;
// Assert that the right number of values were added to the histogram
while (auto result = iter.getNextValueAndCount()) {
ASSERT_EQ(valueCount, result->first);
ASSERT_EQ(threads.size() * numOfAddIterations, result->second);
++valueCount;
auto values = getValuesOnePerBucket(histogram);
EXPECT_EQ(maxVal, values.size());
for (auto& result : values) {
ASSERT_EQ(valueCount++, result.first);
ASSERT_EQ(threads.size() * numOfAddIterations, result.second);
}
}

Expand All @@ -306,68 +313,64 @@ TEST(HdrHistogramTest, percentileWhenEmptyTest) {

// Test the aggregation operator method
TEST(HdrHistogramTest, aggregationTest) {
HdrHistogram histogramOne{0, 15, 3};
HdrHistogram histogramTwo{0, 15, 3};
const uint16_t numberOfValues = 15;
HdrHistogram histogramOne{0, numberOfValues, 3};
HdrHistogram histogramTwo{0, numberOfValues, 3};

for (int i = 0; i < 15; i++) {
for (int i = 0; i < numberOfValues; i++) {
histogramOne.addValue(i);
histogramTwo.addValue(i);
}
// Do aggregation
histogramOne += histogramTwo;

HdrHistogram::Iterator iterOne{
histogramOne.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
HdrHistogram::Iterator iterTwo{
histogramTwo.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
auto histoOneValues = getValuesOnePerBucket(histogramOne);
EXPECT_EQ(numberOfValues, histoOneValues.size());

auto histoTwoValues = getValuesOnePerBucket(histogramTwo);
EXPECT_EQ(numberOfValues, histoTwoValues.size());

EXPECT_NE(histoOneValues, histoTwoValues);

uint64_t valueCount = 0;
for (int i = 0; i < 15; i++) {
auto resultOne = iterOne.getNextValueAndCount();
auto resultTwo = iterTwo.getNextValueAndCount();
for (int i = 0; i < numberOfValues; i++) {
// check values are the same for both histograms
EXPECT_EQ(valueCount, resultTwo->first);
EXPECT_EQ(valueCount, resultOne->first);
EXPECT_EQ(valueCount, histoTwoValues[i].first);
EXPECT_EQ(valueCount, histoOneValues[i].first);
// check that the counts for each value is twice as much as
// in a bucket in histogram one as it is in histogram two
EXPECT_EQ(resultOne->second, resultTwo->second * 2);
EXPECT_EQ(histoOneValues[i].second, histoTwoValues[i].second * 2);
++valueCount;
}

// Check the totals of each histogram
EXPECT_EQ(30, histogramOne.getValueCount());
EXPECT_EQ(15, histogramTwo.getValueCount());
EXPECT_EQ(numberOfValues * 2, histogramOne.getValueCount());
EXPECT_EQ(numberOfValues, histogramTwo.getValueCount());
}

// Test the aggregation operator method
TEST(HdrHistogramTest, aggregationTestEmptyLhr) {
const uint16_t numberOfValues = 200;
HdrHistogram histogramOne{0, 15, 3};
HdrHistogram histogramTwo{0, 200, 3};
HdrHistogram histogramTwo{0, numberOfValues, 3};

for (int i = 0; i < 200; i++) {
for (int i = 0; i < numberOfValues; i++) {
histogramTwo.addValue(i);
}
// Do aggregation
histogramOne += histogramTwo;

HdrHistogram::Iterator iterOne{
histogramOne.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
HdrHistogram::Iterator iterTwo{
histogramTwo.makeLinearIterator(/* valueUnitsPerBucket */ 1)};
auto histoOneValues = getValuesOnePerBucket(histogramOne);
EXPECT_EQ(numberOfValues, histoOneValues.size());

// Max value of LHS should be updated too 200 thus counts should be the
// same for every value in both histograms
for (int i = 0; i < 200; i++) {
auto resultOne = iterOne.getNextValueAndCount();
auto resultTwo = iterTwo.getNextValueAndCount();
// check values are the same for both histograms
EXPECT_EQ(resultOne->first, resultTwo->first);
// check that the counts for each value are the same
EXPECT_EQ(resultOne->second, resultTwo->second);
}
auto histoTwoValues = getValuesOnePerBucket(histogramTwo);
EXPECT_EQ(numberOfValues, histoTwoValues.size());

EXPECT_EQ(histoTwoValues, histoOneValues);

// Check the totals of each histogram
EXPECT_EQ(200, histogramOne.getValueCount());
EXPECT_EQ(200, histogramTwo.getValueCount());
EXPECT_EQ(numberOfValues, histogramOne.getValueCount());
EXPECT_EQ(numberOfValues, histogramTwo.getValueCount());
}

// Test the aggregation operator method
Expand All @@ -381,15 +384,13 @@ TEST(HdrHistogramTest, aggregationTestEmptyRhs) {
// Do aggregation
histogramOne += histogramTwo;

HdrHistogram::Iterator iter{
histogramOne.makeLinearIterator(/* valueUnitsPerBucket */ 1)};

uint64_t valueCount = 0;
// make sure the histogram has expanded in size for all 200 values
while (auto result = iter.getNextValueAndCount()) {
EXPECT_EQ(valueCount, result->first);
EXPECT_EQ(1, result->second);
++valueCount;
auto values = getValuesOnePerBucket(histogramOne);
EXPECT_EQ(200, values.size());
uint64_t valueCount = 0;
for (auto& result : values) {
EXPECT_EQ(valueCount++, result.first);
EXPECT_EQ(1, result.second);
}

// Check the totals of each histogram
Expand All @@ -412,11 +413,13 @@ TEST(HdrHistogramTest, int32MaxSizeTest) {
EXPECT_EQ(0, histogram.getValueAtPercentile(100.0));
EXPECT_EQ(0, histogram.getMinValue());

HdrHistogram::Iterator iter{histogram.getHistogramsIterator()};
auto res = iter.getNextBucketLowHighAndCount();
EXPECT_TRUE(res);
// The 3rd field [2] of the returned tuple is the count
EXPECT_EQ(limit, std::get<2>(*res));
{ // iter read lock scope
HdrHistogram::Iterator iter{histogram.getHistogramsIterator()};
auto res = iter.getNextBucketLowHighAndCount();
EXPECT_TRUE(res);
// The 3rd field [2] of the returned tuple is the count
EXPECT_EQ(limit, std::get<2>(*res));
}

// Add 1 more count (previously this would overflow the total_count field
// in the iterator)
Expand All @@ -428,11 +431,13 @@ TEST(HdrHistogramTest, int32MaxSizeTest) {
EXPECT_EQ(0, histogram.getValueAtPercentile(100.0));
EXPECT_EQ(0, histogram.getMinValue());

HdrHistogram::Iterator iter2{histogram.getHistogramsIterator()};
auto res2 = iter2.getNextBucketLowHighAndCount();
EXPECT_TRUE(res2);
// The 3rd field [2] of the returned tuple is the count
EXPECT_EQ(limit, std::get<2>(*res2));
{ // iter2 read lock scope
HdrHistogram::Iterator iter2{histogram.getHistogramsIterator()};
auto res2 = iter2.getNextBucketLowHighAndCount();
EXPECT_TRUE(res2);
// The 3rd field [2] of the returned tuple is the count
EXPECT_EQ(limit, std::get<2>(*res2));
}
}

TEST(HdrHistogramTest, int64MaxSizeTest) {
Expand Down

0 comments on commit 8ee8c85

Please sign in to comment.