| /* | |
| * Copyright (c) 2021 Daniel R. Carvalho | |
| * All rights reserved | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include <gtest/gtest-spi.h> | |
| #include <gtest/gtest.h> | |
| #include <cmath> | |
| #include "base/gtest/cur_tick_fake.hh" | |
| #include "base/gtest/logging.hh" | |
| #include "base/stats/storage.hh" | |
| using namespace gem5; | |
| // Instantiate the fake class to have a valid curTick of 0 | |
| GTestTickHandler tickHandler; | |
| /** Increases the current tick by one. */ | |
| void increaseTick() { tickHandler.setCurTick(curTick() + 1); } | |
| /** A pair of value and its number of samples, used for sampling. */ | |
| struct ValueSamples | |
| { | |
| statistics::Counter value; | |
| statistics::Counter numSamples; | |
| ValueSamples(statistics::Counter value, statistics::Counter num_samples) | |
| : value(value), numSamples(num_samples) | |
| { | |
| } | |
| }; | |
| /** Test setting and getting a value to the storage. */ | |
| TEST(StatsStatStorTest, SetValueResult) | |
| { | |
| statistics::StatStor stor(nullptr); | |
| statistics::Counter val; | |
| val = 10; | |
| stor.set(val); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(val)); | |
| val = 1234; | |
| stor.set(val); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(val)); | |
| } | |
| /** Test if prepare does not change the value. */ | |
| TEST(StatsStatStorTest, Prepare) | |
| { | |
| statistics::StatStor stor(nullptr); | |
| statistics::Counter val; | |
| val = 10; | |
| stor.set(val); | |
| stor.prepare(nullptr); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(val)); | |
| } | |
| /** Test whether incrementing and decrementing work as expected. */ | |
| TEST(StatsStatStorTest, IncDec) | |
| { | |
| statistics::StatStor stor(nullptr); | |
| statistics::Counter diff_val = 10; | |
| statistics::Counter val = 0; | |
| stor.inc(diff_val); | |
| val += diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.inc(diff_val); | |
| val += diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.dec(diff_val); | |
| val -= diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.dec(diff_val); | |
| val -= diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| } | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsStatStorTest, ZeroReset) | |
| { | |
| statistics::StatStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| stor.inc(val); | |
| ASSERT_FALSE(stor.zero()); | |
| } | |
| /** Test setting and getting a value to the storage. */ | |
| TEST(StatsAvgStorTest, SetValueResult) | |
| { | |
| statistics::AvgStor stor(nullptr); | |
| statistics::Counter val; | |
| statistics::Result total = 0; | |
| Tick last_reset = 0; | |
| Tick last_tick = 0; | |
| val = 10; | |
| stor.set(val); | |
| last_tick = curTick(); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(total + val) / | |
| statistics::Result(curTick() - last_reset + 1)); | |
| increaseTick(); | |
| total += val * (curTick() - last_tick); | |
| val = 1234; | |
| stor.set(val); | |
| last_tick = curTick(); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(total + val) / | |
| statistics::Result(curTick() - last_reset + 1)); | |
| increaseTick(); | |
| } | |
| #if TRACING_ON | |
| /** | |
| * Test whether getting the result in a different tick triggers an assertion. | |
| */ | |
| TEST(StatsAvgStorDeathTest, Result) | |
| { | |
| statistics::AvgStor stor(nullptr); | |
| increaseTick(); | |
| ASSERT_DEATH(stor.result(), ".+"); | |
| } | |
| #endif | |
| /** | |
| * Test whether getting the result in a different tick does not trigger an | |
| * assertion if storage is prepared. | |
| */ | |
| TEST(StatsAvgStorTest, Prepare) | |
| { | |
| statistics::AvgStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Result total = 0; | |
| Tick last_reset = 0; | |
| Tick last_tick = 0; | |
| val = 10; | |
| stor.set(val); | |
| last_tick = curTick(); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(total + val) / | |
| statistics::Result(curTick() - last_reset + 1)); | |
| increaseTick(); | |
| total += val * (curTick() - last_tick); | |
| stor.prepare(nullptr); | |
| last_tick = curTick(); | |
| ASSERT_EQ(stor.value(), val); | |
| ASSERT_EQ(stor.result(), statistics::Result(total + val) / | |
| statistics::Result(curTick() - last_reset + 1)); | |
| increaseTick(); | |
| } | |
| /** Test whether incrementing and decrementing work as expected. */ | |
| TEST(StatsAvgStorTest, IncDec) | |
| { | |
| statistics::AvgStor stor(nullptr); | |
| statistics::Counter diff_val = 10; | |
| statistics::Counter val = 0; | |
| stor.set(diff_val); | |
| val += diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.inc(diff_val); | |
| val += diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.inc(diff_val); | |
| val += diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.dec(diff_val); | |
| val -= diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| stor.dec(diff_val); | |
| val -= diff_val; | |
| ASSERT_EQ(stor.value(), val); | |
| } | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsAvgStorTest, ZeroReset) | |
| { | |
| statistics::AvgStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| ASSERT_TRUE(stor.zero()); | |
| // Set current value to val, reset total and increase tick, so that the | |
| // next call to set will update the total to be different from zero | |
| stor.inc(val); | |
| stor.reset(nullptr); | |
| increaseTick(); | |
| stor.inc(val); | |
| ASSERT_FALSE(stor.zero()); | |
| } | |
| #if TRACING_ON | |
| /** Test that an assertion is thrown when bucket size is 0. */ | |
| TEST(StatsDistStorDeathTest, BucketSize0) | |
| { | |
| EXPECT_ANY_THROW(statistics::DistStor::Params params(0, 5, 0)); | |
| } | |
| #endif | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsDistStorTest, ZeroReset) | |
| { | |
| statistics::DistStor::Params params(0, 99, 10); | |
| statistics::DistStor stor(¶ms); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(¶ms); | |
| stor.sample(val, num_samples); | |
| ASSERT_FALSE(stor.zero()); | |
| stor.reset(¶ms); | |
| ASSERT_TRUE(stor.zero()); | |
| } | |
| /** | |
| * Test that the size of this storage is equal to its counters vector's size, | |
| * and that after it has been set, nothing can modify it. | |
| */ | |
| TEST(StatsDistStorTest, Size) | |
| { | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| statistics::Counter size = 20; | |
| statistics::DistData data; | |
| statistics::DistStor::Params params(0, 19, 1); | |
| statistics::DistStor stor(¶ms); | |
| ASSERT_EQ(stor.size(), size); | |
| stor.sample(val, num_samples); | |
| ASSERT_EQ(stor.size(), size); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(stor.size(), size); | |
| stor.reset(¶ms); | |
| ASSERT_EQ(stor.size(), size); | |
| stor.zero(); | |
| ASSERT_EQ(stor.size(), size); | |
| } | |
| /** | |
| * Compare both dist datas to see if their contents match. | |
| * | |
| * @param data The data being tested. | |
| * @param expected_data The ground truth. | |
| * @param no_log Whether log should not be compared. | |
| */ | |
| void | |
| checkExpectedDistData(const statistics::DistData& data, | |
| const statistics::DistData& expected_data, bool no_log = true) | |
| { | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.min, expected_data.min); | |
| ASSERT_EQ(data.max, expected_data.max); | |
| ASSERT_EQ(data.bucket_size, expected_data.bucket_size); | |
| ASSERT_EQ(data.min_val, expected_data.min_val); | |
| ASSERT_EQ(data.max_val, expected_data.max_val); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| if (!no_log) { | |
| ASSERT_EQ(data.logs, expected_data.logs); | |
| } | |
| ASSERT_EQ(data.samples, expected_data.samples); | |
| ASSERT_EQ(data.cvec.size(), expected_data.cvec.size()); | |
| for (int i = 0; i < expected_data.cvec.size(); i++) { | |
| ASSERT_EQ(data.cvec[i], expected_data.cvec[i]); | |
| } | |
| } | |
| /** | |
| * Auxiliary function that finishes preparing the DistStor's expected values, | |
| * perform the calls to the storage's sample, and compares the expected data. | |
| * | |
| * @param params The params containing the number of buckets. | |
| * @param values The value-num_sample pairs to be sampled. | |
| * @param num_values Number of values in the values array. | |
| * @param expected_data Expected data after sampling, with the following values | |
| * setup to the expected values: bucket_size, min, max_val, and cvec. | |
| */ | |
| void | |
| prepareCheckDistStor(statistics::DistStor::Params& params, | |
| ValueSamples* values, int num_values, statistics::DistData& expected_data) | |
| { | |
| statistics::DistStor stor(¶ms); | |
| statistics::Counter val; | |
| statistics::DistData data; | |
| expected_data.min = params.min; | |
| expected_data.max = params.max; | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| expected_data.logs = 0; | |
| expected_data.samples = 0; | |
| // Populate storage with more data | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| val = values[i].value * values[i].numSamples; | |
| expected_data.sum += val; | |
| expected_data.squares += values[i].value * val; | |
| expected_data.samples += values[i].numSamples; | |
| } | |
| stor.prepare(¶ms, data); | |
| // DistStor does not use log | |
| checkExpectedDistData(data, expected_data, true); | |
| } | |
| /** Test setting and getting value from storage. */ | |
| TEST(StatsDistStorTest, SamplePrepareSingle) | |
| { | |
| statistics::DistStor::Params params(0, 99, 5); | |
| ValueSamples values[] = {{10, 5}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| // Setup expected data | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Dist; | |
| expected_data.bucket_size = params.bucket_size; | |
| expected_data.underflow = 0; | |
| expected_data.overflow = 0; | |
| expected_data.min_val = 10; | |
| expected_data.max_val = 10; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[2] = 5; | |
| prepareCheckDistStor(params, values, num_values, expected_data); | |
| } | |
| /** Test setting and getting value from storage with multiple values. */ | |
| TEST(StatsDistStorTest, SamplePrepareMultiple) | |
| { | |
| statistics::DistStor::Params params(0, 99, 5); | |
| // There are 20 buckets: [0,5[, [5,10[, [10,15[, ..., [95,100[. | |
| // We test that values that pass the maximum bucket value (1234, 12345678, | |
| // 100) are added to the overflow counter, and that the ones below the | |
| // minimum bucket value (-10, -1) are added to the underflow counter. | |
| // The extremes (0 and 99) are added to check if they go to the first and | |
| // last buckets. | |
| ValueSamples values[] = {{10, 5}, {1234, 2}, {12345678, 99}, {-10, 4}, | |
| {17, 17}, {52, 63}, {18, 11}, {0, 1}, {99, 15}, {-1, 200}, {100, 50}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| // Setup variables that should always match params' values | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Dist; | |
| expected_data.min_val = -10; | |
| expected_data.max_val = 12345678; | |
| expected_data.bucket_size = params.bucket_size; | |
| expected_data.underflow = 204; | |
| expected_data.overflow = 151; | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| expected_data.samples = 0; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 1; | |
| expected_data.cvec[2] = 5; | |
| expected_data.cvec[3] = 17+11; | |
| expected_data.cvec[10] = 63; | |
| expected_data.cvec[19] = 15; | |
| prepareCheckDistStor(params, values, num_values, expected_data); | |
| } | |
| /** Test resetting storage. */ | |
| TEST(StatsDistStorTest, Reset) | |
| { | |
| statistics::DistStor::Params params(0, 99, 5); | |
| statistics::DistStor stor(¶ms); | |
| // Populate storage with random samples | |
| ValueSamples values[] = {{10, 5}, {1234, 2}, {12345678, 99}, {-10, 4}, | |
| {17, 17}, {52, 63}, {18, 11}, {0, 1}, {99, 15}, {-1, 200}, {100, 50}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| } | |
| // Reset storage, and make sure all data has been cleared | |
| stor.reset(¶ms); | |
| statistics::DistData data; | |
| stor.prepare(¶ms, data); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Dist; | |
| expected_data.bucket_size = params.bucket_size; | |
| expected_data.underflow = 0; | |
| expected_data.overflow = 0; | |
| expected_data.min = params.min; | |
| expected_data.max = params.max; | |
| expected_data.min_val = 0; | |
| expected_data.max_val = 0; | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| expected_data.samples = 0; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| checkExpectedDistData(data, expected_data, true); | |
| } | |
| #if TRACING_ON | |
| /** Test that an assertion is thrown when not enough buckets are provided. */ | |
| TEST(StatsHistStorDeathTest, NotEnoughBuckets0) | |
| { | |
| EXPECT_ANY_THROW(statistics::HistStor::Params params(0)); | |
| } | |
| /** Test that an assertion is thrown when not enough buckets are provided. */ | |
| TEST(StatsHistStorDeathTest, NotEnoughBuckets1) | |
| { | |
| EXPECT_ANY_THROW(statistics::HistStor::Params params(1)); | |
| } | |
| #endif | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsHistStorTest, ZeroReset) | |
| { | |
| statistics::HistStor::Params params(10); | |
| statistics::HistStor stor(¶ms); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(¶ms); | |
| stor.sample(val, num_samples); | |
| ASSERT_FALSE(stor.zero()); | |
| stor.reset(¶ms); | |
| ASSERT_TRUE(stor.zero()); | |
| } | |
| /** | |
| * Test that the size of this storage is equal to its counters vector's size, | |
| * and that after it has been set, nothing can modify it. | |
| */ | |
| TEST(StatsHistStorTest, Size) | |
| { | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| statistics::DistData data; | |
| statistics::size_type sizes[] = {2, 10, 1234}; | |
| for (int i = 0; i < (sizeof(sizes) / sizeof(statistics::size_type)); i++) { | |
| statistics::HistStor::Params params(sizes[i]); | |
| statistics::HistStor stor(¶ms); | |
| ASSERT_EQ(stor.size(), sizes[i]); | |
| stor.sample(val, num_samples); | |
| ASSERT_EQ(stor.size(), sizes[i]); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(stor.size(), sizes[i]); | |
| stor.reset(¶ms); | |
| ASSERT_EQ(stor.size(), sizes[i]); | |
| stor.zero(); | |
| ASSERT_EQ(stor.size(), sizes[i]); | |
| } | |
| } | |
| /** | |
| * Auxiliary function that finishes preparing the HistStor's expected values, | |
| * perform the calls to the storage's sample, and compares the expected data. | |
| * | |
| * @param params The params containing the number of buckets. | |
| * @param values The value-num_sample pairs to be sampled. | |
| * @param num_values Number of values in the values array. | |
| * @param expected_data Expected data after sampling, with the following values | |
| * setup to the expected values: bucket_size, min, max_val, and cvec. | |
| */ | |
| void | |
| prepareCheckHistStor(statistics::HistStor::Params& params, | |
| ValueSamples* values, int num_values, statistics::DistData& expected_data) | |
| { | |
| statistics::HistStor stor(¶ms); | |
| statistics::Counter val; | |
| statistics::DistData data; | |
| bool no_log = false; | |
| expected_data.min_val = expected_data.min; | |
| expected_data.max = expected_data.max_val + expected_data.bucket_size - 1; | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| expected_data.logs = 0; | |
| expected_data.samples = 0; | |
| // Populate storage with more data | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| val = values[i].value * values[i].numSamples; | |
| expected_data.sum += val; | |
| expected_data.squares += values[i].value * val; | |
| if (values[i].value < 0) { | |
| // Negative values don't have log, so mark log check to be skipped | |
| no_log = true; | |
| } else { | |
| expected_data.logs += | |
| std::log(values[i].value) * values[i].numSamples; | |
| } | |
| expected_data.samples += values[i].numSamples; | |
| } | |
| stor.prepare(¶ms, data); | |
| checkExpectedDistData(data, expected_data, no_log); | |
| } | |
| /** | |
| * Test samples that fit in the initial buckets, and therefore do not need | |
| * to grow up. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareFit) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. The final buckets | |
| // will be divided at: | |
| // Bkt0=[0,1[ , Bkt1=[1,2[, Bkt2=[2,3[, Bkt3=[3,4[ | |
| ValueSamples values[] = {{0, 5}, {1, 2}, {2, 99}, {3, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 1; | |
| expected_data.min = 0; | |
| expected_data.max_val = 3; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 5; | |
| expected_data.cvec[1] = 2; | |
| expected_data.cvec[2] = 99; | |
| expected_data.cvec[3] = 4; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that do not fit in the initial buckets, and therefore have | |
| * to grow up once. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareSingleGrowUp) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // are four buckets, and the highest value is 4, the bucket size will | |
| // grow to be 2. The final buckets will be divided at: | |
| // Bkt0=[0,2[ , Bkt1=[2,4[, Bkt2=[4,6[, Bkt3=[6,8[ | |
| ValueSamples values[] = {{0, 5}, {1, 2}, {2, 99}, {4, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 2; | |
| expected_data.min = 0; | |
| expected_data.max_val = 6; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 5+2; | |
| expected_data.cvec[1] = 99; | |
| expected_data.cvec[2] = 4; | |
| expected_data.cvec[3] = 0; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that do not fit in the initial buckets, and therefore have | |
| * to grow up a few times. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareMultipleGrowUp) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // are four buckets, and the highest value is 4, the bucket size will | |
| // grow thrice to become 8. The final buckets will be divided at: | |
| // Bkt0=[0,8[ , Bkt1=[8,16[, Bkt2=[16,24[, Bkt3=[24,32[ | |
| ValueSamples values[] = {{0, 5}, {1, 2}, {2, 99}, {16, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 8; | |
| expected_data.min = 0; | |
| expected_data.max_val = 24; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 5+2+99; | |
| expected_data.cvec[1] = 0; | |
| expected_data.cvec[2] = 4; | |
| expected_data.cvec[3] = 0; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that have a negative value, and therefore do not fit in the | |
| * initial buckets. Since this involves using negative values, the logs | |
| * become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareGrowDownOddBuckets) | |
| { | |
| statistics::HistStor::Params params(5); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // is a negative value, the min bucket will change, and the bucket size | |
| // will grow to be 2. The final buckets will be divided at: | |
| // Bkt0=[-4,-2[ , Bkt1=[-2,-0[, Bkt2=[0,2[, Bkt3=[2,4[, Bkt4=[4,6[ | |
| ValueSamples values[] = | |
| {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {4, 33}, {-1, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 2; | |
| expected_data.min = -4; | |
| expected_data.max_val = 4; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 0; | |
| expected_data.cvec[1] = 4; | |
| expected_data.cvec[2] = 5+2; | |
| expected_data.cvec[3] = 99+12; | |
| expected_data.cvec[4] = 33; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that have a negative value, and therefore do not fit in the | |
| * initial buckets. Since this involves using negative values, the logs | |
| * become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareGrowDownEvenBuckets) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // is a negative value, the min bucket will change, and the bucket size | |
| // will grow to be 2. The final buckets will be divided at: | |
| // Bkt0=[-4,-2[ , Bkt1=[-2,0[, Bkt2=[0,2[, Bkt3=[2,4[ | |
| ValueSamples values[] = {{0, 5}, {1, 2}, {2, 99}, {-1, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 2; | |
| expected_data.min = -4; | |
| expected_data.max_val = 2; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 0; | |
| expected_data.cvec[1] = 4; | |
| expected_data.cvec[2] = 5+2; | |
| expected_data.cvec[3] = 99; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that have one low negative value, and therefore do not fit | |
| * in the initial buckets and have to grow down a few times. Since this | |
| * involves using negative values, the logs become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareGrowDownGrowOutOddBuckets) | |
| { | |
| statistics::HistStor::Params params(5); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // is a negative value, the min bucket will change, and the bucket size | |
| // will grow to be 8. The final buckets will be divided at: | |
| // Bkt0=[-16,-8[ , Bkt1=[-8,0[, Bkt2=[0,8[, Bkt3=[8,16[, Bkt4=[16,24[ | |
| ValueSamples values[] = | |
| {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {4, 33}, {-12, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 8; | |
| expected_data.min = -16; | |
| expected_data.max_val = 16; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 4; | |
| expected_data.cvec[1] = 0; | |
| expected_data.cvec[2] = 5+2+99+12+33; | |
| expected_data.cvec[3] = 0; | |
| expected_data.cvec[4] = 0; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test samples that have one low negative value, and therefore do not fit | |
| * in the initial buckets and have to grow down a few times. Since this | |
| * involves using negative values, the logs become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareGrowDownGrowOutEvenBuckets) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. Since there | |
| // is a negative value, the min bucket will change, and the bucket size | |
| // will grow to be 8. The final buckets will be divided at: | |
| // Bkt0=[-16,-8[ , Bkt1=[-8,0[, Bkt2=[0,8[, Bkt3=[8,16[ | |
| ValueSamples values[] = | |
| {{0, 5}, {1, 2}, {2, 99}, {3, 12}, {-12, 4}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 8; | |
| expected_data.min = -16; | |
| expected_data.max_val = 8; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 4; | |
| expected_data.cvec[1] = 0; | |
| expected_data.cvec[2] = 5+2+99+12; | |
| expected_data.cvec[3] = 0; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test a complex sample set with negative values, and therefore multiple | |
| * grows will happen. Since this involves using negative values, the logs | |
| * become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareMultipleGrowOddBuckets) | |
| { | |
| statistics::HistStor::Params params(5); | |
| // Setup expected data for the hand-carved values given. This adds quite | |
| // a few positive and negative samples, and the bucket size will grow to | |
| // be 64. The final buckets will be divided at: | |
| // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[, | |
| // Bkt4=[128,192[ | |
| ValueSamples values[] = | |
| {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 64; | |
| expected_data.min = -128; | |
| expected_data.max_val = 128; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 53; | |
| expected_data.cvec[1] = 12+1; | |
| expected_data.cvec[2] = 5+2+99; | |
| expected_data.cvec[3] = 4; | |
| expected_data.cvec[4] = 0; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** | |
| * Test a complex sample set with negative values, and therefore multiple | |
| * grows will happen. Since this involves using negative values, the logs | |
| * become irrelevant. | |
| */ | |
| TEST(StatsHistStorTest, SamplePrepareMultipleGrowEvenBuckets) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup expected data for the hand-carved values given. This adds quite | |
| // a few positive and negative samples, and the bucket size will grow to | |
| // be 64. The final buckets will be divided at: | |
| // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[ | |
| ValueSamples values[] = | |
| {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 64; | |
| expected_data.min = -128; | |
| expected_data.max_val = 64; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 53; | |
| expected_data.cvec[1] = 12+1; | |
| expected_data.cvec[2] = 5+2+99; | |
| expected_data.cvec[3] = 4; | |
| prepareCheckHistStor(params, values, num_values, expected_data); | |
| } | |
| /** Test resetting storage. */ | |
| TEST(StatsHistStorTest, Reset) | |
| { | |
| statistics::HistStor::Params params(4); | |
| statistics::HistStor stor(¶ms); | |
| // Setup expected data for the hand-carved values given. This adds quite | |
| // a few positive and negative samples, and the bucket size will grow to | |
| // be 64. The final buckets will be divided at: | |
| // Bkt0=[-128,-64[ , Bkt1=[-64,0[, Bkt2=[0,64[, Bkt3=[64,128[ | |
| ValueSamples values[] = | |
| {{0, 5}, {7, 2}, {31, 99}, {-8, 12}, {127, 4}, {-120, 53}, {-50, 1}}; | |
| const int num_values = sizeof(values) / sizeof(ValueSamples); | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| } | |
| // Reset storage, and make sure all data has been cleared: | |
| // Bkt0=[0,1[ , Bkt1=[1,2[, Bkt2=[2,3[, Bkt3=[3,4[ | |
| stor.reset(¶ms); | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 1; | |
| expected_data.min = 0; | |
| expected_data.max_val = 3; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| prepareCheckHistStor(params, values, 0, expected_data); | |
| } | |
| #if TRACING_ON | |
| /** Test whether adding storages with different sizes triggers an assertion. */ | |
| TEST(StatsHistStorDeathTest, AddDifferentSize) | |
| { | |
| statistics::HistStor::Params params(4); | |
| statistics::HistStor stor(¶ms); | |
| statistics::HistStor::Params params2(5); | |
| statistics::HistStor stor2(¶ms2); | |
| ASSERT_DEATH(stor.add(&stor2), ".+"); | |
| } | |
| /** Test whether adding storages with different min triggers an assertion. */ | |
| TEST(StatsHistStorDeathTest, AddDifferentMin) | |
| { | |
| statistics::HistStor::Params params(4); | |
| statistics::HistStor stor(¶ms); | |
| stor.sample(-1, 3); | |
| // On creation, the storage's min is zero | |
| statistics::HistStor::Params params2(4); | |
| statistics::HistStor stor2(¶ms2); | |
| ASSERT_DEATH(stor.add(&stor2), ".+"); | |
| } | |
| #endif | |
| /** Test merging two histograms. */ | |
| TEST(StatsHistStorTest, Add) | |
| { | |
| statistics::HistStor::Params params(4); | |
| // Setup first storage. Buckets are: | |
| // Bkt0=[0,16[, Bkt1=[16,32[, Bkt2=[32,48[, Bkt3=[58,64[ | |
| statistics::HistStor stor(¶ms); | |
| ValueSamples values[] = {{0, 5}, {3, 2}, {20, 37}, {32, 18}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| } | |
| statistics::DistData data; | |
| stor.prepare(¶ms, data); | |
| // Setup second storage. Buckets are: | |
| // Bkt0=[0,32[, Bkt1=[32,64[, Bkt2=[64,96[, Bkt3=[96,128[ | |
| statistics::HistStor stor2(¶ms); | |
| ValueSamples values2[] = {{10, 10}, {0, 1}, {80, 4}, {17, 100}, {95, 79}}; | |
| int num_values2 = sizeof(values2) / sizeof(ValueSamples); | |
| for (int i = 0; i < num_values2; i++) { | |
| stor2.sample(values2[i].value, values2[i].numSamples); | |
| } | |
| statistics::DistData data2; | |
| stor2.prepare(¶ms, data2); | |
| // Perform the merge | |
| stor.add(&stor2); | |
| statistics::DistData merge_data; | |
| stor.prepare(¶ms, merge_data); | |
| // Setup expected data. Buckets are: | |
| // Bkt0=[0,32[, Bkt1=[32,64[, Bkt2=[64,96[, Bkt3=[96,128[ | |
| statistics::DistData expected_data; | |
| expected_data.type = statistics::Hist; | |
| expected_data.bucket_size = 32; | |
| expected_data.min = 0; | |
| expected_data.max = 127; | |
| expected_data.min_val = 0; | |
| expected_data.max_val = 96; | |
| expected_data.cvec.clear(); | |
| expected_data.cvec.resize(params.buckets); | |
| expected_data.cvec[0] = 5+2+37+10+1+100; | |
| expected_data.cvec[1] = 18; | |
| expected_data.cvec[2] = 4+79; | |
| expected_data.cvec[3] = 0; | |
| expected_data.sum = data.sum + data2.sum; | |
| expected_data.squares = data.squares + data2.squares; | |
| expected_data.logs = data.squares + data2.logs; | |
| expected_data.samples = data.samples + data2.samples; | |
| // Compare results | |
| checkExpectedDistData(merge_data, expected_data, false); | |
| } | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsSampleStorTest, ZeroReset) | |
| { | |
| statistics::SampleStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| stor.sample(val, num_samples); | |
| ASSERT_FALSE(stor.zero()); | |
| stor.reset(nullptr); | |
| ASSERT_TRUE(stor.zero()); | |
| } | |
| /** Test setting and getting value from storage. */ | |
| TEST(StatsSampleStorTest, SamplePrepare) | |
| { | |
| statistics::SampleStor stor(nullptr); | |
| ValueSamples values[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::Counter val; | |
| statistics::DistData data; | |
| statistics::DistData expected_data; | |
| statistics::SampleStor::Params params; | |
| // Simple test with one value being sampled | |
| stor.sample(values[0].value, values[0].numSamples); | |
| stor.prepare(¶ms, data); | |
| val = values[0].value * values[0].numSamples; | |
| expected_data.type = statistics::Deviation; | |
| expected_data.sum = val; | |
| expected_data.squares = values[0].value * val; | |
| expected_data.samples = values[0].numSamples; | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, expected_data.samples); | |
| // Reset storage, and make sure all data has been cleared | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| expected_data.samples = 0; | |
| stor.reset(nullptr); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, expected_data.samples); | |
| // Populate storage with more data | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| val = values[i].value * values[i].numSamples; | |
| expected_data.sum += val; | |
| expected_data.squares += values[i].value * val; | |
| expected_data.samples += values[i].numSamples; | |
| } | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, expected_data.samples); | |
| } | |
| /** The size is always 1, no matter which functions have been called. */ | |
| TEST(StatsSampleStorTest, Size) | |
| { | |
| statistics::SampleStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| statistics::DistData data; | |
| statistics::SampleStor::Params params; | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.sample(val, num_samples); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.reset(nullptr); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.zero(); | |
| ASSERT_EQ(stor.size(), 1); | |
| } | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsAvgSampleStorTest, ZeroReset) | |
| { | |
| statistics::AvgSampleStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| stor.sample(val, num_samples); | |
| ASSERT_FALSE(stor.zero()); | |
| stor.reset(nullptr); | |
| ASSERT_TRUE(stor.zero()); | |
| } | |
| /** Test setting and getting value from storage. */ | |
| TEST(StatsAvgSampleStorTest, SamplePrepare) | |
| { | |
| statistics::AvgSampleStor stor(nullptr); | |
| ValueSamples values[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::Counter val; | |
| statistics::DistData data; | |
| statistics::DistData expected_data; | |
| statistics::AvgSampleStor::Params params; | |
| // Simple test with one value being sampled | |
| stor.sample(values[0].value, values[0].numSamples); | |
| stor.prepare(¶ms, data); | |
| val = values[0].value * values[0].numSamples; | |
| expected_data.type = statistics::Deviation; | |
| expected_data.sum = val; | |
| expected_data.squares = values[0].value * val; | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, curTick()); | |
| increaseTick(); | |
| // Reset storage, and make sure all data has been cleared | |
| expected_data.sum = 0; | |
| expected_data.squares = 0; | |
| stor.reset(nullptr); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, curTick()); | |
| increaseTick(); | |
| // Populate storage with more data | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| val = values[i].value * values[i].numSamples; | |
| expected_data.sum += val; | |
| expected_data.squares += values[i].value * val; | |
| } | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(data.type, expected_data.type); | |
| ASSERT_EQ(data.sum, expected_data.sum); | |
| ASSERT_EQ(data.squares, expected_data.squares); | |
| ASSERT_EQ(data.samples, curTick()); | |
| } | |
| /** The size is always 1, no matter which functions have been called. */ | |
| TEST(StatsAvgSampleStorTest, Size) | |
| { | |
| statistics::AvgSampleStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| statistics::DistData data; | |
| statistics::AvgSampleStor::Params params; | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.sample(val, num_samples); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.prepare(¶ms, data); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.reset(nullptr); | |
| ASSERT_EQ(stor.size(), 1); | |
| stor.zero(); | |
| ASSERT_EQ(stor.size(), 1); | |
| } | |
| /** | |
| * Test whether zero is correctly set as the reset value. The test order is | |
| * to check if it is initially zero on creation, then it is made non zero, | |
| * and finally reset to zero. | |
| */ | |
| TEST(StatsSparseHistStorTest, ZeroReset) | |
| { | |
| statistics::SparseHistStor stor(nullptr); | |
| statistics::Counter val = 10; | |
| statistics::Counter num_samples = 5; | |
| ASSERT_TRUE(stor.zero()); | |
| stor.reset(nullptr); | |
| stor.sample(val, num_samples); | |
| ASSERT_FALSE(stor.zero()); | |
| stor.reset(nullptr); | |
| ASSERT_TRUE(stor.zero()); | |
| } | |
| /** Test setting and getting value from storage. */ | |
| TEST(StatsSparseHistStorTest, SamplePrepare) | |
| { | |
| statistics::SparseHistStor stor(nullptr); | |
| ValueSamples values[] = {{10, 5}, {1234, 2}, {0xFFFFFFFF, 18}}; | |
| int num_values = sizeof(values) / sizeof(ValueSamples); | |
| statistics::Counter total_samples; | |
| statistics::SparseHistData data; | |
| // Simple test with one value being sampled | |
| stor.sample(values[0].value, values[0].numSamples); | |
| stor.prepare(nullptr, data); | |
| ASSERT_EQ(stor.size(), 1); | |
| ASSERT_EQ(data.cmap.size(), 1); | |
| ASSERT_EQ(data.cmap[values[0].value], values[0].numSamples); | |
| ASSERT_EQ(data.samples, values[0].numSamples); | |
| // Reset storage, and make sure all data has been cleared | |
| stor.reset(nullptr); | |
| stor.prepare(nullptr, data); | |
| ASSERT_EQ(stor.size(), 0); | |
| ASSERT_EQ(data.cmap.size(), 0); | |
| ASSERT_EQ(data.samples, 0); | |
| // Populate storage with more data | |
| for (int i = 0; i < num_values; i++) { | |
| stor.sample(values[i].value, values[i].numSamples); | |
| } | |
| stor.prepare(nullptr, data); | |
| total_samples = 0; | |
| ASSERT_EQ(stor.size(), num_values); | |
| ASSERT_EQ(data.cmap.size(), num_values); | |
| for (int i = 0; i < num_values; i++) { | |
| ASSERT_EQ(data.cmap[values[i].value], values[i].numSamples); | |
| total_samples += values[i].numSamples; | |
| } | |
| ASSERT_EQ(data.samples, total_samples); | |
| } |