1919
2020#include < boost/optional.hpp>
2121#include < folly/portability/GTest.h>
22- #include < hdr_histogram.h>
23-
2422#include < cmath>
25- #include < iomanip>
2623#include < memory>
2724#include < random>
2825#include < thread>
2926#include < utility>
3027
28+ static std::vector<std::pair<uint64_t , uint64_t >> getValuesOnePerBucket (
29+ HdrHistogram& histo) {
30+ std::vector<std::pair<uint64_t , uint64_t >> values;
31+ auto iter = histo.makeLinearIterator (/* valueUnitsPerBucket */ 1 );
32+ while (auto pair = histo.getNextValueAndCount (iter)) {
33+ values.push_back (*pair);
34+ }
35+ return values;
36+ }
37+
3138/*
3239 * Unit tests for the HdrHistogram
3340 */
@@ -79,13 +86,11 @@ TEST(HdrHistogramTest, linearIteratorTest) {
7986 histogram.addValue (ii);
8087 }
8188
82- // Need to create the iterator after we have added the data
83- HdrHistogram::Iterator iter{
84- histogram.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
8589 uint64_t valueCount = 0 ;
86- while (auto result = histogram.getNextValueAndCount (iter)) {
87- EXPECT_EQ (valueCount, result->first );
88- ++valueCount;
90+ auto values = getValuesOnePerBucket (histogram);
91+ EXPECT_EQ (256 , values.size ());
92+ for (auto & result : values) {
93+ EXPECT_EQ (valueCount++, result.first );
8994 }
9095}
9196
@@ -162,11 +167,12 @@ TEST(HdrHistogramTest, addValueAndCountTest) {
162167 HdrHistogram histogram{0 , 255 , 3 };
163168
164169 histogram.addValueAndCount (0 , 100 );
165- // Need to create the iterator after we have added the data
166- HdrHistogram::Iterator iter{histogram.makeLinearIterator (1 )};
167- while (auto result = histogram.getNextValueAndCount (iter)) {
168- EXPECT_EQ (0 , result->first );
169- EXPECT_EQ (100 , result->second );
170+
171+ auto values = getValuesOnePerBucket (histogram);
172+ EXPECT_EQ (1 , values.size ());
173+ for (auto & result : values) {
174+ EXPECT_EQ (0 , result.first );
175+ EXPECT_EQ (100 , result.second );
170176 }
171177}
172178
@@ -287,14 +293,12 @@ TEST(HdrHistogramTest, addValueParallel) {
287293 ASSERT_EQ (maxVal - 1 , histogram.getMaxValue ());
288294 ASSERT_EQ (0 , histogram.getMinValue ());
289295
290- HdrHistogram::Iterator iter{
291- histogram.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
292296 uint64_t valueCount = 0 ;
293- // Assert that the right number of values were added to the histogram
294- while ( auto result = histogram. getNextValueAndCount (iter)) {
295- ASSERT_EQ (valueCount, result-> first );
296- ASSERT_EQ (threads. size () * numOfAddIterations , result-> second );
297- ++valueCount ;
297+ auto values = getValuesOnePerBucket ( histogram);
298+ EXPECT_EQ (maxVal, values. size ());
299+ for ( auto & result : values) {
300+ ASSERT_EQ (valueCount++ , result. first );
301+ ASSERT_EQ (threads. size () * numOfAddIterations, result. second ) ;
298302 }
299303}
300304
@@ -309,68 +313,64 @@ TEST(HdrHistogramTest, percentileWhenEmptyTest) {
309313
310314// Test the aggregation operator method
311315TEST (HdrHistogramTest, aggregationTest) {
312- HdrHistogram histogramOne{0 , 15 , 3 };
313- HdrHistogram histogramTwo{0 , 15 , 3 };
316+ const uint16_t numberOfValues = 15 ;
317+ HdrHistogram histogramOne{0 , numberOfValues, 3 };
318+ HdrHistogram histogramTwo{0 , numberOfValues, 3 };
314319
315- for (int i = 0 ; i < 15 ; i++) {
320+ for (int i = 0 ; i < numberOfValues ; i++) {
316321 histogramOne.addValue (i);
317322 histogramTwo.addValue (i);
318323 }
319324 // Do aggregation
320325 histogramOne += histogramTwo;
321326
322- HdrHistogram::Iterator iterOne{
323- histogramOne.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
324- HdrHistogram::Iterator iterTwo{
325- histogramTwo.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
327+ auto histoOneValues = getValuesOnePerBucket (histogramOne);
328+ EXPECT_EQ (numberOfValues, histoOneValues.size ());
329+
330+ auto histoTwoValues = getValuesOnePerBucket (histogramTwo);
331+ EXPECT_EQ (numberOfValues, histoTwoValues.size ());
332+
333+ EXPECT_NE (histoOneValues, histoTwoValues);
334+
326335 uint64_t valueCount = 0 ;
327- for (int i = 0 ; i < 15 ; i++) {
328- auto resultOne = histogramOne.getNextValueAndCount (iterOne);
329- auto resultTwo = histogramOne.getNextValueAndCount (iterTwo);
336+ for (int i = 0 ; i < numberOfValues; i++) {
330337 // check values are the same for both histograms
331- EXPECT_EQ (valueCount, resultTwo-> first );
332- EXPECT_EQ (valueCount, resultOne-> first );
338+ EXPECT_EQ (valueCount, histoTwoValues[i]. first );
339+ EXPECT_EQ (valueCount, histoOneValues[i]. first );
333340 // check that the counts for each value is twice as much as
334341 // in a bucket in histogram one as it is in histogram two
335- EXPECT_EQ (resultOne-> second , resultTwo-> second * 2 );
342+ EXPECT_EQ (histoOneValues[i]. second , histoTwoValues[i]. second * 2 );
336343 ++valueCount;
337344 }
338345
339346 // Check the totals of each histogram
340- EXPECT_EQ (30 , histogramOne.getValueCount ());
341- EXPECT_EQ (15 , histogramTwo.getValueCount ());
347+ EXPECT_EQ (numberOfValues * 2 , histogramOne.getValueCount ());
348+ EXPECT_EQ (numberOfValues , histogramTwo.getValueCount ());
342349}
343350
344351// Test the aggregation operator method
345352TEST (HdrHistogramTest, aggregationTestEmptyLhr) {
353+ const uint16_t numberOfValues = 200 ;
346354 HdrHistogram histogramOne{0 , 15 , 3 };
347- HdrHistogram histogramTwo{0 , 200 , 3 };
355+ HdrHistogram histogramTwo{0 , numberOfValues , 3 };
348356
349- for (int i = 0 ; i < 200 ; i++) {
357+ for (int i = 0 ; i < numberOfValues ; i++) {
350358 histogramTwo.addValue (i);
351359 }
352360 // Do aggregation
353361 histogramOne += histogramTwo;
354362
355- HdrHistogram::Iterator iterOne{
356- histogramOne.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
357- HdrHistogram::Iterator iterTwo{
358- histogramTwo.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
363+ auto histoOneValues = getValuesOnePerBucket (histogramOne);
364+ EXPECT_EQ (numberOfValues, histoOneValues.size ());
359365
360- // Max value of LHS should be updated too 200 thus counts should be the
361- // same for every value in both histograms
362- for (int i = 0 ; i < 200 ; i++) {
363- auto resultOne = histogramOne.getNextValueAndCount (iterOne);
364- auto resultTwo = histogramOne.getNextValueAndCount (iterTwo);
365- // check values are the same for both histograms
366- EXPECT_EQ (resultOne->first , resultTwo->first );
367- // check that the counts for each value are the same
368- EXPECT_EQ (resultOne->second , resultTwo->second );
369- }
366+ auto histoTwoValues = getValuesOnePerBucket (histogramTwo);
367+ EXPECT_EQ (numberOfValues, histoTwoValues.size ());
368+
369+ EXPECT_EQ (histoTwoValues, histoOneValues);
370370
371371 // Check the totals of each histogram
372- EXPECT_EQ (200 , histogramOne.getValueCount ());
373- EXPECT_EQ (200 , histogramTwo.getValueCount ());
372+ EXPECT_EQ (numberOfValues , histogramOne.getValueCount ());
373+ EXPECT_EQ (numberOfValues , histogramTwo.getValueCount ());
374374}
375375
376376// Test the aggregation operator method
@@ -384,18 +384,73 @@ TEST(HdrHistogramTest, aggregationTestEmptyRhs) {
384384 // Do aggregation
385385 histogramOne += histogramTwo;
386386
387- HdrHistogram::Iterator iter{
388- histogramOne.makeLinearIterator (/* valueUnitsPerBucket */ 1 )};
389-
390- uint64_t valueCount = 0 ;
391387 // make sure the histogram has expanded in size for all 200 values
392- while (auto result = histogramOne.getNextValueAndCount (iter)) {
393- EXPECT_EQ (valueCount, result->first );
394- EXPECT_EQ (1 , result->second );
395- ++valueCount;
388+ auto values = getValuesOnePerBucket (histogramOne);
389+ EXPECT_EQ (200 , values.size ());
390+ uint64_t valueCount = 0 ;
391+ for (auto & result : values) {
392+ EXPECT_EQ (valueCount++, result.first );
393+ EXPECT_EQ (1 , result.second );
396394 }
397395
398396 // Check the totals of each histogram
399397 EXPECT_EQ (200 , histogramOne.getValueCount ());
400398 EXPECT_EQ (0 , histogramTwo.getValueCount ());
401- }
399+ }
400+
401+ static std::vector<boost::optional<std::pair<uint64_t , double >>> getAllValues (
402+ const HdrHistogram& histo, HdrHistogram::Iterator& iter) {
403+ std::vector<boost::optional<std::pair<uint64_t , double >>> values;
404+ while (auto pair = histo.getNextValueAndPercentile (iter)) {
405+ if (!pair.is_initialized ())
406+ break ;
407+ values.push_back (pair);
408+ }
409+ return values;
410+ }
411+
412+ void resetThread (HdrHistogram& histo, ThreadGate& tg) {
413+ EXPECT_EQ (histo.getValueCount (), 10 );
414+ tg.threadUp ();
415+ histo.reset ();
416+ EXPECT_EQ (histo.getValueCount (), 0 );
417+ }
418+
419+ /* *
420+ * Test to check that if you create an iterator on a HdrHistogram object, then
421+ * call reset() on it in another thread and use the iterator that the iterator
422+ * doesn't end up in an infinite loop.
423+ */
424+ TEST (HdrHistogramTest, ResetItoratorInfLoop) {
425+ Hdr2sfMicroSecHistogram histogram;
426+ for (int i = 0 ; i < 10 ; i++) {
427+ histogram.addValue (i);
428+ }
429+ {
430+ auto iter = histogram.getHistogramsIterator ();
431+ auto values = getAllValues (histogram, iter);
432+ EXPECT_EQ (values.size (), 20 );
433+ }
434+
435+ std::thread thread;
436+ ThreadGate tg (2 );
437+ { // Scope that holds read lock for iterator
438+ auto iter2 = histogram.getHistogramsIterator ();
439+ /* *
440+ * Create thread this should start running resetThread() at some point
441+ * int time will be blocked at HdrHistogram::reset() till this scope is
442+ * exited and iter2 is destroyed (releasing the read lock).
443+ * We will also create a ThreadGat to ensure the reset thread is runing
444+ * and is about to try and get an exclusive lock before reading values
445+ * from the histogram.
446+ */
447+ thread = std::thread (resetThread, std::ref (histogram), std::ref (tg));
448+ tg.threadUp ();
449+ auto values = getAllValues (histogram, iter2);
450+ EXPECT_EQ (values.size (), 20 );
451+ } // iter2 read lock released
452+
453+ // wait for resetThread() to complete
454+ thread.join ();
455+ EXPECT_EQ (histogram.getValueCount (), 0 );
456+ }
0 commit comments