diff options
Diffstat (limited to 'src/addrcache_test.cc')
-rw-r--r-- | src/addrcache_test.cc | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/src/addrcache_test.cc b/src/addrcache_test.cc new file mode 100644 index 0000000..64b7169 --- /dev/null +++ b/src/addrcache_test.cc @@ -0,0 +1,634 @@ +// Copyright 2007 Google Inc. +// Author: Lincoln Smith +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <config.h> +#include "addrcache.h" +#include <limits.h> // INT_MAX, INT_MIN +#include <stdint.h> // uint32_t +#include <stdlib.h> // rand, srand +#include <iostream> +#include <string> +#include <vector> +#include "testing.h" +#include "varint_bigendian.h" +#include "vcdiff_defs.h" // RESULT_ERROR + +namespace open_vcdiff { +namespace { + +// Provides an address_stream_ buffer and functions to manually encode +// values into the buffer, and to manually decode and verify test results +// from the buffer. +// +class VCDiffAddressCacheTest : public testing::Test { + public: + typedef std::string string; + + VCDiffAddressCacheTest() : decode_position_(NULL), + decode_position_end_(NULL), + verify_encode_position_(NULL), + last_encode_size_(0), + last_decode_position_(NULL) { } + + virtual ~VCDiffAddressCacheTest() { } + + virtual void SetUp() { + EXPECT_TRUE(cache_.Init()); + } + + // Benchmarks for timing encode/decode operations + void BM_Setup(int test_size); + void BM_CacheEncode(int iterations, int test_size); + void BM_CacheDecode(int iterations, int test_size); + + protected: + virtual void TestBody() { } // to allow instantiation of this class + + void BeginDecode() { + decode_position_ = address_stream_.data(); + EXPECT_TRUE(decode_position_ != NULL); + last_decode_position_ = decode_position_; + decode_position_end_ = decode_position_ + address_stream_.size(); + } + + void ExpectEncodedSizeInBytes(int n) { + EXPECT_EQ(last_encode_size_ + n, address_stream_.size()); + last_encode_size_ = address_stream_.size(); + } + + void ExpectDecodedSizeInBytes(int n) { + EXPECT_EQ(last_decode_position_ + n, decode_position_); + last_decode_position_ = decode_position_; + } + + void ManualEncodeVarint(VCDAddress value) { + VarintBE<VCDAddress>::AppendToString(value, &address_stream_); + } + + void ManualEncodeByte(unsigned char byte) { + address_stream_.push_back(byte); + } + + void ExpectEncodedVarint(VCDAddress expected_value, int expected_size) { + if (!verify_encode_position_) { + verify_encode_position_ = address_stream_.data(); + } + EXPECT_EQ(expected_size, VarintBE<VCDAddress>::Length(expected_value)); + VCDAddress output_val = VarintBE<VCDAddress>::Parse( + address_stream_.data() + address_stream_.size(), + &verify_encode_position_); + EXPECT_EQ(expected_value, output_val); + } + + void ExpectEncodedByte(unsigned char expected_value) { + if (!verify_encode_position_) { + verify_encode_position_ = address_stream_.data(); + } + EXPECT_EQ(expected_value, *verify_encode_position_); + ++verify_encode_position_; + } + + void TestEncode(VCDAddress address, + VCDAddress here_address, + unsigned char mode, + int size) { + VCDAddress encoded_addr = 0; + EXPECT_EQ(mode, cache_.EncodeAddress(address, here_address, &encoded_addr)); + if (cache_.WriteAddressAsVarintForMode(mode)) { + ManualEncodeVarint(encoded_addr); + } else { + EXPECT_GT(256, encoded_addr); + ManualEncodeByte(static_cast<unsigned char>(encoded_addr)); + } + ExpectEncodedSizeInBytes(size); + } + + VCDiffAddressCache cache_; + string address_stream_; + const char* decode_position_; + const char* decode_position_end_; + string large_address_stream_; + std::vector<unsigned char> mode_stream_; + std::vector<VCDAddress> verify_stream_; + + private: + const char* verify_encode_position_; + string::size_type last_encode_size_; + const char* last_decode_position_; +}; + +#ifdef GTEST_HAS_DEATH_TEST +// This synonym is needed for the tests that use ASSERT_DEATH +typedef VCDiffAddressCacheTest VCDiffAddressCacheDeathTest; +#endif // GTEST_HAS_DEATH_TEST + +// Having either or both cache size == 0 is acceptable +TEST_F(VCDiffAddressCacheTest, ZeroCacheSizes) { + VCDiffAddressCache zero_cache(0, 0); + EXPECT_TRUE(zero_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, NegativeCacheSizes) { + VCDiffAddressCache negative_cache(-1, -1); // The constructor must not fail + EXPECT_FALSE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, OnlySameCacheSizeIsNegative) { + VCDiffAddressCache negative_cache(0, -1); // The constructor must not fail + EXPECT_FALSE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, ExtremePositiveCacheSizes) { + // The constructor must not fail + VCDiffAddressCache int_max_cache(INT_MAX, INT_MAX); + EXPECT_FALSE(int_max_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, ExtremeNegativeCacheSizes) { + // The constructor must not fail + VCDiffAddressCache int_min_cache(INT_MIN, INT_MIN); + EXPECT_FALSE(int_min_cache.Init()); +} + +// VCD_MAX_MODES is the maximum number of modes, including SAME and HERE modes. +// So neither the SAME cache nor the HERE cache can be larger than +// (VCD_MAX_MODES - 2). +TEST_F(VCDiffAddressCacheTest, NearCacheSizeIsTooBig) { + VCDiffAddressCache negative_cache(VCD_MAX_MODES - 1, 0); + EXPECT_FALSE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, SameCacheSizeIsTooBig) { + VCDiffAddressCache negative_cache(0, VCD_MAX_MODES - 1); + EXPECT_FALSE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, CombinedSizesAreTooBig) { + VCDiffAddressCache negative_cache((VCD_MAX_MODES / 2), + (VCD_MAX_MODES / 2) - 1); + EXPECT_FALSE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, MaxLegalNearCacheSize) { + VCDiffAddressCache negative_cache(VCD_MAX_MODES - 2, 0); + EXPECT_TRUE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, MaxLegalSameCacheSize) { + VCDiffAddressCache negative_cache(0, VCD_MAX_MODES - 2); + EXPECT_TRUE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, MaxLegalCombinedSizes) { + VCDiffAddressCache negative_cache((VCD_MAX_MODES / 2) - 1, + (VCD_MAX_MODES / 2) - 1); + EXPECT_TRUE(negative_cache.Init()); +} + +TEST_F(VCDiffAddressCacheTest, DestroyWithoutInitialization) { + VCDiffAddressCache no_init_cache(4, 3); + // Should be destroyed without crashing +} + +TEST_F(VCDiffAddressCacheTest, DestroyDefaultWithoutInitialization) { + VCDiffAddressCache no_init_cache; + // Should be destroyed without crashing +} + +TEST_F(VCDiffAddressCacheTest, CacheContentsInitiallyZero) { + VCDAddress test_address = 0; + // Check that caches are initially set to zero + for (test_address = 0; test_address < 4; ++test_address) { + EXPECT_EQ(0, cache_.NearAddress(test_address)); + } + for (test_address = 0; test_address < 256 * 3; ++test_address) { + EXPECT_EQ(0, cache_.SameAddress(test_address)); + } +} + +// Inserts values 1, 2, ... , 10 into the cache and tests its entire +// contents for consistency. +// +TEST_F(VCDiffAddressCacheTest, InsertFirstTen) { + VCDAddress test_address = 0; + for (test_address = 1; test_address <= 10; ++test_address) { + cache_.UpdateCache(test_address); + } + EXPECT_EQ(9, cache_.NearAddress(0)); // slot 0: 1 => 5 => 9 + EXPECT_EQ(10, cache_.NearAddress(1)); // slot 1: 2 => 6 => 10 + EXPECT_EQ(7, cache_.NearAddress(2)); // slot 2: 3 => 7 + EXPECT_EQ(8, cache_.NearAddress(3)); // slot 3: 4 => 8 + EXPECT_EQ(0, cache_.SameAddress(0)); + for (test_address = 1; test_address <= 10; ++test_address) { + EXPECT_EQ(test_address, cache_.SameAddress(test_address)); + } + for (test_address = 11; test_address < 256 * 3; ++test_address) { + EXPECT_EQ(0, cache_.SameAddress(test_address)); + } +} + +TEST_F(VCDiffAddressCacheTest, InsertIntMax) { + cache_.UpdateCache(INT_MAX); + EXPECT_EQ(INT_MAX, cache_.NearAddress(0)); + EXPECT_EQ(INT_MAX, cache_.SameAddress(INT_MAX % (256 * 3))); + EXPECT_EQ(0, cache_.SameAddress((INT_MAX - 256) % (256 * 3))); + EXPECT_EQ(0, cache_.SameAddress((INT_MAX - 512) % (256 * 3))); +} + +// Exercises all four addressing mode types by encoding five values +// with EncodeAddress. +// Checks to see that the proper mode was selected in each case, +// and that the encoding is correct. +// +TEST_F(VCDiffAddressCacheTest, EncodeAddressModes) { + TestEncode(0x0000FFFF, 0x10000000, VCD_SELF_MODE, 3); + TestEncode(0x10000000, 0x10000010, VCD_HERE_MODE, 1); + TestEncode(0x10000004, 0x10000020, cache_.FirstNearMode() + 0x01, 1); + TestEncode(0x0FFFFFFE, 0x10000030, VCD_HERE_MODE, 1); + TestEncode(0x10000004, 0x10000040, cache_.FirstSameMode() + 0x01, 1); + ExpectEncodedVarint(0xFFFF, 3); // SELF mode: addr 0x0000FFFF + ExpectEncodedVarint(0x10, 1); // HERE mode: here - 0x10 = 0x10000000 + ExpectEncodedVarint(0x04, 1); // NEAR cache #1: + // last addr + 0x4 = 0x10000004 + ExpectEncodedVarint(0x32, 1); // HERE mode: here - 0x32 = 0x0FFFFFFE + ExpectEncodedByte(0x04); // SAME cache #1: 0x10000004 hits +} + +// Exercises all four addressing mode types by manually encoding six values +// and calling DecodeAddress on each one. +// +TEST_F(VCDiffAddressCacheTest, DecodeAddressModes) { + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0x1000); + ManualEncodeByte(0xFE); // SAME mode uses a byte, not a Varint + ManualEncodeVarint(0xFE); + ManualEncodeVarint(0x1000); + BeginDecode(); + EXPECT_EQ(0xCAFE, + cache_.DecodeAddress(0x10000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + EXPECT_EQ(0x20000 - 0xCAFE, + cache_.DecodeAddress(0x20000, + VCD_HERE_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + EXPECT_EQ(0xDAFE, + cache_.DecodeAddress(0x30000, + cache_.FirstNearMode(), + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0x1000)); + EXPECT_EQ(0xCAFE, + cache_.DecodeAddress(0x40000, + cache_.FirstSameMode() + (0xCA % 3), + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(sizeof(unsigned char)); // a byte, not a Varint + EXPECT_EQ(0xFE, + cache_.DecodeAddress(0x50000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xFE)); + // NEAR mode #0 has been overwritten by fifth computed addr (wrap around) + EXPECT_EQ(0x10FE, + cache_.DecodeAddress(0x60000, + cache_.FirstNearMode(), + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0x1000)); +} + +// Test with both cache sizes == 0. The encoder should not choose +// a SAME or NEAR mode under these conditions. +TEST_F(VCDiffAddressCacheTest, EncodeAddressZeroCacheSizes) { + VCDAddress encoded_addr = 0; + VCDiffAddressCache zero_cache(0, 0); + EXPECT_TRUE(zero_cache.Init()); + EXPECT_EQ(VCD_SELF_MODE, + zero_cache.EncodeAddress(0x0000FFFF, 0x10000000, &encoded_addr)); + EXPECT_EQ(0xFFFF, encoded_addr); + EXPECT_EQ(VCD_HERE_MODE, + zero_cache.EncodeAddress(0x10000000, 0x10000010, &encoded_addr)); + EXPECT_EQ(0x10, encoded_addr); + EXPECT_EQ(VCD_HERE_MODE, + zero_cache.EncodeAddress(0x10000004, 0x10000020, &encoded_addr)); + EXPECT_EQ(0x1C, encoded_addr); + EXPECT_EQ(VCD_HERE_MODE, + zero_cache.EncodeAddress(0x0FFFFFFE, 0x10000030, &encoded_addr)); + EXPECT_EQ(0x32, encoded_addr); + EXPECT_EQ(VCD_HERE_MODE, + zero_cache.EncodeAddress(0x10000004, 0x10000040, &encoded_addr)); + EXPECT_EQ(0x3C, encoded_addr); +} + +TEST_F(VCDiffAddressCacheTest, DecodeAddressZeroCacheSizes) { + VCDiffAddressCache zero_cache(0, 0); + EXPECT_TRUE(zero_cache.Init()); + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0xDAFE); + BeginDecode(); + EXPECT_EQ(0xCAFE, zero_cache.DecodeAddress(0x10000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + EXPECT_EQ(0x20000 - 0xCAFE, zero_cache.DecodeAddress(0x20000, + VCD_HERE_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + EXPECT_EQ(0xDAFE, zero_cache.DecodeAddress(0x30000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xDAFE)); +} + +#ifdef GTEST_HAS_DEATH_TEST +TEST_F(VCDiffAddressCacheDeathTest, EncodeNegativeAddress) { + VCDAddress dummy_encoded_address = 0; + EXPECT_DEBUG_DEATH(cache_.EncodeAddress(-1, -1, &dummy_encoded_address), + "negative"); +} + +TEST_F(VCDiffAddressCacheDeathTest, EncodeAddressPastHereAddress) { + VCDAddress dummy_encoded_address = 0; + EXPECT_DEBUG_DEATH(cache_.EncodeAddress(0x100, 0x100, &dummy_encoded_address), + "address.*<.*here_address"); + EXPECT_DEBUG_DEATH(cache_.EncodeAddress(0x200, 0x100, &dummy_encoded_address), + "address.*<.*here_address"); +} + +TEST_F(VCDiffAddressCacheDeathTest, DecodeInvalidMode) { + ManualEncodeVarint(0xCAFE); + BeginDecode(); + EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR, + cache_.DecodeAddress(0x10000000, + cache_.LastMode() + 1, + &decode_position_, + decode_position_end_)), + "mode"); + EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR, + cache_.DecodeAddress(0x10000000, + 0xFF, + &decode_position_, + decode_position_end_)), + "mode"); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ +} + +TEST_F(VCDiffAddressCacheDeathTest, DecodeZeroOrNegativeHereAddress) { + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0xCAFE); + BeginDecode(); + // Using a Debug build, the check will fail; using a Release build, + // the check will not occur, and the SELF mode does not depend on + // the value of here_address, so DecodeAddress() will succeed. + EXPECT_DEBUG_DEATH(cache_.DecodeAddress(-1, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_), + "negative"); + // A zero value for here_address should not kill the decoder, + // but instead should return an error value. A delta file may contain + // a window that has no source segment and that (erroneously) + // uses a COPY instruction as its first instruction. This should + // cause an error to be reported, not a debug check failure. + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); +} +#endif // GTEST_HAS_DEATH_TEST + +TEST_F(VCDiffAddressCacheTest, DecodeAddressPastHereAddress) { + ManualEncodeVarint(0xCAFE); + BeginDecode(); + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x1000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ +} + +TEST_F(VCDiffAddressCacheTest, HereModeAddressTooLarge) { + ManualEncodeVarint(0x10001); // here_address + 1 + BeginDecode(); + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000, + VCD_HERE_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ +} + +TEST_F(VCDiffAddressCacheTest, NearModeAddressOverflow) { + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(0x7FFFFFFF); + BeginDecode(); + EXPECT_EQ(0xCAFE, cache_.DecodeAddress(0x10000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + // Now decode a NEAR mode address of base address 0xCAFE + // (the first decoded address) + offset 0x7FFFFFFF. This will cause + // an integer overflow and should signal an error. + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000000, + cache_.FirstNearMode(), + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ +} + +// A Varint should contain at most 9 bytes that have their continuation bit +// (the uppermost, or 7 bit) set. A longer string of bytes that all have +// bit 7 set is not a valid Varint. Try to parse such a string as a Varint +// and confirm that it does not run off the end of the input buffer and +// it returns an error value (RESULT_ERROR). +// +TEST_F(VCDiffAddressCacheTest, DecodeInvalidVarint) { + address_stream_.clear(); + // Write 512 0xFE bytes + address_stream_.append(512, static_cast<char>(0xFE)); + BeginDecode(); + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ +} + +// If only part of a Varint appears in the data to be decoded, +// then DecodeAddress should return RESULT_END_OF_DATA, +// which means that the Varint *may* be valid if there is more +// data expected to be returned. +// +TEST_F(VCDiffAddressCacheTest, DecodePartialVarint) { + address_stream_.clear(); + ManualEncodeByte(0xFE); + ManualEncodeByte(0xFE); + ManualEncodeByte(0xFE); + BeginDecode(); + EXPECT_EQ(RESULT_END_OF_DATA, + cache_.DecodeAddress(0x10000000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); // Should not modify decode_position_ + // Now add the missing last byte (supposedly read from a stream of data) + // and verify that the Varint is now valid. + ManualEncodeByte(0x01); // End the Varint with an additional byte + BeginDecode(); // Reset read position to start of data + EXPECT_EQ(0xFDFBF01, + cache_.DecodeAddress(0x10000000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(4); // ManualEncodeByte was called for 4 byte values +} + +#ifdef GTEST_HAS_DEATH_TEST +TEST_F(VCDiffAddressCacheDeathTest, DecodeBadMode) { + ManualEncodeVarint(0xCAFE); + BeginDecode(); + EXPECT_DEBUG_DEATH(EXPECT_EQ(RESULT_ERROR, + cache_.DecodeAddress(0x10000, + cache_.LastMode() + 1, + &decode_position_, + decode_position_end_)), + "maximum"); + ExpectDecodedSizeInBytes(0); +} +#endif // GTEST_HAS_DEATH_TEST + +TEST_F(VCDiffAddressCacheTest, DecodeInvalidHereAddress) { + ManualEncodeVarint(0x10001); // offset larger than here_address + BeginDecode(); + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000, + VCD_HERE_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); +} + +TEST_F(VCDiffAddressCacheTest, DecodeInvalidNearAddress) { + ManualEncodeVarint(0xCAFE); + ManualEncodeVarint(INT_MAX); // offset will cause integer overflow + BeginDecode(); + EXPECT_EQ(0xCAFE, + cache_.DecodeAddress(0x10000, + VCD_SELF_MODE, + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(VarintBE<VCDAddress>::Length(0xCAFE)); + EXPECT_EQ(RESULT_ERROR, cache_.DecodeAddress(0x10000, + cache_.FirstNearMode(), + &decode_position_, + decode_position_end_)); + ExpectDecodedSizeInBytes(0); +} + +void VCDiffAddressCacheTest::BM_Setup(int test_size) { + mode_stream_.resize(test_size); + verify_stream_.resize(test_size); + VCDAddress here_address = 1; + srand(1); + for (int i = 0; i < test_size; ++i) { + verify_stream_[i] = PortableRandomInRange(here_address - 1); + here_address += 4; + } + BM_CacheEncode(1, test_size); // populate large_address_stream_, mode_stream_ +} + +void VCDiffAddressCacheTest::BM_CacheEncode(int iterations, int test_size) { + VCDAddress here_address = 1; + VCDAddress encoded_addr = 0; + for (int test_iteration = 0; test_iteration < iterations; ++test_iteration) { + cache_.Init(); + large_address_stream_.clear(); + here_address = 1; + for (int i = 0; i < test_size; ++i) { + const unsigned char mode = cache_.EncodeAddress(verify_stream_[i], + here_address, + &encoded_addr); + if (cache_.WriteAddressAsVarintForMode(mode)) { + VarintBE<VCDAddress>::AppendToString(encoded_addr, + &large_address_stream_); + } else { + EXPECT_GT(256, encoded_addr); + large_address_stream_.push_back( + static_cast<unsigned char>(encoded_addr)); + } + mode_stream_[i] = mode; + here_address += 4; + } + } +} + +void VCDiffAddressCacheTest::BM_CacheDecode(int iterations, int test_size) { + VCDAddress here_address = 1; + for (int test_iteration = 0; test_iteration < iterations; ++test_iteration) { + cache_.Init(); + const char* large_decode_pointer = large_address_stream_.data(); + const char* const end_of_encoded_data = + large_decode_pointer + large_address_stream_.size(); + here_address = 1; + for (int i = 0; i < test_size; ++i) { + EXPECT_EQ(verify_stream_[i], + cache_.DecodeAddress(here_address, + mode_stream_[i], + &large_decode_pointer, + end_of_encoded_data)); + here_address += 4; + } + EXPECT_EQ(end_of_encoded_data, large_decode_pointer); + } +} + +TEST_F(VCDiffAddressCacheTest, PerformanceTest) { + const int test_size = 20 * 1024; // 20K random encode/decode operations + const int num_iterations = 40; // run test 40 times and take average + BM_Setup(test_size); + { + CycleTimer encode_timer; + encode_timer.Start(); + BM_CacheEncode(num_iterations, test_size); + encode_timer.Stop(); + double encode_time_in_ms = + static_cast<double>(encode_timer.GetInUsec()) / 1000; + std::cout << "Time to encode: " + << (encode_time_in_ms / num_iterations) << " ms" << std::endl; + } + { + CycleTimer decode_timer; + decode_timer.Start(); + BM_CacheDecode(num_iterations, test_size); + decode_timer.Stop(); + double decode_time_in_ms = + static_cast<double>(decode_timer.GetInUsec()) / 1000; + std::cout << "Time to decode: " + << (decode_time_in_ms / num_iterations) << " ms" << std::endl; + } +} + +} // unnamed namespace +} // namespace open_vcdiff |