xref: /aosp_15_r20/external/cronet/base/metrics/sample_vector_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/metrics/sample_vector.h"
6 
7 #include <limits.h>
8 #include <stddef.h>
9 
10 #include <atomic>
11 #include <memory>
12 #include <vector>
13 
14 #include "base/metrics/bucket_ranges.h"
15 #include "base/metrics/histogram.h"
16 #include "base/metrics/persistent_memory_allocator.h"
17 #include "base/test/gtest_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 
20 namespace base {
21 
22 // This framework class has "friend" access to the SampleVector for accessing
23 // non-public methods and fields.
24 class SampleVectorTest : public testing::Test {
25  public:
HasSamplesCounts(const SampleVectorBase & samples)26   bool HasSamplesCounts(const SampleVectorBase& samples) {
27     return samples.counts().has_value();
28   }
29 };
30 
TEST_F(SampleVectorTest,Accumulate)31 TEST_F(SampleVectorTest, Accumulate) {
32   // Custom buckets: [1, 5) [5, 10)
33   BucketRanges ranges(3);
34   ranges.set_range(0, 1);
35   ranges.set_range(1, 5);
36   ranges.set_range(2, 10);
37   SampleVector samples(1, &ranges);
38 
39   samples.Accumulate(1, 200);
40   samples.Accumulate(2, -300);
41   EXPECT_EQ(-100, samples.GetCountAtIndex(0));
42 
43   samples.Accumulate(5, 200);
44   EXPECT_EQ(200, samples.GetCountAtIndex(1));
45 
46   EXPECT_EQ(600, samples.sum());
47   EXPECT_EQ(100, samples.redundant_count());
48   EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
49 
50   samples.Accumulate(5, -100);
51   EXPECT_EQ(100, samples.GetCountAtIndex(1));
52 
53   EXPECT_EQ(100, samples.sum());
54   EXPECT_EQ(0, samples.redundant_count());
55   EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
56 }
57 
TEST_F(SampleVectorTest,Accumulate_LargeValuesDontOverflow)58 TEST_F(SampleVectorTest, Accumulate_LargeValuesDontOverflow) {
59   // Custom buckets: [1, 250000000) [250000000, 500000000)
60   BucketRanges ranges(3);
61   ranges.set_range(0, 1);
62   ranges.set_range(1, 250000000);
63   ranges.set_range(2, 500000000);
64   SampleVector samples(1, &ranges);
65 
66   samples.Accumulate(240000000, 200);
67   samples.Accumulate(249999999, -300);
68   EXPECT_EQ(-100, samples.GetCountAtIndex(0));
69 
70   samples.Accumulate(250000000, 200);
71   EXPECT_EQ(200, samples.GetCountAtIndex(1));
72 
73   EXPECT_EQ(23000000300LL, samples.sum());
74   EXPECT_EQ(100, samples.redundant_count());
75   EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
76 
77   samples.Accumulate(250000000, -100);
78   EXPECT_EQ(100, samples.GetCountAtIndex(1));
79 
80   EXPECT_EQ(-1999999700LL, samples.sum());
81   EXPECT_EQ(0, samples.redundant_count());
82   EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
83 }
84 
TEST_F(SampleVectorTest,AddSubtract)85 TEST_F(SampleVectorTest, AddSubtract) {
86   // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX)
87   BucketRanges ranges(5);
88   ranges.set_range(0, 0);
89   ranges.set_range(1, 1);
90   ranges.set_range(2, 2);
91   ranges.set_range(3, 3);
92   ranges.set_range(4, INT_MAX);
93 
94   SampleVector samples1(1, &ranges);
95   samples1.Accumulate(0, 100);
96   samples1.Accumulate(2, 100);
97   samples1.Accumulate(4, 100);
98   EXPECT_EQ(600, samples1.sum());
99   EXPECT_EQ(300, samples1.TotalCount());
100   EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
101 
102   SampleVector samples2(2, &ranges);
103   samples2.Accumulate(1, 200);
104   samples2.Accumulate(2, 200);
105   samples2.Accumulate(4, 200);
106   EXPECT_EQ(1400, samples2.sum());
107   EXPECT_EQ(600, samples2.TotalCount());
108   EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount());
109 
110   samples1.Add(samples2);
111   EXPECT_EQ(100, samples1.GetCountAtIndex(0));
112   EXPECT_EQ(200, samples1.GetCountAtIndex(1));
113   EXPECT_EQ(300, samples1.GetCountAtIndex(2));
114   EXPECT_EQ(300, samples1.GetCountAtIndex(3));
115   EXPECT_EQ(2000, samples1.sum());
116   EXPECT_EQ(900, samples1.TotalCount());
117   EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
118 
119   samples1.Subtract(samples2);
120   EXPECT_EQ(100, samples1.GetCountAtIndex(0));
121   EXPECT_EQ(0, samples1.GetCountAtIndex(1));
122   EXPECT_EQ(100, samples1.GetCountAtIndex(2));
123   EXPECT_EQ(100, samples1.GetCountAtIndex(3));
124   EXPECT_EQ(600, samples1.sum());
125   EXPECT_EQ(300, samples1.TotalCount());
126   EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
127 }
128 
TEST_F(SampleVectorTest,BucketIndexDeath)129 TEST_F(SampleVectorTest, BucketIndexDeath) {
130   // 8 buckets with exponential layout:
131   // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
132   BucketRanges ranges(9);
133   Histogram::InitializeBucketRanges(1, 64, &ranges);
134   SampleVector samples(1, &ranges);
135 
136   // Normal case
137   samples.Accumulate(0, 1);
138   samples.Accumulate(3, 2);
139   samples.Accumulate(64, 3);
140   EXPECT_EQ(1, samples.GetCount(0));
141   EXPECT_EQ(2, samples.GetCount(2));
142   EXPECT_EQ(3, samples.GetCount(65));
143 
144   // Extreme case.
145   EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(INT_MIN, 100), "");
146   EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(-1, 100), "");
147   EXPECT_DEATH_IF_SUPPORTED(samples.Accumulate(INT_MAX, 100), "");
148 
149   // Custom buckets: [1, 5) [5, 10)
150   // Note, this is not a valid BucketRanges for Histogram because it does not
151   // have overflow buckets.
152   BucketRanges ranges2(3);
153   ranges2.set_range(0, 1);
154   ranges2.set_range(1, 5);
155   ranges2.set_range(2, 10);
156   SampleVector samples2(2, &ranges2);
157 
158   // Normal case.
159   samples2.Accumulate(1, 1);
160   samples2.Accumulate(4, 1);
161   samples2.Accumulate(5, 2);
162   samples2.Accumulate(9, 2);
163   EXPECT_EQ(2, samples2.GetCount(1));
164   EXPECT_EQ(4, samples2.GetCount(5));
165 
166   // Extreme case.
167   EXPECT_DEATH_IF_SUPPORTED(samples2.Accumulate(0, 100), "");
168   EXPECT_DEATH_IF_SUPPORTED(samples2.Accumulate(10, 100), "");
169 }
170 
TEST_F(SampleVectorTest,AddSubtractBucketNotMatchDeath)171 TEST_F(SampleVectorTest, AddSubtractBucketNotMatchDeath) {
172   // Custom buckets 1: [1, 3) [3, 5)
173   BucketRanges ranges1(3);
174   ranges1.set_range(0, 1);
175   ranges1.set_range(1, 3);
176   ranges1.set_range(2, 5);
177   SampleVector samples1(1, &ranges1);
178 
179   // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
180   BucketRanges ranges2(5);
181   ranges2.set_range(0, 0);
182   ranges2.set_range(1, 1);
183   ranges2.set_range(2, 3);
184   ranges2.set_range(3, 6);
185   ranges2.set_range(4, 7);
186   SampleVector samples2(2, &ranges2);
187 
188   samples2.Accumulate(1, 100);
189   samples1.Add(samples2);
190   EXPECT_EQ(100, samples1.GetCountAtIndex(0));
191 
192   // Extra bucket in the beginning. These should CHECK in GetBucketIndex.
193   samples2.Accumulate(0, 100);
194   EXPECT_DEATH_IF_SUPPORTED(samples1.Add(samples2), "");
195   EXPECT_DEATH_IF_SUPPORTED(samples1.Subtract(samples2), "");
196 
197   // Extra bucket in the end. These should cause AddSubtractImpl to fail, and
198   // Add to DCHECK as a result.
199   samples2.Accumulate(0, -100);
200   samples2.Accumulate(6, 100);
201   EXPECT_DCHECK_DEATH(samples1.Add(samples2));
202   EXPECT_DCHECK_DEATH(samples1.Subtract(samples2));
203 
204   // Bucket not match: [3, 5) VS [3, 6). These should cause AddSubtractImpl to
205   // DCHECK.
206   samples2.Accumulate(6, -100);
207   samples2.Accumulate(3, 100);
208   EXPECT_DCHECK_DEATH(samples1.Add(samples2));
209   EXPECT_DCHECK_DEATH(samples1.Subtract(samples2));
210 }
211 
TEST_F(SampleVectorTest,Iterate)212 TEST_F(SampleVectorTest, Iterate) {
213   BucketRanges ranges(5);
214   ranges.set_range(0, 0);
215   ranges.set_range(1, 1);
216   ranges.set_range(2, 2);
217   ranges.set_range(3, 3);
218   ranges.set_range(4, 4);
219 
220   // Create iterator from SampleVector.
221   SampleVector samples(1, &ranges);
222   samples.Accumulate(0, 0);  // Iterator will bypass this empty bucket.
223   samples.Accumulate(1, 1);
224   samples.Accumulate(2, 2);
225   samples.Accumulate(3, 3);
226   std::unique_ptr<SampleCountIterator> it = samples.Iterator();
227 
228   int i;
229   size_t index;
230   HistogramBase::Sample min;
231   int64_t max;
232   HistogramBase::Count count;
233   for (i = 1; !it->Done(); i++, it->Next()) {
234     it->Get(&min, &max, &count);
235     EXPECT_EQ(i, min);
236     EXPECT_EQ(i + 1, max);
237     EXPECT_EQ(i, count);
238 
239     EXPECT_TRUE(it->GetBucketIndex(&index));
240     EXPECT_EQ(static_cast<size_t>(i), index);
241   }
242   EXPECT_EQ(4, i);
243 }
244 
TEST_F(SampleVectorTest,Iterator_InvalidSingleSample)245 TEST_F(SampleVectorTest, Iterator_InvalidSingleSample) {
246   // Create 3 buckets: [0, 1), [1, 2), [2, INT_MAX).
247   BucketRanges ranges(4);
248   ranges.set_range(0, 0);
249   ranges.set_range(1, 1);
250   ranges.set_range(2, 2);
251   ranges.set_range(3, HistogramBase::kSampleType_MAX);
252 
253   // Create an invalid SingleSample.
254   HistogramSamples::AtomicSingleSample invalid_single_sample;
255   invalid_single_sample.Accumulate(/*bucket=*/4, /*count=*/1);
256 
257   // Create a SampleVector and set its SingleSample to the invalid one.
258   SampleVector samples(&ranges);
259   *samples.SingleSampleForTesting() = invalid_single_sample;
260 
261   // Create an iterator and verify that it is empty (the sample is ignored).
262   std::unique_ptr<SampleCountIterator> it = samples.Iterator();
263   ASSERT_TRUE(it->Done());
264 
265   // Add some valid samples. SampleVector should now use a counts storage.
266   samples.Accumulate(/*value=*/0, /*count=*/1);
267   samples.Accumulate(/*value=*/1, /*count=*/1);
268 
269   // Create an iterator. Verify that the new samples are returned, and that the
270   // invalid sample is not (it was discarded).
271   HistogramBase::Sample min;
272   int64_t max;
273   HistogramBase::Count count;
274   it = samples.Iterator();
275   ASSERT_FALSE(it->Done());
276   it->Get(&min, &max, &count);
277   EXPECT_EQ(min, 0);
278   EXPECT_EQ(max, 1);
279   EXPECT_EQ(count, 1);
280   it->Next();
281   ASSERT_FALSE(it->Done());
282   it->Get(&min, &max, &count);
283   EXPECT_EQ(min, 1);
284   EXPECT_EQ(max, 2);
285   EXPECT_EQ(count, 1);
286   it->Next();
287   EXPECT_TRUE(it->Done());
288 }
289 
TEST_F(SampleVectorTest,ExtractingIterator_InvalidSingleSample)290 TEST_F(SampleVectorTest, ExtractingIterator_InvalidSingleSample) {
291   // Create 3 buckets: [0, 1), [1, 2), and [2, INT_MAX).
292   BucketRanges ranges(4);
293   ranges.set_range(0, 0);
294   ranges.set_range(1, 1);
295   ranges.set_range(2, 2);
296   ranges.set_range(3, HistogramBase::kSampleType_MAX);
297 
298   // Create an invalid SingleSample.
299   HistogramSamples::AtomicSingleSample invalid_single_sample;
300   invalid_single_sample.Accumulate(/*bucket=*/4, /*count=*/1);
301 
302   // Create a SampleVector and set its SingleSample to the invalid one.
303   SampleVector samples(&ranges);
304   *samples.SingleSampleForTesting() = invalid_single_sample;
305 
306   // Create an extracting iterator and verify that it is empty (the sample is
307   // ignored).
308   std::unique_ptr<SampleCountIterator> it = samples.ExtractingIterator();
309   ASSERT_TRUE(it->Done());
310 
311   // Verify that the invalid sample was extracted.
312   HistogramSamples::SingleSample current_single_sample =
313       samples.SingleSampleForTesting()->Load();
314   EXPECT_EQ(current_single_sample.bucket, 0);
315   EXPECT_EQ(current_single_sample.count, 0);
316 }
317 
TEST_F(SampleVectorTest,IterateDoneDeath)318 TEST_F(SampleVectorTest, IterateDoneDeath) {
319   BucketRanges ranges(5);
320   ranges.set_range(0, 0);
321   ranges.set_range(1, 1);
322   ranges.set_range(2, 2);
323   ranges.set_range(3, 3);
324   ranges.set_range(4, INT_MAX);
325   SampleVector samples(1, &ranges);
326 
327   std::unique_ptr<SampleCountIterator> it = samples.Iterator();
328 
329   EXPECT_TRUE(it->Done());
330 
331   HistogramBase::Sample min;
332   int64_t max;
333   HistogramBase::Count count;
334   EXPECT_DCHECK_DEATH(it->Get(&min, &max, &count));
335 
336   EXPECT_DCHECK_DEATH(it->Next());
337 
338   samples.Accumulate(2, 100);
339   it = samples.Iterator();
340   EXPECT_FALSE(it->Done());
341 }
342 
TEST_F(SampleVectorTest,SingleSample)343 TEST_F(SampleVectorTest, SingleSample) {
344   // Custom buckets: [1, 5) [5, 10)
345   BucketRanges ranges(3);
346   ranges.set_range(0, 1);
347   ranges.set_range(1, 5);
348   ranges.set_range(2, 10);
349   SampleVector samples(&ranges);
350 
351   // Ensure that a single value accumulates correctly.
352   EXPECT_FALSE(HasSamplesCounts(samples));
353   samples.Accumulate(3, 200);
354   EXPECT_EQ(200, samples.GetCount(3));
355   EXPECT_FALSE(HasSamplesCounts(samples));
356   samples.Accumulate(3, 400);
357   EXPECT_EQ(600, samples.GetCount(3));
358   EXPECT_FALSE(HasSamplesCounts(samples));
359   EXPECT_EQ(3 * 600, samples.sum());
360   EXPECT_EQ(600, samples.TotalCount());
361   EXPECT_EQ(600, samples.redundant_count());
362 
363   // Ensure that the iterator returns only one value.
364   HistogramBase::Sample min;
365   int64_t max;
366   HistogramBase::Count count;
367   std::unique_ptr<SampleCountIterator> it = samples.Iterator();
368   ASSERT_FALSE(it->Done());
369   it->Get(&min, &max, &count);
370   EXPECT_EQ(1, min);
371   EXPECT_EQ(5, max);
372   EXPECT_EQ(600, count);
373   it->Next();
374   EXPECT_TRUE(it->Done());
375 
376   // Ensure that it can be merged to another single-sample vector.
377   SampleVector samples_copy(&ranges);
378   samples_copy.Add(samples);
379   EXPECT_FALSE(HasSamplesCounts(samples_copy));
380   EXPECT_EQ(3 * 600, samples_copy.sum());
381   EXPECT_EQ(600, samples_copy.TotalCount());
382   EXPECT_EQ(600, samples_copy.redundant_count());
383 
384   // A different value should cause creation of the counts array.
385   samples.Accumulate(8, 100);
386   EXPECT_TRUE(HasSamplesCounts(samples));
387   EXPECT_EQ(600, samples.GetCount(3));
388   EXPECT_EQ(100, samples.GetCount(8));
389   EXPECT_EQ(3 * 600 + 8 * 100, samples.sum());
390   EXPECT_EQ(600 + 100, samples.TotalCount());
391   EXPECT_EQ(600 + 100, samples.redundant_count());
392 
393   // The iterator should now return both values.
394   it = samples.Iterator();
395   ASSERT_FALSE(it->Done());
396   it->Get(&min, &max, &count);
397   EXPECT_EQ(1, min);
398   EXPECT_EQ(5, max);
399   EXPECT_EQ(600, count);
400   it->Next();
401   ASSERT_FALSE(it->Done());
402   it->Get(&min, &max, &count);
403   EXPECT_EQ(5, min);
404   EXPECT_EQ(10, max);
405   EXPECT_EQ(100, count);
406   it->Next();
407   EXPECT_TRUE(it->Done());
408 
409   // Ensure that it can merged to a single-sample vector.
410   samples_copy.Add(samples);
411   EXPECT_TRUE(HasSamplesCounts(samples_copy));
412   EXPECT_EQ(3 * 1200 + 8 * 100, samples_copy.sum());
413   EXPECT_EQ(1200 + 100, samples_copy.TotalCount());
414   EXPECT_EQ(1200 + 100, samples_copy.redundant_count());
415 }
416 
TEST_F(SampleVectorTest,PersistentSampleVector)417 TEST_F(SampleVectorTest, PersistentSampleVector) {
418   LocalPersistentMemoryAllocator allocator(64 << 10, 0, "");
419   std::atomic<PersistentMemoryAllocator::Reference> samples_ref;
420   samples_ref.store(0, std::memory_order_relaxed);
421   HistogramSamples::Metadata samples_meta;
422   memset(&samples_meta, 0, sizeof(samples_meta));
423 
424   // Custom buckets: [1, 5) [5, 10)
425   BucketRanges ranges(3);
426   ranges.set_range(0, 1);
427   ranges.set_range(1, 5);
428   ranges.set_range(2, 10);
429 
430   // Persistent allocation.
431   const size_t counts_bytes =
432       sizeof(HistogramBase::AtomicCount) * ranges.bucket_count();
433   const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1,
434                                                counts_bytes, false);
435 
436   PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation);
437   EXPECT_FALSE(HasSamplesCounts(samples1));
438   samples1.Accumulate(3, 200);
439   EXPECT_EQ(200, samples1.GetCount(3));
440   EXPECT_FALSE(HasSamplesCounts(samples1));
441   EXPECT_EQ(0, samples1.GetCount(8));
442   EXPECT_FALSE(HasSamplesCounts(samples1));
443 
444   PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation);
445   EXPECT_EQ(200, samples2.GetCount(3));
446   EXPECT_FALSE(HasSamplesCounts(samples2));
447 
448   HistogramBase::Sample min;
449   int64_t max;
450   HistogramBase::Count count;
451   std::unique_ptr<SampleCountIterator> it = samples2.Iterator();
452   ASSERT_FALSE(it->Done());
453   it->Get(&min, &max, &count);
454   EXPECT_EQ(1, min);
455   EXPECT_EQ(5, max);
456   EXPECT_EQ(200, count);
457   it->Next();
458   EXPECT_TRUE(it->Done());
459 
460   samples1.Accumulate(8, 100);
461   EXPECT_TRUE(HasSamplesCounts(samples1));
462 
463   EXPECT_FALSE(HasSamplesCounts(samples2));
464   EXPECT_EQ(200, samples2.GetCount(3));
465   EXPECT_EQ(100, samples2.GetCount(8));
466   EXPECT_TRUE(HasSamplesCounts(samples2));
467   EXPECT_EQ(3 * 200 + 8 * 100, samples2.sum());
468   EXPECT_EQ(300, samples2.TotalCount());
469   EXPECT_EQ(300, samples2.redundant_count());
470 
471   it = samples2.Iterator();
472   ASSERT_FALSE(it->Done());
473   it->Get(&min, &max, &count);
474   EXPECT_EQ(1, min);
475   EXPECT_EQ(5, max);
476   EXPECT_EQ(200, count);
477   it->Next();
478   ASSERT_FALSE(it->Done());
479   it->Get(&min, &max, &count);
480   EXPECT_EQ(5, min);
481   EXPECT_EQ(10, max);
482   EXPECT_EQ(100, count);
483   it->Next();
484   EXPECT_TRUE(it->Done());
485 
486   PersistentSampleVector samples3(0, &ranges, &samples_meta, allocation);
487   EXPECT_TRUE(HasSamplesCounts(samples2));
488   EXPECT_EQ(200, samples3.GetCount(3));
489   EXPECT_EQ(100, samples3.GetCount(8));
490   EXPECT_EQ(3 * 200 + 8 * 100, samples3.sum());
491   EXPECT_EQ(300, samples3.TotalCount());
492   EXPECT_EQ(300, samples3.redundant_count());
493 
494   it = samples3.Iterator();
495   ASSERT_FALSE(it->Done());
496   it->Get(&min, &max, &count);
497   EXPECT_EQ(1, min);
498   EXPECT_EQ(5, max);
499   EXPECT_EQ(200, count);
500   it->Next();
501   ASSERT_FALSE(it->Done());
502   it->Get(&min, &max, &count);
503   EXPECT_EQ(5, min);
504   EXPECT_EQ(10, max);
505   EXPECT_EQ(100, count);
506   it->Next();
507   EXPECT_TRUE(it->Done());
508 }
509 
TEST_F(SampleVectorTest,PersistentSampleVectorTestWithOutsideAlloc)510 TEST_F(SampleVectorTest, PersistentSampleVectorTestWithOutsideAlloc) {
511   LocalPersistentMemoryAllocator allocator(64 << 10, 0, "");
512   std::atomic<PersistentMemoryAllocator::Reference> samples_ref;
513   samples_ref.store(0, std::memory_order_relaxed);
514   HistogramSamples::Metadata samples_meta;
515   memset(&samples_meta, 0, sizeof(samples_meta));
516 
517   // Custom buckets: [1, 5) [5, 10)
518   BucketRanges ranges(3);
519   ranges.set_range(0, 1);
520   ranges.set_range(1, 5);
521   ranges.set_range(2, 10);
522 
523   // Persistent allocation.
524   const size_t counts_bytes =
525       sizeof(HistogramBase::AtomicCount) * ranges.bucket_count();
526   const DelayedPersistentAllocation allocation(&allocator, &samples_ref, 1,
527                                                counts_bytes, false);
528 
529   PersistentSampleVector samples1(0, &ranges, &samples_meta, allocation);
530   EXPECT_FALSE(HasSamplesCounts(samples1));
531   samples1.Accumulate(3, 200);
532   EXPECT_EQ(200, samples1.GetCount(3));
533   EXPECT_FALSE(HasSamplesCounts(samples1));
534 
535   // Because the delayed allocation can be shared with other objects (the
536   // |offset| parameter allows concatinating multiple data blocks into the
537   // same allocation), it's possible that the allocation gets realized from
538   // the outside even though the data block being accessed is all zero.
539   allocation.Get<uint8_t>();
540   EXPECT_EQ(200, samples1.GetCount(3));
541   EXPECT_FALSE(HasSamplesCounts(samples1));
542 
543   HistogramBase::Sample min;
544   int64_t max;
545   HistogramBase::Count count;
546   std::unique_ptr<SampleCountIterator> it = samples1.Iterator();
547   ASSERT_FALSE(it->Done());
548   it->Get(&min, &max, &count);
549   EXPECT_EQ(1, min);
550   EXPECT_EQ(5, max);
551   EXPECT_EQ(200, count);
552   it->Next();
553   EXPECT_TRUE(it->Done());
554 
555   // A duplicate samples object should still see the single-sample entry even
556   // when storage is available.
557   PersistentSampleVector samples2(0, &ranges, &samples_meta, allocation);
558   EXPECT_EQ(200, samples2.GetCount(3));
559 
560   // New accumulations, in both directions, of the existing value should work.
561   samples1.Accumulate(3, 50);
562   EXPECT_EQ(250, samples1.GetCount(3));
563   EXPECT_EQ(250, samples2.GetCount(3));
564   samples2.Accumulate(3, 50);
565   EXPECT_EQ(300, samples1.GetCount(3));
566   EXPECT_EQ(300, samples2.GetCount(3));
567 
568   it = samples1.Iterator();
569   ASSERT_FALSE(it->Done());
570   it->Get(&min, &max, &count);
571   EXPECT_EQ(1, min);
572   EXPECT_EQ(5, max);
573   EXPECT_EQ(300, count);
574   it->Next();
575   EXPECT_TRUE(it->Done());
576 
577   samples1.Accumulate(8, 100);
578   EXPECT_TRUE(HasSamplesCounts(samples1));
579   EXPECT_EQ(300, samples1.GetCount(3));
580   EXPECT_EQ(300, samples2.GetCount(3));
581   EXPECT_EQ(100, samples1.GetCount(8));
582   EXPECT_EQ(100, samples2.GetCount(8));
583   samples2.Accumulate(8, 100);
584   EXPECT_EQ(300, samples1.GetCount(3));
585   EXPECT_EQ(300, samples2.GetCount(3));
586   EXPECT_EQ(200, samples1.GetCount(8));
587   EXPECT_EQ(200, samples2.GetCount(8));
588 }
589 
590 // Tests GetPeakBucketSize() returns accurate max bucket size.
TEST_F(SampleVectorTest,GetPeakBucketSize)591 TEST_F(SampleVectorTest, GetPeakBucketSize) {
592   // Custom buckets: [1, 5) [5, 10) [10, 20)
593   BucketRanges ranges(4);
594   ranges.set_range(0, 1);
595   ranges.set_range(1, 5);
596   ranges.set_range(2, 10);
597   ranges.set_range(3, 20);
598   SampleVector samples(1, &ranges);
599   samples.Accumulate(3, 1);
600   samples.Accumulate(6, 2);
601   samples.Accumulate(12, 3);
602   EXPECT_EQ(3, samples.GetPeakBucketSize());
603 }
604 
605 }  // namespace base
606