2 * Copyright (c) 2021 Daniel R. Carvalho
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <gtest/gtest-spi.h>
30 #include <gtest/gtest.h>
34 #include "base/gtest/cur_tick_fake.hh"
35 #include "base/stats/storage.hh"
37 // Instantiate the fake class to have a valid curTick of 0
38 GTestTickHandler tickHandler
;
40 /** Increases the current tick by one. */
41 void increaseTick() { tickHandler
.setCurTick(curTick() + 1); }
43 /** A pair of value and its number of samples, used for sampling. */
47 Stats::Counter numSamples
;
49 ValueSamples(Stats::Counter value
, Stats::Counter num_samples
)
50 : value(value
), numSamples(num_samples
)
56 * A mocked info class.
57 * @todo There is no real dependency on the info class, so this must be
58 * removed on a cleanup.
60 class MockInfo
: public Stats::Info
63 MockInfo(Stats::StorageParams
* storage_params
)
66 this->storageParams
= storage_params
;
68 ~MockInfo() = default;
70 bool check() const override
{ return true; }
71 void prepare() override
{ }
72 void reset() override
{ }
73 bool zero() const override
{ return true; }
74 void visit(Stats::Output
&visitor
) override
{ }
77 /** Test setting and getting a value to the storage. */
78 TEST(StatsStatStorTest
, SetValueResult
)
80 Stats::StatStor
stor(nullptr);
85 ASSERT_EQ(stor
.value(), val
);
86 ASSERT_EQ(stor
.result(), Stats::Result(val
));
90 ASSERT_EQ(stor
.value(), val
);
91 ASSERT_EQ(stor
.result(), Stats::Result(val
));
94 /** Test if prepare does not change the value. */
95 TEST(StatsStatStorTest
, Prepare
)
97 Stats::StatStor
stor(nullptr);
102 stor
.prepare(nullptr);
103 ASSERT_EQ(stor
.value(), val
);
104 ASSERT_EQ(stor
.result(), Stats::Result(val
));
107 /** Test whether incrementing and decrementing work as expected. */
108 TEST(StatsStatStorTest
, IncDec
)
110 Stats::StatStor
stor(nullptr);
111 Stats::Counter diff_val
= 10;
112 Stats::Counter val
= 0;
116 ASSERT_EQ(stor
.value(), val
);
120 ASSERT_EQ(stor
.value(), val
);
124 ASSERT_EQ(stor
.value(), val
);
128 ASSERT_EQ(stor
.value(), val
);
132 * Test whether zero is correctly set as the reset value. The test order is
133 * to check if it is initially zero on creation, then it is made non zero,
134 * and finally reset to zero.
136 TEST(StatsStatStorTest
, ZeroReset
)
138 Stats::StatStor
stor(nullptr);
139 Stats::Counter val
= 10;
141 ASSERT_TRUE(stor
.zero());
144 ASSERT_TRUE(stor
.zero());
148 ASSERT_FALSE(stor
.zero());
151 /** Test setting and getting a value to the storage. */
152 TEST(StatsAvgStorTest
, SetValueResult
)
154 Stats::AvgStor
stor(nullptr);
156 Stats::Result total
= 0;
162 last_tick
= curTick();
163 ASSERT_EQ(stor
.value(), val
);
164 ASSERT_EQ(stor
.result(), Stats::Result(total
+ val
) /
165 Stats::Result(curTick() - last_reset
+ 1));
168 total
+= val
* (curTick() - last_tick
);
171 last_tick
= curTick();
172 ASSERT_EQ(stor
.value(), val
);
173 ASSERT_EQ(stor
.result(), Stats::Result(total
+ val
) /
174 Stats::Result(curTick() - last_reset
+ 1));
179 * Test whether getting the result in a different tick triggers an assertion.
181 TEST(StatsAvgStorDeathTest
, Result
)
183 Stats::AvgStor
stor(nullptr);
185 ASSERT_DEATH(stor
.result(), ".+");
189 * Test whether getting the result in a different tick does not trigger an
190 * assertion if storage is prepared.
192 TEST(StatsAvgStorTest
, Prepare
)
194 Stats::AvgStor
stor(nullptr);
195 Stats::Counter val
= 10;
196 Stats::Result total
= 0;
202 last_tick
= curTick();
203 ASSERT_EQ(stor
.value(), val
);
204 ASSERT_EQ(stor
.result(), Stats::Result(total
+ val
) /
205 Stats::Result(curTick() - last_reset
+ 1));
208 total
+= val
* (curTick() - last_tick
);
209 stor
.prepare(nullptr);
210 last_tick
= curTick();
211 ASSERT_EQ(stor
.value(), val
);
212 ASSERT_EQ(stor
.result(), Stats::Result(total
+ val
) /
213 Stats::Result(curTick() - last_reset
+ 1));
217 /** Test whether incrementing and decrementing work as expected. */
218 TEST(StatsAvgStorTest
, IncDec
)
220 Stats::AvgStor
stor(nullptr);
221 Stats::Counter diff_val
= 10;
222 Stats::Counter val
= 0;
226 ASSERT_EQ(stor
.value(), val
);
230 ASSERT_EQ(stor
.value(), val
);
234 ASSERT_EQ(stor
.value(), val
);
238 ASSERT_EQ(stor
.value(), val
);
242 ASSERT_EQ(stor
.value(), val
);
246 * Test whether zero is correctly set as the reset value. The test order is
247 * to check if it is initially zero on creation, then it is made non zero,
248 * and finally reset to zero.
250 TEST(StatsAvgStorTest
, ZeroReset
)
252 Stats::AvgStor
stor(nullptr);
253 Stats::Counter val
= 10;
255 ASSERT_TRUE(stor
.zero());
258 ASSERT_TRUE(stor
.zero());
260 // Set current value to val, reset total and increase tick, so that the
261 // next call to set will update the total to be different from zero
266 ASSERT_FALSE(stor
.zero());
270 * Test that an assertion is thrown when no bucket size is provided before
273 TEST(StatsDistStorDeathTest
, NoBucketSize
)
275 Stats::Counter val
= 10;
276 Stats::Counter num_samples
= 5;
277 Stats::DistStor::Params params
;
278 MockInfo
info(¶ms
);
279 Stats::DistStor
stor(&info
);
280 ASSERT_DEATH(stor
.sample(val
, num_samples
), ".+");
284 * Test whether zero is correctly set as the reset value. The test order is
285 * to check if it is initially zero on creation, then it is made non zero,
286 * and finally reset to zero.
288 TEST(StatsDistStorTest
, ZeroReset
)
290 Stats::DistStor::Params params
;
291 params
.bucket_size
= 10;
292 MockInfo
info(¶ms
);
293 Stats::DistStor
stor(&info
);
294 Stats::Counter val
= 10;
295 Stats::Counter num_samples
= 5;
297 ASSERT_TRUE(stor
.zero());
300 stor
.sample(val
, num_samples
);
301 ASSERT_FALSE(stor
.zero());
304 ASSERT_TRUE(stor
.zero());
308 * Test that the size of this storage is equal to its counters vector's size,
309 * and that after it has been set, nothing can modify it.
311 TEST(StatsDistStorTest
, Size
)
313 Stats::Counter val
= 10;
314 Stats::Counter num_samples
= 5;
315 Stats::Counter size
= 20;
316 Stats::DistData data
;
318 Stats::DistStor::Params params
;
319 params
.bucket_size
= 1;
320 params
.buckets
= size
;
321 MockInfo
info(¶ms
);
322 Stats::DistStor
stor(&info
);
324 ASSERT_EQ(stor
.size(), size
);
325 stor
.sample(val
, num_samples
);
326 ASSERT_EQ(stor
.size(), size
);
327 stor
.prepare(&info
, data
);
328 ASSERT_EQ(stor
.size(), size
);
330 ASSERT_EQ(stor
.size(), size
);
332 ASSERT_EQ(stor
.size(), size
);
336 * Compare both dist datas to see if their contents match.
338 * @param data The data being tested.
339 * @param expected_data The ground truth.
340 * @param no_log Whether log should not be compared.
343 checkExpectedDistData(const Stats::DistData
& data
,
344 const Stats::DistData
& expected_data
, bool no_log
= true)
346 ASSERT_EQ(data
.type
, expected_data
.type
);
347 ASSERT_EQ(data
.min
, expected_data
.min
);
348 ASSERT_EQ(data
.max
, expected_data
.max
);
349 ASSERT_EQ(data
.bucket_size
, expected_data
.bucket_size
);
350 ASSERT_EQ(data
.min_val
, expected_data
.min_val
);
351 ASSERT_EQ(data
.max_val
, expected_data
.max_val
);
352 ASSERT_EQ(data
.sum
, expected_data
.sum
);
353 ASSERT_EQ(data
.squares
, expected_data
.squares
);
355 ASSERT_EQ(data
.logs
, expected_data
.logs
);
357 ASSERT_EQ(data
.samples
, expected_data
.samples
);
358 ASSERT_EQ(data
.cvec
.size(), expected_data
.cvec
.size());
359 for (int i
= 0; i
< expected_data
.cvec
.size(); i
++) {
360 ASSERT_EQ(data
.cvec
[i
], expected_data
.cvec
[i
]);
365 * Auxiliary function that finishes preparing the DistStor's expected values,
366 * perform the calls to the storage's sample, and compares the expected data.
368 * @param params The params containing the number of buckets.
369 * @param values The value-num_sample pairs to be sampled.
370 * @param num_values Number of values in the values array.
371 * @param expected_data Expected data after sampling, with the following values
372 * setup to the expected values: bucket_size, min, max_val, and cvec.
375 prepareCheckDistStor(Stats::DistStor::Params
& params
, ValueSamples
* values
,
376 int num_values
, Stats::DistData
& expected_data
)
378 MockInfo
info(¶ms
);
379 Stats::DistStor
stor(&info
);
382 Stats::DistData data
;
384 expected_data
.min
= params
.min
;
385 expected_data
.max
= params
.max
;
386 expected_data
.sum
= 0;
387 expected_data
.squares
= 0;
388 expected_data
.logs
= 0;
389 expected_data
.samples
= 0;
391 // Populate storage with more data
392 for (int i
= 0; i
< num_values
; i
++) {
393 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
395 val
= values
[i
].value
* values
[i
].numSamples
;
396 expected_data
.sum
+= val
;
397 expected_data
.squares
+= values
[i
].value
* val
;
398 expected_data
.samples
+= values
[i
].numSamples
;
400 stor
.prepare(&info
, data
);
402 // DistStor does not use log
403 checkExpectedDistData(data
, expected_data
, true);
406 /** Test setting and getting value from storage. */
407 TEST(StatsDistStorTest
, SamplePrepareSingle
)
409 Stats::DistStor::Params params
;
412 params
.bucket_size
= 5;
415 ValueSamples values
[] = {{10, 5}};
416 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
418 // Setup expected data
419 Stats::DistData expected_data
;
420 expected_data
.type
= Stats::Dist
;
421 expected_data
.bucket_size
= params
.bucket_size
;
422 expected_data
.underflow
= 0;
423 expected_data
.overflow
= 0;
424 expected_data
.min_val
= 10;
425 expected_data
.max_val
= 10;
426 expected_data
.cvec
.clear();
427 expected_data
.cvec
.resize(params
.buckets
);
428 expected_data
.cvec
[2] = 5;
430 prepareCheckDistStor(params
, values
, num_values
, expected_data
);
433 /** Test setting and getting value from storage with multiple values. */
434 TEST(StatsDistStorTest
, SamplePrepareMultiple
)
436 Stats::DistStor::Params params
;
439 params
.bucket_size
= 5;
442 // There are 20 buckets: [0,5[, [5,10[, [10,15[, ..., [95,100[.
443 // We test that values that pass the maximum bucket value (1234, 12345678,
444 // 100) are added to the overflow counter, and that the ones below the
445 // minimum bucket value (-10, -1) are added to the underflow counter.
446 // The extremes (0 and 99) are added to check if they go to the first and
448 ValueSamples values
[] = {{10, 5}, {1234, 2}, {12345678, 99}, {-10, 4},
449 {17, 17}, {52, 63}, {18, 11}, {0, 1}, {99, 15}, {-1, 200}, {100, 50}};
450 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
452 // Setup variables that should always match params' values
453 Stats::DistData expected_data
;
454 expected_data
.type
= Stats::Dist
;
455 expected_data
.min_val
= -10;
456 expected_data
.max_val
= 12345678;
457 expected_data
.bucket_size
= params
.bucket_size
;
458 expected_data
.underflow
= 204;
459 expected_data
.overflow
= 151;
460 expected_data
.sum
= 0;
461 expected_data
.squares
= 0;
462 expected_data
.samples
= 0;
463 expected_data
.cvec
.clear();
464 expected_data
.cvec
.resize(params
.buckets
);
465 expected_data
.cvec
[0] = 1;
466 expected_data
.cvec
[2] = 5;
467 expected_data
.cvec
[3] = 17+11;
468 expected_data
.cvec
[10] = 63;
469 expected_data
.cvec
[19] = 15;
471 prepareCheckDistStor(params
, values
, num_values
, expected_data
);
474 /** Test resetting storage. */
475 TEST(StatsDistStorTest
, Reset
)
477 Stats::DistStor::Params params
;
480 params
.bucket_size
= 5;
482 MockInfo
info(¶ms
);
483 Stats::DistStor
stor(&info
);
485 // Populate storage with random samples
486 ValueSamples values
[] = {{10, 5}, {1234, 2}, {12345678, 99}, {-10, 4},
487 {17, 17}, {52, 63}, {18, 11}, {0, 1}, {99, 15}, {-1, 200}, {100, 50}};
488 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
489 for (int i
= 0; i
< num_values
; i
++) {
490 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
493 // Reset storage, and make sure all data has been cleared
495 Stats::DistData data
;
496 stor
.prepare(&info
, data
);
498 Stats::DistData expected_data
;
499 expected_data
.type
= Stats::Dist
;
500 expected_data
.bucket_size
= params
.bucket_size
;
501 expected_data
.underflow
= 0;
502 expected_data
.overflow
= 0;
503 expected_data
.min
= params
.min
;
504 expected_data
.max
= params
.max
;
505 expected_data
.min_val
= 0;
506 expected_data
.max_val
= 0;
507 expected_data
.sum
= 0;
508 expected_data
.squares
= 0;
509 expected_data
.samples
= 0;
510 expected_data
.cvec
.clear();
511 expected_data
.cvec
.resize(params
.buckets
);
513 checkExpectedDistData(data
, expected_data
, true);
517 * Test that an assertion is thrown when no bucket size is provided before
520 TEST(StatsHistStorDeathTest
, NoBucketSize
)
522 Stats::Counter val
= 10;
523 Stats::Counter num_samples
= 5;
525 // If no bucket size is specified, it is 0 by default
526 Stats::HistStor::Params params
;
527 MockInfo
info(¶ms
);
528 Stats::HistStor
stor(&info
);
529 ASSERT_DEATH(stor
.sample(val
, num_samples
), ".+");
533 * Test whether zero is correctly set as the reset value. The test order is
534 * to check if it is initially zero on creation, then it is made non zero,
535 * and finally reset to zero.
537 TEST(StatsHistStorTest
, ZeroReset
)
539 Stats::HistStor::Params params
;
541 MockInfo
info(¶ms
);
542 Stats::HistStor
stor(&info
);
543 Stats::Counter val
= 10;
544 Stats::Counter num_samples
= 5;
546 ASSERT_TRUE(stor
.zero());
549 stor
.sample(val
, num_samples
);
550 ASSERT_FALSE(stor
.zero());
553 ASSERT_TRUE(stor
.zero());
557 * Test that the size of this storage is equal to its counters vector's size,
558 * and that after it has been set, nothing can modify it.
560 TEST(StatsHistStorTest
, Size
)
562 Stats::Counter val
= 10;
563 Stats::Counter num_samples
= 5;
564 Stats::DistData data
;
565 Stats::size_type sizes
[] = {2, 10, 1234};
567 // If no bucket size is specified, it is 0 by default
569 Stats::HistStor::Params params
;
570 MockInfo
info(¶ms
);
571 Stats::HistStor
stor(&info
);
573 ASSERT_EQ(stor
.size(), 0);
574 stor
.prepare(&info
, data
);
575 ASSERT_EQ(stor
.size(), 0);
577 ASSERT_EQ(stor
.size(), 0);
579 ASSERT_EQ(stor
.size(), 0);
582 for (int i
= 0; i
< (sizeof(sizes
) / sizeof(Stats::size_type
)); i
++) {
583 Stats::HistStor::Params params
;
584 params
.buckets
= sizes
[i
];
585 MockInfo
info(¶ms
);
586 Stats::HistStor
stor(&info
);
588 ASSERT_EQ(stor
.size(), sizes
[i
]);
589 stor
.sample(val
, num_samples
);
590 ASSERT_EQ(stor
.size(), sizes
[i
]);
591 stor
.prepare(&info
, data
);
592 ASSERT_EQ(stor
.size(), sizes
[i
]);
594 ASSERT_EQ(stor
.size(), sizes
[i
]);
596 ASSERT_EQ(stor
.size(), sizes
[i
]);
601 * Auxiliary function that finishes preparing the HistStor's expected values,
602 * perform the calls to the storage's sample, and compares the expected data.
604 * @param params The params containing the number of buckets.
605 * @param values The value-num_sample pairs to be sampled.
606 * @param num_values Number of values in the values array.
607 * @param expected_data Expected data after sampling, with the following values
608 * setup to the expected values: bucket_size, min, max_val, and cvec.
611 prepareCheckHistStor(Stats::HistStor::Params
& params
, ValueSamples
* values
,
612 int num_values
, Stats::DistData
& expected_data
)
614 MockInfo
info(¶ms
);
615 Stats::HistStor
stor(&info
);
618 Stats::DistData data
;
621 expected_data
.min_val
= expected_data
.min
;
622 expected_data
.max
= expected_data
.max_val
+ expected_data
.bucket_size
- 1;
623 expected_data
.sum
= 0;
624 expected_data
.squares
= 0;
625 expected_data
.logs
= 0;
626 expected_data
.samples
= 0;
628 // Populate storage with more data
629 for (int i
= 0; i
< num_values
; i
++) {
630 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
632 val
= values
[i
].value
* values
[i
].numSamples
;
633 expected_data
.sum
+= val
;
634 expected_data
.squares
+= values
[i
].value
* val
;
635 if (values
[i
].value
< 0) {
636 // Negative values don't have log, so mark log check to be skipped
639 expected_data
.logs
+=
640 std::log(values
[i
].value
) * values
[i
].numSamples
;
642 expected_data
.samples
+= values
[i
].numSamples
;
644 stor
.prepare(&info
, data
);
645 checkExpectedDistData(data
, expected_data
, no_log
);
649 * Test samples that fit in the initial buckets, and therefore do not need
652 TEST(StatsHistStorTest
, SamplePrepareFit
)
654 Stats::HistStor::Params params
;
657 // Setup expected data for the hand-carved values given. The final buckets
658 // will be divided at:
659 // Bkt0=[0,1[ , Bkt1=[1,2[, Bkt2=[2,3[, Bkt3=[3,4[
660 ValueSamples values
[] = {{0, 5}, {1, 2}, {2, 99}, {3, 4}};
661 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
662 Stats::DistData expected_data
;
663 expected_data
.type
= Stats::Hist
;
664 expected_data
.bucket_size
= 1;
665 expected_data
.min
= 0;
666 expected_data
.max_val
= 3;
667 expected_data
.cvec
.clear();
668 expected_data
.cvec
.resize(params
.buckets
);
669 expected_data
.cvec
[0] = 5;
670 expected_data
.cvec
[1] = 2;
671 expected_data
.cvec
[2] = 99;
672 expected_data
.cvec
[3] = 4;
674 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
678 * Test samples that do not fit in the initial buckets, and therefore have
681 TEST(StatsHistStorTest
, SamplePrepareSingleGrowUp
)
683 Stats::HistStor::Params params
;
686 // Setup expected data for the hand-carved values given. Since there
687 // are four buckets, and the highest value is 4, the bucket size will
688 // grow to be 2. The final buckets will be divided at:
689 // Bkt0=[0,2[ , Bkt1=[2,4[, Bkt2=[4,6[, Bkt3=[6,8[
690 ValueSamples values
[] = {{0, 5}, {1, 2}, {2, 99}, {4, 4}};
691 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
692 Stats::DistData expected_data
;
693 expected_data
.type
= Stats::Hist
;
694 expected_data
.bucket_size
= 2;
695 expected_data
.min
= 0;
696 expected_data
.max_val
= 6;
697 expected_data
.cvec
.clear();
698 expected_data
.cvec
.resize(params
.buckets
);
699 expected_data
.cvec
[0] = 5+2;
700 expected_data
.cvec
[1] = 99;
701 expected_data
.cvec
[2] = 4;
702 expected_data
.cvec
[3] = 0;
704 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
708 * Test samples that do not fit in the initial buckets, and therefore have
709 * to grow up a few times.
711 TEST(StatsHistStorTest
, SamplePrepareMultipleGrowUp
)
713 Stats::HistStor::Params params
;
716 // Setup expected data for the hand-carved values given. Since there
717 // are four buckets, and the highest value is 4, the bucket size will
718 // grow thrice to become 8. The final buckets will be divided at:
719 // Bkt0=[0,8[ , Bkt1=[8,16[, Bkt2=[16,24[, Bkt3=[24,32[
720 ValueSamples values
[] = {{0, 5}, {1, 2}, {2, 99}, {16, 4}};
721 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
722 Stats::DistData expected_data
;
723 expected_data
.type
= Stats::Hist
;
724 expected_data
.bucket_size
= 8;
725 expected_data
.min
= 0;
726 expected_data
.max_val
= 24;
727 expected_data
.cvec
.clear();
728 expected_data
.cvec
.resize(params
.buckets
);
729 expected_data
.cvec
[0] = 5+2+99;
730 expected_data
.cvec
[1] = 0;
731 expected_data
.cvec
[2] = 4;
732 expected_data
.cvec
[3] = 0;
734 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
738 * Test samples that have a negative value, and therefore do not fit in the
739 * initial buckets. Since this involves using negative values, the logs
742 TEST(StatsHistStorTest
, SamplePrepareGrowDownOddBuckets
)
744 Stats::HistStor::Params params
;
747 // Setup expected data for the hand-carved values given. Since there
748 // is a negative value, the min bucket will change, and the bucket size
749 // will grow to be 2. The final buckets will be divided at:
750 // Bkt0=[-4,-2[ , Bkt1=[-2,-0[, Bkt2=[0,2[, Bkt3=[2,4[, Bkt4=[4,6[
751 ValueSamples values
[] =
752 {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {4, 33}, {-1, 4}};
753 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
754 Stats::DistData expected_data
;
755 expected_data
.type
= Stats::Hist
;
756 expected_data
.bucket_size
= 2;
757 expected_data
.min
= -4;
758 expected_data
.max_val
= 4;
759 expected_data
.cvec
.clear();
760 expected_data
.cvec
.resize(params
.buckets
);
761 expected_data
.cvec
[0] = 0;
762 expected_data
.cvec
[1] = 4;
763 expected_data
.cvec
[2] = 5+2;
764 expected_data
.cvec
[3] = 99+12;
765 expected_data
.cvec
[4] = 33;
767 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
771 * Test samples that have a negative value, and therefore do not fit in the
772 * initial buckets. Since this involves using negative values, the logs
775 TEST(StatsHistStorTest
, SamplePrepareGrowDownEvenBuckets
)
777 Stats::HistStor::Params params
;
780 // Setup expected data for the hand-carved values given. Since there
781 // is a negative value, the min bucket will change, and the bucket size
782 // will grow to be 2. The final buckets will be divided at:
783 // Bkt0=[-4,-2[ , Bkt1=[-2,0[, Bkt2=[0,2[, Bkt3=[2,4[
784 ValueSamples values
[] = {{0, 5}, {1, 2}, {2, 99}, {-1, 4}};
785 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
786 Stats::DistData expected_data
;
787 expected_data
.type
= Stats::Hist
;
788 expected_data
.bucket_size
= 2;
789 expected_data
.min
= -4;
790 expected_data
.max_val
= 2;
791 expected_data
.cvec
.clear();
792 expected_data
.cvec
.resize(params
.buckets
);
793 expected_data
.cvec
[0] = 0;
794 expected_data
.cvec
[1] = 4;
795 expected_data
.cvec
[2] = 5+2;
796 expected_data
.cvec
[3] = 99;
798 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
802 * Test samples that have one low negative value, and therefore do not fit
803 * in the initial buckets and have to grow down a few times. Since this
804 * involves using negative values, the logs become irrelevant.
806 TEST(StatsHistStorTest
, SamplePrepareGrowDownGrowOutOddBuckets
)
808 Stats::HistStor::Params params
;
811 // Setup expected data for the hand-carved values given. Since there
812 // is a negative value, the min bucket will change, and the bucket size
813 // will grow to be 8. The final buckets will be divided at:
814 // Bkt0=[-16,-8[ , Bkt1=[-8,0[, Bkt2=[0,8[, Bkt3=[8,16[, Bkt4=[16,24[
815 ValueSamples values
[] =
816 {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {4, 33}, {-12, 4}};
817 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
818 Stats::DistData expected_data
;
819 expected_data
.type
= Stats::Hist
;
820 expected_data
.bucket_size
= 8;
821 expected_data
.min
= -16;
822 expected_data
.max_val
= 16;
823 expected_data
.cvec
.clear();
824 expected_data
.cvec
.resize(params
.buckets
);
825 expected_data
.cvec
[0] = 4;
826 expected_data
.cvec
[1] = 0;
827 expected_data
.cvec
[2] = 5+2+99+12+33;
828 expected_data
.cvec
[3] = 0;
829 expected_data
.cvec
[4] = 0;
831 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
835 * Test samples that have one low negative value, and therefore do not fit
836 * in the initial buckets and have to grow down a few times. Since this
837 * involves using negative values, the logs become irrelevant.
839 TEST(StatsHistStorTest
, SamplePrepareGrowDownGrowOutEvenBuckets
)
841 Stats::HistStor::Params params
;
844 // Setup expected data for the hand-carved values given. Since there
845 // is a negative value, the min bucket will change, and the bucket size
846 // will grow to be 8. The final buckets will be divided at:
847 // Bkt0=[-16,-8[ , Bkt1=[-8,0[, Bkt2=[0,8[, Bkt3=[8,16[
848 ValueSamples values
[] =
849 {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {-12, 4}};
850 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
851 Stats::DistData expected_data
;
852 expected_data
.type
= Stats::Hist
;
853 expected_data
.bucket_size
= 8;
854 expected_data
.min
= -16;
855 expected_data
.max_val
= 8;
856 expected_data
.cvec
.clear();
857 expected_data
.cvec
.resize(params
.buckets
);
858 expected_data
.cvec
[0] = 4;
859 expected_data
.cvec
[1] = 0;
860 expected_data
.cvec
[2] = 5+2+99+12;
861 expected_data
.cvec
[3] = 0;
863 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
867 * Test a complex sample set with negative values, and therefore multiple
868 * grows will happen. Since this involves using negative values, the logs
871 TEST(StatsHistStorTest
, SamplePrepareMultipleGrowOddBuckets
)
873 Stats::HistStor::Params params
;
876 // Setup expected data for the hand-carved values given. This adds quite
877 // a few positive and negative samples, and the bucket size will grow to
878 // be 64. The final buckets will be divided at:
879 // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[,
881 ValueSamples values
[] =
882 {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}};
883 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
884 Stats::DistData expected_data
;
885 expected_data
.type
= Stats::Hist
;
886 expected_data
.bucket_size
= 64;
887 expected_data
.min
= -128;
888 expected_data
.max_val
= 128;
889 expected_data
.cvec
.clear();
890 expected_data
.cvec
.resize(params
.buckets
);
891 expected_data
.cvec
[0] = 53;
892 expected_data
.cvec
[1] = 12+1;
893 expected_data
.cvec
[2] = 5+2+99;
894 expected_data
.cvec
[3] = 4;
895 expected_data
.cvec
[4] = 0;
897 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
901 * Test a complex sample set with negative values, and therefore multiple
902 * grows will happen. Since this involves using negative values, the logs
905 TEST(StatsHistStorTest
, SamplePrepareMultipleGrowEvenBuckets
)
907 Stats::HistStor::Params params
;
910 // Setup expected data for the hand-carved values given. This adds quite
911 // a few positive and negative samples, and the bucket size will grow to
912 // be 64. The final buckets will be divided at:
913 // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[
914 ValueSamples values
[] =
915 {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}};
916 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
917 Stats::DistData expected_data
;
918 expected_data
.type
= Stats::Hist
;
919 expected_data
.bucket_size
= 64;
920 expected_data
.min
= -128;
921 expected_data
.max_val
= 64;
922 expected_data
.cvec
.clear();
923 expected_data
.cvec
.resize(params
.buckets
);
924 expected_data
.cvec
[0] = 53;
925 expected_data
.cvec
[1] = 12+1;
926 expected_data
.cvec
[2] = 5+2+99;
927 expected_data
.cvec
[3] = 4;
929 prepareCheckHistStor(params
, values
, num_values
, expected_data
);
932 /** Test resetting storage. */
933 TEST(StatsHistStorTest
, Reset
)
935 Stats::HistStor::Params params
;
937 MockInfo
info(¶ms
);
938 Stats::HistStor
stor(&info
);
940 // Setup expected data for the hand-carved values given. This adds quite
941 // a few positive and negative samples, and the bucket size will grow to
942 // be 64. The final buckets will be divided at:
943 // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[
944 ValueSamples values
[] =
945 {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}};
946 const int num_values
= sizeof(values
) / sizeof(ValueSamples
);
947 for (int i
= 0; i
< num_values
; i
++) {
948 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
951 // Reset storage, and make sure all data has been cleared:
952 // Bkt0=[0,1[ , Bkt1=[1,2[, Bkt2=[2,3[, Bkt3=[3,4[
954 Stats::DistData expected_data
;
955 expected_data
.type
= Stats::Hist
;
956 expected_data
.bucket_size
= 1;
957 expected_data
.min
= 0;
958 expected_data
.max_val
= 3;
959 expected_data
.cvec
.clear();
960 expected_data
.cvec
.resize(params
.buckets
);
961 prepareCheckHistStor(params
, values
, 0, expected_data
);
964 /** Test whether adding storages with different sizes triggers an assertion. */
965 TEST(StatsHistStorDeathTest
, AddDifferentSize
)
967 Stats::HistStor::Params params
;
969 MockInfo
info(¶ms
);
970 Stats::HistStor
stor(&info
);
972 Stats::HistStor::Params params2
;
974 MockInfo
info2(¶ms2
);
975 Stats::HistStor
stor2(&info2
);
977 ASSERT_DEATH(stor
.add(&stor2
), ".+");
980 /** Test whether adding storages with different min triggers an assertion. */
981 TEST(StatsHistStorDeathTest
, AddDifferentMin
)
983 Stats::HistStor::Params params
;
985 MockInfo
info(¶ms
);
986 Stats::HistStor
stor(&info
);
989 // On creation, the storage's min is zero
990 Stats::HistStor::Params params2
;
992 MockInfo
info2(¶ms2
);
993 Stats::HistStor
stor2(&info2
);
995 ASSERT_DEATH(stor
.add(&stor2
), ".+");
998 /** Test merging two histograms. */
999 TEST(StatsHistStorTest
, Add
)
1001 Stats::HistStor::Params params
;
1003 MockInfo
info(¶ms
);
1005 // Setup first storage. Buckets are:
1006 // Bkt0=[0,16[, Bkt1=[16,32[, Bkt2=[32,48[, Bkt3=[58,64[
1007 Stats::HistStor
stor(&info
);
1008 ValueSamples values
[] = {{0, 5}, {3, 2}, {20, 37}, {32, 18}};
1009 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
1010 for (int i
= 0; i
< num_values
; i
++) {
1011 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
1013 Stats::DistData data
;
1014 stor
.prepare(&info
, data
);
1016 // Setup second storage. Buckets are:
1017 // Bkt0=[0,32[, Bkt1=[32,64[, Bkt2=[64,96[, Bkt3=[96,128[
1018 Stats::HistStor
stor2(&info
);
1019 ValueSamples values2
[] = {{10, 10}, {0, 1}, {80, 4}, {17, 100}, {95, 79}};
1020 int num_values2
= sizeof(values2
) / sizeof(ValueSamples
);
1021 for (int i
= 0; i
< num_values2
; i
++) {
1022 stor2
.sample(values2
[i
].value
, values2
[i
].numSamples
);
1024 Stats::DistData data2
;
1025 stor2
.prepare(&info
, data2
);
1027 // Perform the merge
1029 Stats::DistData merge_data
;
1030 stor
.prepare(&info
, merge_data
);
1032 // Setup expected data. Buckets are:
1033 // Bkt0=[0,32[, Bkt1=[32,64[, Bkt2=[64,96[, Bkt3=[96,128[
1034 Stats::DistData expected_data
;
1035 expected_data
.type
= Stats::Hist
;
1036 expected_data
.bucket_size
= 32;
1037 expected_data
.min
= 0;
1038 expected_data
.max
= 127;
1039 expected_data
.min_val
= 0;
1040 expected_data
.max_val
= 96;
1041 expected_data
.cvec
.clear();
1042 expected_data
.cvec
.resize(params
.buckets
);
1043 expected_data
.cvec
[0] = 5+2+37+10+1+100;
1044 expected_data
.cvec
[1] = 18;
1045 expected_data
.cvec
[2] = 4+79;
1046 expected_data
.cvec
[3] = 0;
1047 expected_data
.sum
= data
.sum
+ data2
.sum
;
1048 expected_data
.squares
= data
.squares
+ data2
.squares
;
1049 expected_data
.logs
= data
.squares
+ data2
.logs
;
1050 expected_data
.samples
= data
.samples
+ data2
.samples
;
1053 checkExpectedDistData(merge_data
, expected_data
, false);
1057 * Test whether zero is correctly set as the reset value. The test order is
1058 * to check if it is initially zero on creation, then it is made non zero,
1059 * and finally reset to zero.
1061 TEST(StatsSampleStorTest
, ZeroReset
)
1063 Stats::SampleStor
stor(nullptr);
1064 Stats::Counter val
= 10;
1065 Stats::Counter num_samples
= 5;
1067 ASSERT_TRUE(stor
.zero());
1069 stor
.reset(nullptr);
1070 stor
.sample(val
, num_samples
);
1071 ASSERT_FALSE(stor
.zero());
1073 stor
.reset(nullptr);
1074 ASSERT_TRUE(stor
.zero());
1077 /** Test setting and getting value from storage. */
1078 TEST(StatsSampleStorTest
, SamplePrepare
)
1080 Stats::SampleStor
stor(nullptr);
1081 ValueSamples values
[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}};
1082 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
1084 Stats::DistData data
;
1085 Stats::DistData expected_data
;
1086 Stats::DistParams
params(Stats::Deviation
);
1087 MockInfo
info(¶ms
);
1089 // Simple test with one value being sampled
1090 stor
.sample(values
[0].value
, values
[0].numSamples
);
1091 stor
.prepare(&info
, data
);
1092 val
= values
[0].value
* values
[0].numSamples
;
1093 expected_data
.type
= Stats::Deviation
;
1094 expected_data
.sum
= val
;
1095 expected_data
.squares
= values
[0].value
* val
;
1096 expected_data
.samples
= values
[0].numSamples
;
1097 ASSERT_EQ(data
.type
, expected_data
.type
);
1098 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1099 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1100 ASSERT_EQ(data
.samples
, expected_data
.samples
);
1102 // Reset storage, and make sure all data has been cleared
1103 expected_data
.sum
= 0;
1104 expected_data
.squares
= 0;
1105 expected_data
.samples
= 0;
1106 stor
.reset(nullptr);
1107 stor
.prepare(&info
, data
);
1108 ASSERT_EQ(data
.type
, expected_data
.type
);
1109 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1110 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1111 ASSERT_EQ(data
.samples
, expected_data
.samples
);
1113 // Populate storage with more data
1114 for (int i
= 0; i
< num_values
; i
++) {
1115 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
1117 val
= values
[i
].value
* values
[i
].numSamples
;
1118 expected_data
.sum
+= val
;
1119 expected_data
.squares
+= values
[i
].value
* val
;
1120 expected_data
.samples
+= values
[i
].numSamples
;
1122 stor
.prepare(&info
, data
);
1123 ASSERT_EQ(data
.type
, expected_data
.type
);
1124 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1125 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1126 ASSERT_EQ(data
.samples
, expected_data
.samples
);
1129 /** The size is always 1, no matter which functions have been called. */
1130 TEST(StatsSampleStorTest
, Size
)
1132 Stats::SampleStor
stor(nullptr);
1133 Stats::Counter val
= 10;
1134 Stats::Counter num_samples
= 5;
1135 Stats::DistData data
;
1136 Stats::DistParams
params(Stats::Deviation
);
1137 MockInfo
info(¶ms
);
1139 ASSERT_EQ(stor
.size(), 1);
1140 stor
.sample(val
, num_samples
);
1141 ASSERT_EQ(stor
.size(), 1);
1142 stor
.prepare(&info
, data
);
1143 ASSERT_EQ(stor
.size(), 1);
1144 stor
.reset(nullptr);
1145 ASSERT_EQ(stor
.size(), 1);
1147 ASSERT_EQ(stor
.size(), 1);
1151 * Test whether zero is correctly set as the reset value. The test order is
1152 * to check if it is initially zero on creation, then it is made non zero,
1153 * and finally reset to zero.
1155 TEST(StatsAvgSampleStorTest
, ZeroReset
)
1157 Stats::AvgSampleStor
stor(nullptr);
1158 Stats::Counter val
= 10;
1159 Stats::Counter num_samples
= 5;
1161 ASSERT_TRUE(stor
.zero());
1163 stor
.reset(nullptr);
1164 stor
.sample(val
, num_samples
);
1165 ASSERT_FALSE(stor
.zero());
1167 stor
.reset(nullptr);
1168 ASSERT_TRUE(stor
.zero());
1171 /** Test setting and getting value from storage. */
1172 TEST(StatsAvgSampleStorTest
, SamplePrepare
)
1174 Stats::AvgSampleStor
stor(nullptr);
1175 ValueSamples values
[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}};
1176 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
1178 Stats::DistData data
;
1179 Stats::DistData expected_data
;
1180 Stats::DistParams
params(Stats::Deviation
);
1181 MockInfo
info(¶ms
);
1183 // Simple test with one value being sampled
1184 stor
.sample(values
[0].value
, values
[0].numSamples
);
1185 stor
.prepare(&info
, data
);
1186 val
= values
[0].value
* values
[0].numSamples
;
1187 expected_data
.type
= Stats::Deviation
;
1188 expected_data
.sum
= val
;
1189 expected_data
.squares
= values
[0].value
* val
;
1190 ASSERT_EQ(data
.type
, expected_data
.type
);
1191 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1192 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1193 ASSERT_EQ(data
.samples
, curTick());
1197 // Reset storage, and make sure all data has been cleared
1198 expected_data
.sum
= 0;
1199 expected_data
.squares
= 0;
1200 stor
.reset(nullptr);
1201 stor
.prepare(&info
, data
);
1202 ASSERT_EQ(data
.type
, expected_data
.type
);
1203 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1204 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1205 ASSERT_EQ(data
.samples
, curTick());
1209 // Populate storage with more data
1210 for (int i
= 0; i
< num_values
; i
++) {
1211 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
1213 val
= values
[i
].value
* values
[i
].numSamples
;
1214 expected_data
.sum
+= val
;
1215 expected_data
.squares
+= values
[i
].value
* val
;
1217 stor
.prepare(&info
, data
);
1218 ASSERT_EQ(data
.type
, expected_data
.type
);
1219 ASSERT_EQ(data
.sum
, expected_data
.sum
);
1220 ASSERT_EQ(data
.squares
, expected_data
.squares
);
1221 ASSERT_EQ(data
.samples
, curTick());
1224 /** The size is always 1, no matter which functions have been called. */
1225 TEST(StatsAvgSampleStorTest
, Size
)
1227 Stats::AvgSampleStor
stor(nullptr);
1228 Stats::Counter val
= 10;
1229 Stats::Counter num_samples
= 5;
1230 Stats::DistData data
;
1231 Stats::DistParams
params(Stats::Deviation
);
1232 MockInfo
info(¶ms
);
1234 ASSERT_EQ(stor
.size(), 1);
1235 stor
.sample(val
, num_samples
);
1236 ASSERT_EQ(stor
.size(), 1);
1237 stor
.prepare(&info
, data
);
1238 ASSERT_EQ(stor
.size(), 1);
1239 stor
.reset(nullptr);
1240 ASSERT_EQ(stor
.size(), 1);
1242 ASSERT_EQ(stor
.size(), 1);
1246 * Test whether zero is correctly set as the reset value. The test order is
1247 * to check if it is initially zero on creation, then it is made non zero,
1248 * and finally reset to zero.
1250 TEST(StatsSparseHistStorTest
, ZeroReset
)
1252 Stats::SparseHistStor
stor(nullptr);
1253 Stats::Counter val
= 10;
1254 Stats::Counter num_samples
= 5;
1256 ASSERT_TRUE(stor
.zero());
1258 stor
.reset(nullptr);
1259 stor
.sample(val
, num_samples
);
1260 ASSERT_FALSE(stor
.zero());
1262 stor
.reset(nullptr);
1263 ASSERT_TRUE(stor
.zero());
1266 /** Test setting and getting value from storage. */
1267 TEST(StatsSparseHistStorTest
, SamplePrepare
)
1269 Stats::SparseHistStor
stor(nullptr);
1270 ValueSamples values
[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}};
1271 int num_values
= sizeof(values
) / sizeof(ValueSamples
);
1272 Stats::Counter total_samples
;
1273 Stats::SparseHistData data
;
1275 // Simple test with one value being sampled
1276 stor
.sample(values
[0].value
, values
[0].numSamples
);
1277 stor
.prepare(nullptr, data
);
1278 ASSERT_EQ(stor
.size(), 1);
1279 ASSERT_EQ(data
.cmap
.size(), 1);
1280 ASSERT_EQ(data
.cmap
[values
[0].value
], values
[0].numSamples
);
1281 ASSERT_EQ(data
.samples
, values
[0].numSamples
);
1283 // Reset storage, and make sure all data has been cleared
1284 stor
.reset(nullptr);
1285 stor
.prepare(nullptr, data
);
1286 ASSERT_EQ(stor
.size(), 0);
1287 ASSERT_EQ(data
.cmap
.size(), 0);
1288 ASSERT_EQ(data
.samples
, 0);
1290 // Populate storage with more data
1291 for (int i
= 0; i
< num_values
; i
++) {
1292 stor
.sample(values
[i
].value
, values
[i
].numSamples
);
1294 stor
.prepare(nullptr, data
);
1296 ASSERT_EQ(stor
.size(), num_values
);
1297 ASSERT_EQ(data
.cmap
.size(), num_values
);
1298 for (int i
= 0; i
< num_values
; i
++) {
1299 ASSERT_EQ(data
.cmap
[values
[i
].value
], values
[i
].numSamples
);
1300 total_samples
+= values
[i
].numSamples
;
1302 ASSERT_EQ(data
.samples
, total_samples
);