| Index: base/metrics/sample_vector_unittest.cc
|
| diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
|
| index 864a44dcbf3a7fac5de6e8037e9f955f9959f29f..2aef015668784c954aa75d0a65135729433c821a 100644
|
| --- a/base/metrics/sample_vector_unittest.cc
|
| +++ b/base/metrics/sample_vector_unittest.cc
|
| @@ -7,18 +7,29 @@
|
| #include <limits.h>
|
| #include <stddef.h>
|
|
|
| +#include <atomic>
|
| #include <memory>
|
| #include <vector>
|
|
|
| #include "base/metrics/bucket_ranges.h"
|
| #include "base/metrics/histogram.h"
|
| +#include "base/metrics/persistent_memory_allocator.h"
|
| #include "base/test/gtest_util.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace base {
|
| -namespace {
|
|
|
| -TEST(SampleVectorTest, AccumulateTest) {
|
| +// This framework class has "friend" access to the SampleVector for accessing
|
| +// non-public methods and fields.
|
| +class SampleVectorTest : public testing::Test {
|
| + public:
|
| + const HistogramBase::AtomicCount* GetSamplesCounts(
|
| + const SampleVectorBase& samples) {
|
| + return samples.counts();
|
| + }
|
| +};
|
| +
|
| +TEST_F(SampleVectorTest, Accumulate) {
|
| // Custom buckets: [1, 5) [5, 10)
|
| BucketRanges ranges(3);
|
| ranges.set_range(0, 1);
|
| @@ -45,7 +56,7 @@ TEST(SampleVectorTest, AccumulateTest) {
|
| EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
|
| }
|
|
|
| -TEST(SampleVectorTest, Accumulate_LargeValuesDontOverflow) {
|
| +TEST_F(SampleVectorTest, Accumulate_LargeValuesDontOverflow) {
|
| // Custom buckets: [1, 250000000) [250000000, 500000000)
|
| BucketRanges ranges(3);
|
| ranges.set_range(0, 1);
|
| @@ -72,7 +83,7 @@ TEST(SampleVectorTest, Accumulate_LargeValuesDontOverflow) {
|
| EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
|
| }
|
|
|
| -TEST(SampleVectorTest, AddSubtractTest) {
|
| +TEST_F(SampleVectorTest, AddSubtract) {
|
| // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX)
|
| BucketRanges ranges(5);
|
| ranges.set_range(0, 0);
|
| @@ -116,7 +127,7 @@ TEST(SampleVectorTest, AddSubtractTest) {
|
| EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
|
| }
|
|
|
| -TEST(SampleVectorDeathTest, BucketIndexTest) {
|
| +TEST_F(SampleVectorTest, BucketIndexDeath) {
|
| // 8 buckets with exponential layout:
|
| // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
|
| BucketRanges ranges(9);
|
| @@ -158,7 +169,7 @@ TEST(SampleVectorDeathTest, BucketIndexTest) {
|
| EXPECT_DCHECK_DEATH(samples2.Accumulate(10, 100));
|
| }
|
|
|
| -TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
|
| +TEST_F(SampleVectorTest, AddSubtractBucketNotMatchDeath) {
|
| // Custom buckets 1: [1, 3) [3, 5)
|
| BucketRanges ranges1(3);
|
| ranges1.set_range(0, 1);
|
| @@ -197,7 +208,7 @@ TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
|
| EXPECT_DCHECK_DEATH(samples1.Subtract(samples2));
|
| }
|
|
|
| -TEST(SampleVectorIteratorTest, IterateTest) {
|
| +TEST_F(SampleVectorTest, Iterate) {
|
| BucketRanges ranges(5);
|
| ranges.set_range(0, 0);
|
| ranges.set_range(1, 1);
|
| @@ -257,7 +268,7 @@ TEST(SampleVectorIteratorTest, IterateTest) {
|
| EXPECT_EQ(4, i);
|
| }
|
|
|
| -TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
|
| +TEST_F(SampleVectorTest, IterateDoneDeath) {
|
| BucketRanges ranges(5);
|
| ranges.set_range(0, 0);
|
| ranges.set_range(1, 1);
|
| @@ -282,5 +293,251 @@ TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
|
| EXPECT_FALSE(it->Done());
|
| }
|
|
|
| -} // namespace
|
| +TEST_F(SampleVectorTest, SingleSample) {
|
| + // Custom buckets: [1, 5) [5, 10)
|
| + BucketRanges ranges(3);
|
| + ranges.set_range(0, 1);
|
| + ranges.set_range(1, 5);
|
| + ranges.set_range(2, 10);
|
| + SampleVector samples(&ranges);
|
| +
|
| + // Ensure that a single value accumulates correctly.
|
| + EXPECT_FALSE(GetSamplesCounts(samples));
|
| + samples.Accumulate(3, 200);
|
| + EXPECT_EQ(200, samples.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples));
|
| + samples.Accumulate(3, 400);
|
| + EXPECT_EQ(600, samples.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples));
|
| + EXPECT_EQ(3 * 600, samples.sum());
|
| + EXPECT_EQ(600, samples.TotalCount());
|
| + EXPECT_EQ(600, samples.redundant_count());
|
| +
|
| + // Ensure that the iterator returns only one value.
|
| + HistogramBase::Sample min;
|
| + int64_t max;
|
| + HistogramBase::Count count;
|
| + std::unique_ptr<SampleCountIterator> it = samples.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(600, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + // Ensure that it can be merged to another single-sample vector.
|
| + SampleVector samples_copy(&ranges);
|
| + samples_copy.Add(samples);
|
| + EXPECT_FALSE(GetSamplesCounts(samples_copy));
|
| + EXPECT_EQ(3 * 600, samples_copy.sum());
|
| + EXPECT_EQ(600, samples_copy.TotalCount());
|
| + EXPECT_EQ(600, samples_copy.redundant_count());
|
| +
|
| + // A different value should cause creation of the counts array.
|
| + samples.Accumulate(8, 100);
|
| + EXPECT_TRUE(GetSamplesCounts(samples));
|
| + EXPECT_EQ(600, samples.GetCount(3));
|
| + EXPECT_EQ(100, samples.GetCount(8));
|
| + EXPECT_EQ(3 * 600 + 8 * 100, samples.sum());
|
| + EXPECT_EQ(600 + 100, samples.TotalCount());
|
| + EXPECT_EQ(600 + 100, samples.redundant_count());
|
| +
|
| + // The iterator should now return both values.
|
| + it = samples.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(600, count);
|
| + it->Next();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(5, min);
|
| + EXPECT_EQ(10, max);
|
| + EXPECT_EQ(100, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + // Ensure that it can merged to a single-sample vector.
|
| + samples_copy.Add(samples);
|
| + EXPECT_TRUE(GetSamplesCounts(samples_copy));
|
| + EXPECT_EQ(3 * 1200 + 8 * 100, samples_copy.sum());
|
| + EXPECT_EQ(1200 + 100, samples_copy.TotalCount());
|
| + EXPECT_EQ(1200 + 100, samples_copy.redundant_count());
|
| +}
|
| +
|
| +TEST_F(SampleVectorTest, PersistentSampleVector) {
|
| + LocalPersistentMemoryAllocator allocator(64 << 10, 0, "");
|
| + std::atomic<PersistentMemoryAllocator::Reference> samples_ref;
|
| + samples_ref.store(0, std::memory_order_relaxed);
|
| + HistogramSamples::Metadata samples_meta;
|
| + memset(&samples_meta, 0, sizeof(samples_meta));
|
| +
|
| + // Custom buckets: [1, 5) [5, 10)
|
| + BucketRanges ranges(3);
|
| + ranges.set_range(0, 1);
|
| + ranges.set_range(1, 5);
|
| + ranges.set_range(2, 10);
|
| +
|
| + // Persistent allocation.
|
| + const size_t counts_bytes =
|
| + sizeof(HistogramBase::AtomicCount) * ranges.bucket_count();
|
| + const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1,
|
| + counts_bytes, false);
|
| +
|
| + PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation);
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| + samples1.Accumulate(3, 200);
|
| + EXPECT_EQ(200, samples1.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| + EXPECT_EQ(0, samples1.GetCount(8));
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| +
|
| + PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation);
|
| + EXPECT_EQ(200, samples2.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples2));
|
| +
|
| + HistogramBase::Sample min;
|
| + int64_t max;
|
| + HistogramBase::Count count;
|
| + std::unique_ptr<SampleCountIterator> it = samples2.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(200, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + samples1.Accumulate(8, 100);
|
| + EXPECT_TRUE(GetSamplesCounts(samples1));
|
| +
|
| + EXPECT_FALSE(GetSamplesCounts(samples2));
|
| + EXPECT_EQ(200, samples2.GetCount(3));
|
| + EXPECT_EQ(100, samples2.GetCount(8));
|
| + EXPECT_TRUE(GetSamplesCounts(samples2));
|
| + EXPECT_EQ(3 * 200 + 8 * 100, samples2.sum());
|
| + EXPECT_EQ(300, samples2.TotalCount());
|
| + EXPECT_EQ(300, samples2.redundant_count());
|
| +
|
| + it = samples2.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(200, count);
|
| + it->Next();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(5, min);
|
| + EXPECT_EQ(10, max);
|
| + EXPECT_EQ(100, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + PersistentSampleVector samples3(0, &ranges, &samples_meta, allocation);
|
| + EXPECT_TRUE(GetSamplesCounts(samples2));
|
| + EXPECT_EQ(200, samples3.GetCount(3));
|
| + EXPECT_EQ(100, samples3.GetCount(8));
|
| + EXPECT_EQ(3 * 200 + 8 * 100, samples3.sum());
|
| + EXPECT_EQ(300, samples3.TotalCount());
|
| + EXPECT_EQ(300, samples3.redundant_count());
|
| +
|
| + it = samples3.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(200, count);
|
| + it->Next();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(5, min);
|
| + EXPECT_EQ(10, max);
|
| + EXPECT_EQ(100, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +}
|
| +
|
| +TEST_F(SampleVectorTest, PersistentSampleVectorTestWithOutsideAlloc) {
|
| + LocalPersistentMemoryAllocator allocator(64 << 10, 0, "");
|
| + std::atomic<PersistentMemoryAllocator::Reference> samples_ref;
|
| + samples_ref.store(0, std::memory_order_relaxed);
|
| + HistogramSamples::Metadata samples_meta;
|
| + memset(&samples_meta, 0, sizeof(samples_meta));
|
| +
|
| + // Custom buckets: [1, 5) [5, 10)
|
| + BucketRanges ranges(3);
|
| + ranges.set_range(0, 1);
|
| + ranges.set_range(1, 5);
|
| + ranges.set_range(2, 10);
|
| +
|
| + // Persistent allocation.
|
| + const size_t counts_bytes =
|
| + sizeof(HistogramBase::AtomicCount) * ranges.bucket_count();
|
| + const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1,
|
| + counts_bytes, false);
|
| +
|
| + PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation);
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| + samples1.Accumulate(3, 200);
|
| + EXPECT_EQ(200, samples1.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| +
|
| + // Because the delayed allocation can be shared with other objects (the
|
| + // |offset| parameter allows concatinating multiple data blocks into the
|
| + // same allocation), it's possible that the allocation gets realized from
|
| + // the outside even though the data block being accessed is all zero.
|
| + allocation.Get();
|
| + EXPECT_EQ(200, samples1.GetCount(3));
|
| + EXPECT_FALSE(GetSamplesCounts(samples1));
|
| +
|
| + HistogramBase::Sample min;
|
| + int64_t max;
|
| + HistogramBase::Count count;
|
| + std::unique_ptr<SampleCountIterator> it = samples1.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(200, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + // A duplicate samples object should still see the single-sample entry even
|
| + // when storage is available.
|
| + PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation);
|
| + EXPECT_EQ(200, samples2.GetCount(3));
|
| +
|
| + // New accumulations, in both directions, of the existing value should work.
|
| + samples1.Accumulate(3, 50);
|
| + EXPECT_EQ(250, samples1.GetCount(3));
|
| + EXPECT_EQ(250, samples2.GetCount(3));
|
| + samples2.Accumulate(3, 50);
|
| + EXPECT_EQ(300, samples1.GetCount(3));
|
| + EXPECT_EQ(300, samples2.GetCount(3));
|
| +
|
| + it = samples1.Iterator();
|
| + ASSERT_FALSE(it->Done());
|
| + it->Get(&min, &max, &count);
|
| + EXPECT_EQ(1, min);
|
| + EXPECT_EQ(5, max);
|
| + EXPECT_EQ(300, count);
|
| + it->Next();
|
| + EXPECT_TRUE(it->Done());
|
| +
|
| + samples1.Accumulate(8, 100);
|
| + EXPECT_TRUE(GetSamplesCounts(samples1));
|
| + EXPECT_EQ(300, samples1.GetCount(3));
|
| + EXPECT_EQ(300, samples2.GetCount(3));
|
| + EXPECT_EQ(100, samples1.GetCount(8));
|
| + EXPECT_EQ(100, samples2.GetCount(8));
|
| + samples2.Accumulate(8, 100);
|
| + EXPECT_EQ(300, samples1.GetCount(3));
|
| + EXPECT_EQ(300, samples2.GetCount(3));
|
| + EXPECT_EQ(200, samples1.GetCount(8));
|
| + EXPECT_EQ(200, samples2.GetCount(8));
|
| +}
|
| +
|
| } // namespace base
|
|
|