diff options
Diffstat (limited to 'testing')
-rw-r--r-- | testing/Makefile | 8 | ||||
-rw-r--r-- | testing/checksum_test.cc | 756 | ||||
-rw-r--r-- | testing/checksum_test_c.c | 174 | ||||
-rw-r--r-- | testing/delta.h | 38 | ||||
-rw-r--r-- | testing/file.h | 51 | ||||
-rw-r--r-- | testing/modify.h | 12 | ||||
-rw-r--r-- | testing/random.h | 2 | ||||
-rw-r--r-- | testing/regtest.cc | 573 | ||||
-rwxr-xr-x | testing/run_release.sh | 2 | ||||
-rw-r--r-- | testing/sizes.h | 19 | ||||
-rw-r--r-- | testing/test.h | 10 |
11 files changed, 212 insertions, 1433 deletions
diff --git a/testing/Makefile b/testing/Makefile deleted file mode 100644 index d0b9c9e..0000000 --- a/testing/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: - (cd .. && make all) - -xdelta3regtest: - (cd .. && make xdelta3regtest) - -xdelta3checksum: - (cd .. && make xdelta3checksum) diff --git a/testing/checksum_test.cc b/testing/checksum_test.cc deleted file mode 100644 index 9418d24..0000000 --- a/testing/checksum_test.cc +++ /dev/null @@ -1,756 +0,0 @@ -/* Copyright (C) 2007 Josh MacDonald */ - -#include "test.h" -#include <assert.h> -#include <list> -#include <vector> -#include <algorithm> - -#include "../cpp-btree/btree_map.h" - -extern "C" { -uint32_t xd3_large32_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); -uint32_t xd3_large32_cksum_update_old (xd3_hash_cfg *cfg, uint32_t cksum, - const uint8_t *base, const usize_t look); - -uint64_t xd3_large64_cksum_old (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look); -uint64_t xd3_large64_cksum_update_old (xd3_hash_cfg *cfg, uint64_t cksum, - const uint8_t *base, const usize_t look); -} - -using btree::btree_map; -using std::list; -using std::vector; - -// MLCG parameters -// a, a* -uint32_t good_32bit_values[] = { - 1597334677U, // ... - 741103597U, 887987685U, -}; - -// a, a* -uint64_t good_64bit_values[] = { - 1181783497276652981ULL, 4292484099903637661ULL, - 7664345821815920749ULL, // ... -}; - -void print_header() { - static int hdr_cnt = 0; - if (hdr_cnt++ % 20 == 0) { - printf("%-32sConf\t\tCount\tUniq\tFull\tCover\tColls" - "\tMB/s\tIters\t#Colls\n", "Name"); - } -} - -struct true_type { }; -struct false_type { }; - -template <typename Word> -usize_t bitsof(); - -template<> -usize_t bitsof<unsigned int>() { - return sizeof(unsigned int) * 8; -} - -template<> -usize_t bitsof<unsigned long>() { - return sizeof(unsigned long) * 8; -} - -template<> -usize_t bitsof<unsigned long long>() { - return sizeof(unsigned long long) * 8; -} - -template <typename Word> -struct hhash { // shift "s" bits leaving the high bits as a hash value for - // this checksum, which are the most "distant" in terms of the - // spectral test for the rabin_karp MLCG. For short windows, - // the high bits aren't enough, XOR "mask" worth of these in. - Word operator()(const Word t, const Word s, const Word mask) { - return (t >> s) ^ (t & mask); - } -}; - -template <typename Word> -Word good_word(); - -template<> -uint32_t good_word<uint32_t>() { - return good_32bit_values[0]; -} - -template<> -uint64_t good_word<uint64_t>() { - return good_64bit_values[0]; -} - -// CLASSES - -#define SELF Word, CksumSize, CksumSkip, Hash, Compaction -#define MEMBER template <typename Word, \ - int CksumSize, \ - int CksumSkip, \ - typename Hash, \ - int Compaction> - -MEMBER -struct cksum_params { - typedef Word word_type; - typedef Hash hash_type; - - static const int cksum_size = CksumSize; - static const int cksum_skip = CksumSkip; - static const int compaction = Compaction; -}; - -MEMBER -struct rabin_karp : public cksum_params<SELF> { - // (a^cksum_size-1 c_0) + (a^cksum_size-2 c_1) ... - rabin_karp() - : powers(make_powers()), - product(powers[0] * good_word<Word>()), - incr_state(0) { } - - static Word* make_powers() { - Word *p = new Word[CksumSize]; - p[CksumSize - 1] = 1; - for (int i = CksumSize - 2; i >= 0; i--) { - p[i] = p[i + 1] * good_word<Word>(); - } - return p; - } - - ~rabin_karp() { - delete [] powers; - } - - Word step(const uint8_t *ptr) { - Word h = 0; - for (int i = 0; i < CksumSize; i++) { - h += (ptr[i]) * powers[i]; - } - return h; - } - - Word state0(const uint8_t *ptr) { - incr_state = step(ptr); - return incr_state; - } - - Word incr(const uint8_t *ptr) { - incr_state = good_word<Word>() * incr_state - - product * (ptr[-1]) + (ptr[CksumSize - 1]); - return incr_state; - } - - const Word *const powers; - const Word product; - Word incr_state; -}; - -MEMBER -struct with_stream : public cksum_params<SELF> { - xd3_stream stream; - - with_stream() - { - xd3_config cfg; - memset (&stream, 0, sizeof (stream)); - xd3_init_config (&cfg, 0); - cfg.smatch_cfg = XD3_SMATCH_SOFT; - cfg.smatcher_soft.large_look = CksumSize; - cfg.smatcher_soft.large_step = CksumSkip; - cfg.smatcher_soft.small_look = 4; - cfg.smatcher_soft.small_chain = 4; - cfg.smatcher_soft.small_lchain = 4; - cfg.smatcher_soft.max_lazy = 4; - cfg.smatcher_soft.long_enough = 4; - CHECK_EQ(0, xd3_config_stream (&stream, &cfg)); - - CHECK_EQ(0, xd3_size_hashtable (&stream, - 1<<10 /* ignored */, - stream.smatcher.large_look, - & stream.large_hash)); - } - ~with_stream() - { - xd3_free_stream (&stream); - } -}; - -MEMBER -struct large_cksum : public with_stream<SELF> { - Word step(const uint8_t *ptr) { - return xd3_large_cksum (&this->stream.large_hash, ptr, CksumSize); - } - - Word state0(const uint8_t *ptr) { - incr_state = step(ptr); - return incr_state; - } - - Word incr(const uint8_t *ptr) { - incr_state = xd3_large_cksum_update (&this->stream.large_hash, - incr_state, ptr - 1, CksumSize); - return incr_state; - } - - Word incr_state; -}; - -#if SIZEOF_USIZE_T == 4 -#define xd3_large_cksum_old xd3_large32_cksum_old -#define xd3_large_cksum_update_old xd3_large32_cksum_update_old -#elif SIZEOF_USIZE_T == 8 -#define xd3_large_cksum_old xd3_large64_cksum_old -#define xd3_large_cksum_update_old xd3_large64_cksum_update_old -#endif - -MEMBER -struct large_cksum_old : public with_stream<SELF> { - Word step(const uint8_t *ptr) { - return xd3_large_cksum_old (&this->stream.large_hash, ptr, CksumSize); - } - - Word state0(const uint8_t *ptr) { - incr_state = step(ptr); - return incr_state; - } - - Word incr(const uint8_t *ptr) { - incr_state = xd3_large_cksum_update_old (&this->stream.large_hash, - incr_state, ptr - 1, CksumSize); - return incr_state; - } - - Word incr_state; -}; - -// TESTS - -template <typename Word> -struct file_stats { - typedef const uint8_t* ptr_type; - typedef Word word_type; - typedef btree::btree_multimap<word_type, ptr_type> table_type; - typedef typename table_type::iterator table_iterator; - - usize_t cksum_size; - usize_t cksum_skip; - usize_t unique; - usize_t unique_values; - usize_t count; - table_type table; - - file_stats(usize_t size, usize_t skip) - : cksum_size(size), - cksum_skip(skip), - unique(0), - unique_values(0), - count(0) { - } - - void reset() { - unique = 0; - unique_values = 0; - count = 0; - table.clear(); - } - - void update(word_type word, ptr_type ptr) { - table_iterator t_i = table.find(word); - - count++; - if (t_i != table.end()) { - int collisions = 0; - for (table_iterator p_i = t_i; - p_i != table.end() && p_i->first == word; - ++p_i) { - if (memcmp(p_i->second, ptr, cksum_size) == 0) { - return; - } - collisions++; - } - if (collisions >= 1000) { - fprintf(stderr, "Something is not right, lots of collisions=%d\n", - collisions); - abort(); - } - } else { - unique_values++; - } - unique++; - table.insert(std::make_pair(word, ptr)); - return; - } - - void freeze() { - table.clear(); - } -}; - -struct test_result_base; - -static vector<test_result_base*> all_tests; - -struct test_result_base { - virtual ~test_result_base() { - } - virtual void reset() = 0; - virtual void print() = 0; - virtual void get(const uint8_t* buf, const size_t buf_size, - usize_t iters) = 0; - virtual void stat() = 0; - virtual usize_t count() = 0; - virtual usize_t dups() = 0; - virtual double uniqueness() = 0; - virtual double fullness() = 0; - virtual double collisions() = 0; - virtual double coverage() = 0; - virtual double compression() = 0; - virtual double time() = 0; - virtual double total_time() = 0; - virtual usize_t total_count() = 0; - virtual usize_t total_dups() = 0; -}; - -template <typename Checksum> -struct test_result : public test_result_base { - Checksum cksum; - const char *test_name; - file_stats<typename Checksum::word_type> fstats; - usize_t test_size; - usize_t n_steps; - usize_t n_incrs; - typename Checksum::word_type s_bits; - typename Checksum::word_type s_mask; - usize_t t_entries; - usize_t h_bits; - usize_t h_buckets_full; - char *hash_table; - long accum_millis; - usize_t accum_iters; - - // These are not reset - double accum_time; - usize_t accum_count; - usize_t accum_dups; - usize_t accum_colls; - size_t accum_size; - - test_result(const char *name) - : test_name(name), - fstats(Checksum::cksum_size, Checksum::cksum_skip), - hash_table(NULL), - accum_millis(0), - accum_iters(0), - accum_time(0.0), - accum_count(0), - accum_dups(0), - accum_colls(0), - accum_size(0) { - all_tests.push_back(this); - } - - ~test_result() { - reset(); - } - - void reset() { - // size of file - test_size = 0; - - // count - n_steps = 0; - n_incrs = 0; - - // four values used by new_table()/summarize_table() - s_bits = 0; - s_mask = 0; - t_entries = 0; - h_bits = 0; - h_buckets_full = 0; - - accum_millis = 0; - accum_iters = 0; - - fstats.reset(); - - // temporary - if (hash_table) { - delete(hash_table); - hash_table = NULL; - } - } - - usize_t count() { - if (Checksum::cksum_skip == 1) { - return n_incrs; - } else { - return n_steps; - } - } - - usize_t dups() { - return fstats.count - fstats.unique; - } - - /* Fraction of distinct strings of length cksum_size which are not - * represented in the hash table. */ - double collisions() { - return (fstats.unique - fstats.unique_values) / (double) fstats.unique; - } - usize_t colls() { - return (fstats.unique - fstats.unique_values); - } - - double uniqueness() { - return 1.0 - (double) dups() / count(); - } - - double fullness() { - return (double) h_buckets_full / (1 << h_bits); - } - - double coverage() { - return (double) h_buckets_full / uniqueness() / count(); - } - - double compression() { - return 1.0 - coverage(); - } - - double time() { - return (double) accum_millis / accum_iters; - } - - double total_time() { - return accum_time; - } - - usize_t total_count() { - return accum_count; - } - - usize_t total_dups() { - return accum_dups; - } - - usize_t total_colls() { - return accum_dups; - } - - void stat() { - accum_time += time(); - accum_count += count(); - accum_dups += dups(); - accum_colls += colls(); - accum_size += test_size; - } - - void print() { - if (fstats.count != count()) { - fprintf(stderr, "internal error: %" W "d != %" W "d\n", fstats.count, count()); - abort(); - } - print_header(); - printf("%-32s%d/%d 2^%" W "u\t%" W "u\t%0.4f\t%.4f\t%.4f\t%.1e\t%.2f\t" - "%" W "u\t%" W "u\n", - test_name, - Checksum::cksum_size, - Checksum::cksum_skip, - h_bits, - count(), - uniqueness(), - fullness(), - coverage(), - collisions(), - 0.001 * accum_iters * test_size / accum_millis, - accum_iters, - colls()); - } - - usize_t size_log2 (usize_t slots) { - usize_t bits = bitsof<typename Checksum::word_type>() - 1; - usize_t i; - - for (i = 3; i <= bits; i += 1) { - if (slots <= (1U << i)) { - return i - Checksum::compaction; - } - } - - return bits; - } - - void new_table(usize_t entries) { - t_entries = entries; - h_bits = size_log2(entries); - - usize_t n = 1 << h_bits; - - s_bits = bitsof<typename Checksum::word_type>() - h_bits; - s_mask = n - 1U; - - hash_table = new char[n / 8]; - memset(hash_table, 0, n / 8); - } - - int get_table_bit(usize_t i) { - return hash_table[i/8] & (1 << i%8); - } - - int set_table_bit(usize_t i) { - return hash_table[i/8] |= (1 << i%8); - } - - void summarize_table() { - usize_t n = 1 << h_bits; - usize_t f = 0; - for (usize_t i = 0; i < n; i++) { - if (get_table_bit(i)) { - f++; - } - } - h_buckets_full = f; - } - - void get(const uint8_t* buf, const size_t buf_size, usize_t test_iters) { - typename Checksum::hash_type hash; - const uint8_t *ptr; - const uint8_t *end; - usize_t periods; - int64_t last_offset; - int64_t stop; - - test_size = buf_size; - last_offset = buf_size - Checksum::cksum_size; - - if (last_offset < 0) { - periods = 0; - n_steps = 0; - n_incrs = 0; - stop = -Checksum::cksum_size; - } else { - periods = last_offset / Checksum::cksum_skip; - n_steps = periods + 1; - n_incrs = last_offset + 1; - stop = last_offset - (periods + 1) * Checksum::cksum_skip; - } - - // Compute file stats once. - if (fstats.unique_values == 0) { - if (Checksum::cksum_skip == 1) { - for (size_t i = 0; i <= buf_size - Checksum::cksum_size; i++) { - fstats.update(hash(cksum.step(buf + i), s_bits, s_mask), buf + i); - } - } else { - ptr = buf + last_offset; - end = buf + stop; - - for (; ptr != end; ptr -= Checksum::cksum_skip) { - fstats.update(hash(cksum.step(ptr), s_bits, s_mask), ptr); - } - } - fstats.freeze(); - } - - long start_test = get_millisecs_now(); - - if (Checksum::cksum_skip != 1) { - new_table(n_steps); - - for (usize_t i = 0; i < test_iters; i++) { - ptr = buf + last_offset; - end = buf + stop; - - for (; ptr != end; ptr -= Checksum::cksum_skip) { - set_table_bit(hash(cksum.step(ptr), s_bits, s_mask)); - } - } - - summarize_table(); - } - - stop = buf_size - Checksum::cksum_size + 1; - if (stop < 0) { - stop = 0; - } - - if (Checksum::cksum_skip == 1) { - new_table(n_incrs); - - for (usize_t i = 0; i < test_iters; i++) { - ptr = buf; - end = buf + stop; - - if (ptr != end) { - set_table_bit(hash(cksum.state0(ptr++), s_bits, s_mask)); - } - - for (; ptr != end; ptr++) { - typename Checksum::word_type w = cksum.incr(ptr); - CHECK_EQ(w, cksum.step(ptr)); - set_table_bit(hash(w, s_bits, s_mask)); - } - } - - summarize_table(); - } - - accum_iters += test_iters; - accum_millis += get_millisecs_now() - start_test; - } -}; - -static int read_whole_file(const char *name, - uint8_t **buf_ptr, - size_t *buf_len) { - main_file file; - int ret; - xoff_t len; - size_t nread; - main_file_init(&file); - file.filename = name; - ret = main_file_open(&file, name, XO_READ); - if (ret != 0) { - fprintf(stderr, "open failed\n"); - goto exit; - } - ret = main_file_stat(&file, &len); - if (ret != 0) { - fprintf(stderr, "stat failed\n"); - goto exit; - } - - (*buf_len) = (size_t)len; - (*buf_ptr) = (uint8_t*) main_malloc(*buf_len); - ret = main_file_read(&file, *buf_ptr, *buf_len, &nread, - "read failed"); - if (ret == 0 && *buf_len == nread) { - ret = 0; - } else { - fprintf(stderr, "invalid read\n"); - ret = XD3_INTERNAL; - } - exit: - main_file_cleanup(&file); - return ret; -} - -int main(int argc, char** argv) { - int i; - uint8_t *buf = NULL; - size_t buf_len = 0; - int ret; - - if (argc <= 1) { - fprintf(stderr, "usage: %s file ...\n", argv[0]); - return 1; - } - -// TODO: The xdelta3-hash.h code is identical now; add sameness test. -// using rabin_karp<> template. -#define TEST(T,Z,S,C) \ - test_result<large_cksum<T,Z,S,hhash<T>,C>> \ - _xck_ ## T ## _ ## Z ## _ ## S ## _ ## C \ - ("xck_" #T "_" #Z "_" #S "_" #C); \ - test_result<large_cksum_old<T,Z,S,hhash<T>,C>> \ - _old_ ## T ## _ ## Z ## _ ## S ## _ ## C \ - ("old_" #T "_" #Z "_" #S "_" #C) - -#define TESTS(SIZE, SKIP) \ - TEST(usize_t, SIZE, SKIP, 1); \ - TEST(usize_t, SIZE, SKIP, 2) - - TESTS(5, 1); - TESTS(6, 1); - TESTS(7, 1); - TESTS(8, 1); - TESTS(9, 1); - TESTS(10, 1); - TESTS(11, 1); - TESTS(12, 1); - TESTS(13, 1); - TESTS(14, 1); - TESTS(15, 1); - TESTS(16, 1); - TESTS(17, 1); - TESTS(18, 1); - TESTS(19, 1); - TESTS(20, 1); - TESTS(21, 1); - TESTS(22, 1); - TESTS(23, 1); - TESTS(24, 1); - TESTS(25, 1); - TESTS(26, 1); - TESTS(27, 1); - TESTS(28, 1); - TESTS(29, 1); - TESTS(30, 1); - TESTS(31, 1); - TESTS(32, 1); - TESTS(33, 1); - TESTS(34, 1); - TESTS(35, 1); - TESTS(36, 1); - TESTS(37, 1); - TESTS(38, 1); - TESTS(39, 1); - - - for (i = 1; i < argc; i++) { - if ((ret = read_whole_file(argv[i], - & buf, - & buf_len))) { - return 1; - } - - fprintf(stderr, "file %s is %zu bytes\n", - argv[i], buf_len); - - double min_time = -1.0; - double min_compression = 0.0; - - for (vector<test_result_base*>::iterator iter = all_tests.begin(); - iter != all_tests.end(); ++iter) { - test_result_base *test = *iter; - test->reset(); - - usize_t iters = 1; - long start_test = get_millisecs_now(); - - do { - test->get(buf, buf_len, iters); - iters *= 3; - iters /= 2; - } while (get_millisecs_now() - start_test < 2000); - - test->stat(); - - if (min_time < 0.0) { - min_compression = test->compression(); - min_time = test->time(); - } - - if (min_time > test->time()) { - min_time = test->time(); - } - - if (min_compression > test->compression()) { - min_compression = test->compression(); - } - - test->print(); - } - - main_free(buf); - buf = NULL; - } - - return 0; -} diff --git a/testing/checksum_test_c.c b/testing/checksum_test_c.c deleted file mode 100644 index 8f0507a..0000000 --- a/testing/checksum_test_c.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "../xdelta3.c" - -// OLD CHECKSUM CODE - -#define PERMUTE32(x) (__single_hash32[x]) -#define PERMUTE64(x) (__single_hash64[x]) - -const uint16_t __single_hash32[256] = -{ - /* This hashes the input alphabet (Scheme SLIB pseudo-random). */ - 0xbcd1, 0xbb65, 0x42c2, 0xdffe, 0x9666, 0x431b, 0x8504, 0xeb46, - 0x6379, 0xd460, 0xcf14, 0x53cf, 0xdb51, 0xdb08, 0x12c8, 0xf602, - 0xe766, 0x2394, 0x250d, 0xdcbb, 0xa678, 0x02af, 0xa5c6, 0x7ea6, - 0xb645, 0xcb4d, 0xc44b, 0xe5dc, 0x9fe6, 0x5b5c, 0x35f5, 0x701a, - 0x220f, 0x6c38, 0x1a56, 0x4ca3, 0xffc6, 0xb152, 0x8d61, 0x7a58, - 0x9025, 0x8b3d, 0xbf0f, 0x95a3, 0xe5f4, 0xc127, 0x3bed, 0x320b, - 0xb7f3, 0x6054, 0x333c, 0xd383, 0x8154, 0x5242, 0x4e0d, 0x0a94, - 0x7028, 0x8689, 0x3a22, 0x0980, 0x1847, 0xb0f1, 0x9b5c, 0x4176, - 0xb858, 0xd542, 0x1f6c, 0x2497, 0x6a5a, 0x9fa9, 0x8c5a, 0x7743, - 0xa8a9, 0x9a02, 0x4918, 0x438c, 0xc388, 0x9e2b, 0x4cad, 0x01b6, - 0xab19, 0xf777, 0x365f, 0x1eb2, 0x091e, 0x7bf8, 0x7a8e, 0x5227, - 0xeab1, 0x2074, 0x4523, 0xe781, 0x01a3, 0x163d, 0x3b2e, 0x287d, - 0x5e7f, 0xa063, 0xb134, 0x8fae, 0x5e8e, 0xb7b7, 0x4548, 0x1f5a, - 0xfa56, 0x7a24, 0x900f, 0x42dc, 0xcc69, 0x02a0, 0x0b22, 0xdb31, - 0x71fe, 0x0c7d, 0x1732, 0x1159, 0xcb09, 0xe1d2, 0x1351, 0x52e9, - 0xf536, 0x5a4f, 0xc316, 0x6bf9, 0x8994, 0xb774, 0x5f3e, 0xf6d6, - 0x3a61, 0xf82c, 0xcc22, 0x9d06, 0x299c, 0x09e5, 0x1eec, 0x514f, - 0x8d53, 0xa650, 0x5c6e, 0xc577, 0x7958, 0x71ac, 0x8916, 0x9b4f, - 0x2c09, 0x5211, 0xf6d8, 0xcaaa, 0xf7ef, 0x287f, 0x7a94, 0xab49, - 0xfa2c, 0x7222, 0xe457, 0xd71a, 0x00c3, 0x1a76, 0xe98c, 0xc037, - 0x8208, 0x5c2d, 0xdfda, 0xe5f5, 0x0b45, 0x15ce, 0x8a7e, 0xfcad, - 0xaa2d, 0x4b5c, 0xd42e, 0xb251, 0x907e, 0x9a47, 0xc9a6, 0xd93f, - 0x085e, 0x35ce, 0xa153, 0x7e7b, 0x9f0b, 0x25aa, 0x5d9f, 0xc04d, - 0x8a0e, 0x2875, 0x4a1c, 0x295f, 0x1393, 0xf760, 0x9178, 0x0f5b, - 0xfa7d, 0x83b4, 0x2082, 0x721d, 0x6462, 0x0368, 0x67e2, 0x8624, - 0x194d, 0x22f6, 0x78fb, 0x6791, 0xb238, 0xb332, 0x7276, 0xf272, - 0x47ec, 0x4504, 0xa961, 0x9fc8, 0x3fdc, 0xb413, 0x007a, 0x0806, - 0x7458, 0x95c6, 0xccaa, 0x18d6, 0xe2ae, 0x1b06, 0xf3f6, 0x5050, - 0xc8e8, 0xf4ac, 0xc04c, 0xf41c, 0x992f, 0xae44, 0x5f1b, 0x1113, - 0x1738, 0xd9a8, 0x19ea, 0x2d33, 0x9698, 0x2fe9, 0x323f, 0xcde2, - 0x6d71, 0xe37d, 0xb697, 0x2c4f, 0x4373, 0x9102, 0x075d, 0x8e25, - 0x1672, 0xec28, 0x6acb, 0x86cc, 0x186e, 0x9414, 0xd674, 0xd1a5 -}; - -const uint32_t __single_hash64[256] = -{ - /* http://random.org 2014.10.24 */ - 0xd25e9f0a, 0xb1af9d5e, 0xb753dfa2, 0x157050f7, /* 0 */ - 0xc84b072c, 0xdd14fe7c, 0xf92208c3, 0xdf08a0c0, - 0x63a5c118, 0x76f5d90f, 0xa2f8b93e, 0xb6c12d22, - 0xaf074957, 0x966fb7d9, 0x62f7b785, 0xb40e8a09, - 0x0a811d5d, 0x323a6daa, 0xb62f7c5b, 0xfdcb9a53, - 0xf25a9067, 0x4506bc7a, 0xff58a74b, 0x5ae62817, - 0x74097675, 0x722c0fd9, 0x116a2a66, 0x65f76728, - 0x72c79651, 0xe043cf9d, 0x64b867c7, 0x6604834f, - 0xcdca58a6, 0x0f164e2d, 0x24515f05, 0x632cdbf8, - 0x18091d4a, 0x3eff4128, 0x673d1c33, 0xd8e10c71, - 0x1a3edf11, 0xba52892f, 0xa56949e0, 0xf3e1dd77, /* 10 */ - 0x86fcbe3e, 0x138d66d0, 0x4fc98359, 0xc22e5dd6, - 0xc59f2267, 0x6c6dd739, 0xe03da190, 0x07e8469c, - 0xadcfb02c, 0x00d3b0d9, 0xa1f44918, 0x8bd84d87, - 0x08ec9ec1, 0xbbcd156f, 0xb57718e3, 0x3177e752, - 0xf52a4d70, 0xde7aaad9, 0x075f1da0, 0x21ba00c6, - 0xb9469a5c, 0xcf08d5ba, 0x91ac9edc, 0xc6167b63, - 0xc1974919, 0xc8c8d195, 0x4b1996dd, 0xeff8991c, - 0xf7f66c6b, 0x25b012e2, 0x59d12a98, 0xea40d3cc, - 0x41f9970b, 0xec48101a, 0xa3bdcf90, 0x99f16905, - 0x27af6c97, 0xc849af37, 0x49cad89b, 0xf48c2278, /* 20 */ - 0x5529c3d8, 0x9e7d6dce, 0x16feb52d, 0xf1b0aca1, - 0xaf28fccb, 0x48e4ce3c, 0xc4436617, 0x64524e3e, - 0x61806681, 0x6384f2d7, 0x1172880f, 0x34a5ef5f, - 0xcc8cc0a8, 0x66e8f100, 0x2866085f, 0xba9b1b2d, - 0x51285949, 0x2be4b574, 0x889b1ef5, 0x3dbe920d, - 0x9277a62f, 0x0584a9f6, 0x085d8fc4, 0x4b5d403d, - 0x4e46ca78, 0x3294c2f9, 0x29313e70, 0xe4f09b24, - 0xe73b331c, 0x072f5552, 0x2e390b78, 0xea0021ca, - 0xd8f40320, 0xed0e16fd, 0x7de9cf7a, 0xf17e3d6c, - 0x8df1bd85, 0x052cae67, 0x3486e512, 0x3a1c09b8, /* 30 */ - 0x6c2a7b4e, 0x83455753, 0xbc0353ac, 0x0ffe20b6, - 0x5fdcef85, 0x010f506c, 0x595ce972, 0xe28680d0, - 0xa7e216b2, 0xa392ee0f, 0x25b73faa, 0x2b1f4983, - 0xeeaefe98, 0x1d3d9cbc, 0x6aebe97b, 0x8b7b3584, - 0x9e6a9a07, 0xd37f1e99, 0x4ac2a441, 0x8ae9a213, - 0x7d0e27d7, 0x5de54b9a, 0x8621de1f, 0xf0f2f866, - 0xcb08d275, 0x49c3f87e, 0xd5ee68c1, 0x9802fc77, - 0x68be6c5e, 0x65aa8c27, 0xf423d5f7, 0x10ec5502, - 0x9909bce1, 0x509cdf1b, 0x338fea72, 0x2733e9bf, - 0xf92f4fd7, 0x87738ea2, 0x931a8bbc, 0x0a5c9155, /* 40 */ - 0xbe5edd9b, 0xadbf5838, 0x0338f8d2, 0x290da210, - 0x390c37d8, 0xe7cffae8, 0x20617ebe, 0x464322dd, - 0x7b3c4e78, 0xac142dcb, 0x2d5cef76, 0xd8fe49fc, - 0x60f4e9a9, 0x7473816f, 0x0dc35f39, 0x5eed80c1, - 0x0cb55ab6, 0x1d3ac541, 0x13c7f529, 0x7bffdf4a, - 0xe334785b, 0x85263ec1, 0xd132ae56, 0x7c868b9e, - 0x47f60638, 0x1012b979, 0x81c31dd3, 0x1af868c8, - 0x0c5d0742, 0xd1b3e1a2, 0x5873200a, 0xf848465c, - 0x0fc4d596, 0x609c18af, 0xc9f5a480, 0xd1a94a84, - 0xa1431a3f, 0x7de8bb1a, 0x25f1256b, 0x1dcc732c, /* 50 */ - 0x6aa1549a, 0xa2367281, 0x32f2a77e, 0x82e62a0f, - 0x045cbb56, 0x74b2027c, 0xd71a32d9, 0x022e7cb5, - 0xe99be177, 0x60222fdf, 0xd69681ca, 0x9008ee2c, - 0x32923db4, 0xcf82bf97, 0x38960a5b, 0xb3503d5b, - 0x9bd4c7f2, 0x33c029c8, 0x1ef504a3, 0xdb249d3b, - 0x91e89676, 0x4ca43b36, 0x9191433c, 0x465d5dc4, - 0xf4dcb118, 0x9d11dd00, 0xb592f058, 0xdbe5ce30, - 0x74790d92, 0x779850a8, 0x7180d25b, 0xfa951d99, - 0x5990935a, 0x921cb022, 0x3b7c39bc, 0x6a38a7c7, - 0xdc22703b, 0x142bab3b, 0x4e3d9479, 0x44bb8482, /* 60 */ - 0x8043abce, 0xfebe832a, 0x8e6a2f98, 0x4d43c4fe, - 0xd192a70a, 0x802f3c3a, 0x5d11bbab, 0x2665d241, - 0xb3f3a680, 0x3a8d223f, 0xcf82cdb4, 0x4ed28743, -}; - -uint64_t -xd3_large64_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look) -{ - static const uint64_t kBits = 32; - static const uint64_t kMask = 0xffffffff; - usize_t i = 0; - uint64_t low = 0; - uint64_t high = 0; - - for (; i < look; i += 1) - { - low += PERMUTE64(*base++); - high += low; - } - - return ((high & kMask) << kBits) | (low & kMask); -} - -uint64_t -xd3_large64_cksum_update_old (xd3_hash_cfg *ignore, const uint64_t cksum, - const uint8_t *base, const usize_t look) -{ - static const uint64_t kBits = 32; - static const uint64_t kMask = 0xffffffff; - uint64_t old_c = PERMUTE64(base[0]); - uint64_t new_c = PERMUTE64(base[look]); - uint64_t low = ((cksum & kMask) - old_c + new_c) & kMask; - uint64_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask; - return (high << kBits) | low; -} - -uint32_t -xd3_large32_cksum_old (xd3_hash_cfg *ignore, const uint8_t *base, const usize_t look) -{ - static const uint32_t kBits = 16; - static const uint32_t kMask = 0xffff; - usize_t i = 0; - uint32_t low = 0; - uint32_t high = 0; - - for (; i < look; i += 1) - { - low += PERMUTE32(*base++); - high += low; - } - - return ((high & kMask) << kBits) | (low & kMask); -} - -uint32_t -xd3_large32_cksum_update_old (xd3_hash_cfg *ignore, const uint32_t cksum, - const uint8_t *base, const usize_t look) -{ - static const uint32_t kBits = 16; - static const uint32_t kMask = 0xffff; - uint32_t old_c = PERMUTE32(base[0]); - uint32_t new_c = PERMUTE32(base[look]); - uint32_t low = ((cksum & kMask) - old_c + new_c) & kMask; - uint32_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask; - return (high << kBits) | low; -} diff --git a/testing/delta.h b/testing/delta.h index deac217..b0cca7c 100644 --- a/testing/delta.h +++ b/testing/delta.h @@ -30,7 +30,7 @@ public: case XD3_WINFINISH: break; default: - cerr << "decode: " << done; + DP(RINT "error code %s\n", xd3_strerror (ret)); abort(); } } @@ -48,25 +48,23 @@ public: return stream_.whole_target.wininfolen; } -// Note: This does not benefit from -Wformat= checking, due to the -// enclosing template. Further, it was not used. -// void Print() const { -// for (size_t i = 0; i < stream_.whole_target.instlen; i++) { -// xd3_winst &winst = stream_.whole_target.inst[i]; -// switch (winst.type) { -// case XD3_RUN: -// DP(RINT, "%" Q "u run %" W "u\n", winst.position, winst.size); -// break; -// case XD3_ADD: -// DP(RINT "%" Q "u add %" W "u\n", winst.position, winst.size); -// break; -// default: -// DP(RINT "%" Q "u copy %" W "u @ %" Q "u (mode %u)\n", -// winst.position, winst.size, winst.addr, winst.mode); -// break; -// } -// } -// } + void Print() const { + for (size_t i = 0; i < stream_.whole_target.instlen; i++) { + xd3_winst &winst = stream_.whole_target.inst[i]; + switch (winst.type) { + case XD3_RUN: + DP(RINT "%"Q"u run %u\n", winst.position, winst.size); + break; + case XD3_ADD: + DP(RINT "%"Q"u add %u\n", winst.position, winst.size); + break; + default: + DP(RINT "%"Q"u copy %u @ %"Q"u (mode %u)\n", + winst.position, winst.size, winst.addr, winst.mode); + break; + } + } + } private: xd3_stream stream_; diff --git a/testing/file.h b/testing/file.h index 2188f7a..a204d74 100644 --- a/testing/file.h +++ b/testing/file.h @@ -50,7 +50,7 @@ public: } data_ = new uint8_t[data_size_]; memcpy(data_, tmp, size_); - delete [] tmp; + delete tmp; } memcpy(data_ + size_, data, size); @@ -62,43 +62,36 @@ public: size_ = 0; } - // Note: This does not benefit from -Wformat= checking, due to the - // enclosing template. Further, it was not used. - // void Print() const { - // xoff_t pos = 0; - // for (size_t i = 0; i < Size(); i++) { - // if (pos % 16 == 0) { - // DP(RINT "%5" Q "x: ", pos); - // } - // DP(RINT "%02x ", (*this)[i]); - // if (pos % 16 == 15) { - // DP(RINT "\n"); - // } - // pos++; - // } - // DP(RINT "\n"); - // } + void Print() const { + xoff_t pos = 0; + for (size_t i = 0; i < Size(); i++) { + if (pos % 16 == 0) { + DP(RINT "%5"Q"x: ", pos); + } + DP(RINT "%02x ", (*this)[i]); + if (pos % 16 == 15) { + DP(RINT "\n"); + } + pos++; + } + DP(RINT "\n"); + } void WriteTmpFile(TmpFile *f) const { f->Append(this); } void SetSize(size_t size) { - uint8_t *t = NULL; + size_ = size; + if (data_size_ < size) { if (data_) { - t = data_; + delete [] data_; } data_ = new uint8_t[size]; data_size_ = size; } - if (t && size < size_) { - memcpy(data_, t, size); - } - delete [] t; - size_ = size; } - private: friend class BlockIterator; @@ -275,7 +268,6 @@ public: } void SetBlock(xoff_t blkno) { - CHECK_LE(blkno, Blocks()); blkno_ = blkno; } @@ -313,10 +305,8 @@ class ExtFile { public: ExtFile() { static int static_counter = 0; - pid_t pid = getpid(); - char buf[64]; - xoff_t xpid = pid; - snprintf(buf, 64, "/tmp/regtest.%" Q "u.%d", xpid, static_counter++); + char buf[32]; + snprintf(buf, 32, "/tmp/regtest.%d", static_counter++); filename_.append(buf); unlink(filename_.c_str()); } @@ -383,3 +373,4 @@ public: private: mutable main_file file_; }; + diff --git a/testing/modify.h b/testing/modify.h index 93f7bde..5c2e316 100644 --- a/testing/modify.h +++ b/testing/modify.h @@ -12,12 +12,12 @@ public: enum Kind { MODIFY = 1, // Mutate a certain range w/ random or supplied data ADD = 2, // Insert random or supplied data - DELRANGE = 3, // Delete a specified range of data + DELETE = 3, // Delete a specified range of data COPY = 4, // Copy from one region, inserting elsewhere MOVE = 5, // Copy then delete copied-from range - COPYOVER = 6 // Copy then delete copied-to range + COPYOVER = 6 // Copy then delete copied-to range - // ADD, DELRANGE, and COPY change the file size + // ADD, DELETE, and COPY change the file size // MODIFY, MOVE, COPYOVER preserve the file size }; @@ -97,7 +97,7 @@ public: case Change::MODIFY: ModifyChange(ch, table, source_table, rand); break; - case Change::DELRANGE: + case Change::DELETE: DeleteChange(ch, table, source_table, rand); break; case Change::COPY: @@ -269,7 +269,7 @@ public: SegmentMap tmp; CHECK_NE(ch.addr1, ch.addr2); CopyChange(ch, &tmp, source_table, rand); - Change d(Change::DELRANGE, ch.size, + Change d(Change::DELETE, ch.size, ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size); DeleteChange(d, table, &tmp, rand); } @@ -282,7 +282,7 @@ public: SegmentMap tmp; CHECK_NE(ch.addr1, ch.addr2); CopyChange(ch, &tmp, source_table, rand); - Change d(Change::DELRANGE, ch.size, ch.addr2 + ch.size); + Change d(Change::DELETE, ch.size, ch.addr2 + ch.size); DeleteChange(d, table, &tmp, rand); } diff --git a/testing/random.h b/testing/random.h index 8ff64db..d1a6840 100644 --- a/testing/random.h +++ b/testing/random.h @@ -21,7 +21,7 @@ class MTRandom { Init(TEST_SEED1); } - explicit MTRandom(uint32_t seed) { + MTRandom(uint32_t seed) { Init(seed); } diff --git a/testing/regtest.cc b/testing/regtest.cc index dd2ab8d..8219cc0 100644 --- a/testing/regtest.cc +++ b/testing/regtest.cc @@ -9,20 +9,12 @@ public: typedef typename Constants::Sizes Sizes; struct Options { - Options() - : encode_srcwin_maxsz(1<<20), - block_size(Constants::BLOCK_SIZE), - window_size(Constants::WINDOW_SIZE), - size_known(false), - iopt_size(XD3_DEFAULT_IOPT_SIZE), - smatch_cfg(XD3_SMATCH_DEFAULT) { } - - xoff_t encode_srcwin_maxsz; + Options() : encode_srcwin_maxsz(1<<20), + block_size(Constants::BLOCK_SIZE), + size_known(false) { } + uint64_t encode_srcwin_maxsz; size_t block_size; - xoff_t window_size; bool size_known; - usize_t iopt_size; - xd3_smatch_cfg smatch_cfg; }; #include "segment.h" @@ -34,7 +26,7 @@ public: void InMemoryEncodeDecode(const FileSpec &source_file, const FileSpec &target_file, Block *coded_data, - const Options &options) { + const Options &options = Options()) { xd3_stream encode_stream; xd3_config encode_config; xd3_source encode_source; @@ -58,9 +50,17 @@ public: xd3_init_config(&encode_config, XD3_ADLER32); xd3_init_config(&decode_config, XD3_ADLER32); - encode_config.winsize = options.window_size; - encode_config.iopt_size = options.iopt_size; - encode_config.smatch_cfg = options.smatch_cfg; + encode_config.winsize = Constants::WINDOW_SIZE; + + // TODO! the smatcher setup isn't working, + // if (options.large_cksum_step) { + // encode_config.smatch_cfg = XD3_SMATCH_SOFT; + // encode_config.smatcher_soft.large_step = options.large_cksum_step; + // } + // if (options.large_cksum_size) { + // encode_config.smatch_cfg = XD3_SMATCH_SOFT; + // encode_config.smatcher_soft.large_look = options.large_cksum_size; + // } CHECK_EQ(0, xd3_config_stream (&encode_stream, &encode_config)); CHECK_EQ(0, xd3_config_stream (&decode_stream, &decode_config)); @@ -71,45 +71,42 @@ public: encode_source.max_winsize = options.encode_srcwin_maxsz; decode_source.max_winsize = options.encode_srcwin_maxsz; - if (!options.size_known) + if (!options.size_known) { xd3_set_source (&encode_stream, &encode_source); xd3_set_source (&decode_stream, &decode_source); } - else + else { - xd3_set_source_and_size (&encode_stream, &encode_source, + xd3_set_source_and_size (&encode_stream, &encode_source, source_file.Size()); xd3_set_source_and_size (&decode_stream, &decode_source, source_file.Size()); } BlockIterator source_iterator(source_file, options.block_size); - BlockIterator target_iterator(target_file, Constants::WINDOW_SIZE); + BlockIterator target_iterator(target_file, Constants::READ_SIZE); Block encode_source_block, decode_source_block; Block decoded_block, target_block; bool encoding = true; bool done = false; bool done_after_input = false; - IF_DEBUG1 (XPR(NTR "source %" Q "u[%" Z "u] target %" Q "u winsize %" Z "u\n", - source_file.Size(), options.block_size, - target_file.Size(), - Constants::WINDOW_SIZE)); + IF_DEBUG1 (XPR(NTR "source %"Q"u[%"Q"u] target %"Q"u[%lu] winsize %lu\n", + source_file.Size(), options.block_size, + target_file.Size(), Constants::READ_SIZE, + Constants::WINDOW_SIZE)); while (!done) { target_iterator.Get(&target_block); xoff_t blks = target_iterator.Blocks(); - IF_DEBUG2(XPR(NTR "target in %s: %" Q "u[%" Z "u] %" Q "u(%" Q "u) " - "verified %" Q "u\n", - encoding ? "encoding" : "decoding", - target_iterator.Offset(), - target_block.Size(), - target_iterator.Blkno(), - blks, - verified_bytes)); + IF_DEBUG2(XPR(NTR "target in %s: %llu..%llu %"Q"u(%"Q"u) verified %"Q"u\n", + encoding ? "encoding" : "decoding", + target_iterator.Offset(), + target_iterator.Offset() + target_block.Size(), + target_iterator.Blkno(), blks, verified_bytes)); if (blks == 0 || target_iterator.Blkno() == (blks - 1)) { xd3_set_flags(&encode_stream, XD3_FLUSH | encode_stream.flags); @@ -155,11 +152,11 @@ public: xd3_source *src = (encoding ? &encode_source : &decode_source); Block *block = (encoding ? &encode_source_block : &decode_source_block); if (encoding) { - IF_DEBUG2(XPR(NTR "[srcblock] %" Q "u last srcpos %" Q "u " - "encodepos %" Q "u\n", - encode_source.getblkno, - encode_stream.match_last_srcpos, - encode_stream.input_position + encode_stream.total_in)); + IF_DEBUG1(XPR(NTR "[srcblock] %"Q"u last srcpos %"Q"u " + "encodepos %"Q"u\n", + encode_source.getblkno, + encode_stream.match_last_srcpos, + encode_stream.input_position + encode_stream.total_in)); } source_iterator.SetBlock(src->getblkno); @@ -232,10 +229,10 @@ public: ExtFile *coded_data, const Options &options) { vector<const char*> ecmd; - char bbuf[16]; - snprintf(bbuf, sizeof(bbuf), "-B%" Q "u", options.encode_srcwin_maxsz); + char buf[16]; + snprintf(buf, sizeof(buf), "-B%"Q"u", options.encode_srcwin_maxsz); ecmd.push_back("xdelta3"); - ecmd.push_back(bbuf); + ecmd.push_back(buf); ecmd.push_back("-s"); ecmd.push_back(source_file.Name()); ecmd.push_back(target_file.Name()); @@ -248,7 +245,7 @@ public: vector<const char*> dcmd; ExtFile recon_file; dcmd.push_back("xdelta3"); - ecmd.push_back(bbuf); + ecmd.push_back(buf); dcmd.push_back("-d"); dcmd.push_back("-s"); dcmd.push_back(source_file.Name()); @@ -259,146 +256,32 @@ public: CHECK_EQ(0, xd3_main_cmdline(dcmd.size() - 1, const_cast<char**>(&dcmd[0]))); - CHECK_EQ(0, test_compare_files(recon_file.Name(), + CHECK_EQ(0, test_compare_files(recon_file.Name(), target_file.Name())); } - // Similar to xd3_process_memory, with support for test Options. - // Exercises xd3_process_stream. - int TestProcessMemory (int is_encode, - int (*func) (xd3_stream *), - const uint8_t *input, - usize_t input_size, - const uint8_t *source, - usize_t source_size, - uint8_t *output, - usize_t *output_size, - usize_t output_size_max, - const Options &options) { - xd3_stream stream; - xd3_config config; - xd3_source src; - int ret; - - memset (& stream, 0, sizeof (stream)); - memset (& config, 0, sizeof (config)); - - if (is_encode) - { - config.winsize = input_size; - config.iopt_size = options.iopt_size; - config.sprevsz = xd3_pow2_roundup (config.winsize); - } - - if ((ret = xd3_config_stream (&stream, &config)) != 0) - { - goto exit; - } - - if (source != NULL) - { - memset (& src, 0, sizeof (src)); - - src.blksize = source_size; - src.onblk = source_size; - src.curblk = source; - src.curblkno = 0; - src.max_winsize = source_size; - - if ((ret = xd3_set_source_and_size (&stream, &src, source_size)) != 0) - { - goto exit; - } - } - - if ((ret = xd3_process_stream (is_encode, - & stream, - func, 1, - input, input_size, - output, - output_size, - output_size_max)) != 0) - { - goto exit; - } - - exit: - if (ret != 0) - { - IF_DEBUG2 (DP(RINT "test_process_memory: %d: %s\n", ret, stream.msg)); - } - xd3_free_stream(&stream); - return ret; - } - - void EncodeDecodeAPI(const FileSpec &spec0, const FileSpec &spec1, - Block *delta, const Options &options) { - Block from; - Block to; - spec0.Get(&from, 0, spec0.Size()); - spec1.Get(&to, 0, spec1.Size()); - - delta->SetSize(to.Size() * 1.5); - usize_t out_size; - int enc_ret = TestProcessMemory(true, - &xd3_encode_input, - to.Data(), - to.Size(), - from.Data(), - from.Size(), - delta->Data(), - &out_size, - delta->Size(), - options); - CHECK_EQ(0, enc_ret); - delta->SetSize(out_size); - - Block recon; - recon.SetSize(to.Size()); - usize_t recon_size; - int dec_ret = xd3_decode_memory(delta->Data(), - delta->Size(), - from.Data(), - from.Size(), - recon.Data(), - &recon_size, - recon.Size(), - 0); - CHECK_EQ(0, dec_ret); - CHECK_EQ(0, CmpDifferentBlockBytes(to, recon)); - } + ////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// + void TestRandomNumbers() { + MTRandom rand; + int rounds = 1<<20; + uint64_t usum = 0; + uint64_t esum = 0; -void TestPrintf() { - char buf[64]; - xoff_t x = XOFF_T_MAX; - snprintf_func (buf, sizeof(buf), "%" Q "u", x); - const char *expect = XD3_USE_LARGEFILE64 ? - "18446744073709551615" : "4294967295"; - XD3_ASSERT(strcmp (buf, expect) == 0); -} - -void TestRandomNumbers() { - MTRandom rand; - int rounds = 1<<20; - uint64_t usum = 0; - uint64_t esum = 0; - - for (int i = 0; i < rounds; i++) { - usum += rand.Rand32(); - esum += rand.ExpRand32(1024); - } + for (int i = 0; i < rounds; i++) { + usum += rand.Rand32(); + esum += rand.ExpRand32(1024); + } - double allowed_error = 0.01; + double allowed_error = 0.01; - uint32_t umean = usum / rounds; - uint32_t emean = esum / rounds; + uint32_t umean = usum / rounds; + uint32_t emean = esum / rounds; - uint32_t uexpect = UINT32_MAX / 2; - uint32_t eexpect = 1024; + uint32_t uexpect = UINT32_MAX / 2; + uint32_t eexpect = 1024; - if (umean < uexpect * (1.0 - allowed_error) || + if (umean < uexpect * (1.0 - allowed_error) || umean > uexpect * (1.0 + allowed_error)) { XPR(NT "uniform mean error: %u != %u\n", umean, uexpect); abort(); @@ -487,7 +370,7 @@ void TestFirstByte() { } spec0.GenerateFixedSize(size); spec0.ModifyTo(Modify1stByte(), &spec1); - InMemoryEncodeDecode(spec0, spec1, NULL, Options()); + InMemoryEncodeDecode(spec0, spec1, NULL); } } @@ -523,7 +406,7 @@ void TestModifyMutator() { // pass. CHECK_GE(diff, test_cases[i].size - (2 * test_cases[i].size / 256)); - InMemoryEncodeDecode(spec0, spec1, NULL, Options()); + InMemoryEncodeDecode(spec0, spec1, NULL); } } @@ -556,7 +439,7 @@ void TestAddMutator() { CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size()); Block coded; - InMemoryEncodeDecode(spec0, spec1, &coded, Options()); + InMemoryEncodeDecode(spec0, spec1, &coded); Delta delta(coded); CHECK_EQ(test_cases[i].expected_adds, @@ -587,13 +470,13 @@ void TestDeleteMutator() { for (size_t i = 0; i < SIZEOF_ARRAY(test_cases); i++) { ChangeList cl1; - cl1.push_back(Change(Change::DELRANGE, test_cases[i].size, + cl1.push_back(Change(Change::DELETE, test_cases[i].size, test_cases[i].addr)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size() - test_cases[i].size, spec1.Size()); Block coded; - InMemoryEncodeDecode(spec0, spec1, &coded, Options()); + InMemoryEncodeDecode(spec0, spec1, &coded); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); @@ -628,7 +511,7 @@ void TestCopyMutator() { CHECK_EQ(spec0.Size() + test_cases[i].size, spec1.Size()); Block coded; - InMemoryEncodeDecode(spec0, spec1, &coded, Options()); + InMemoryEncodeDecode(spec0, spec1, &coded); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); @@ -670,7 +553,7 @@ void TestMoveMutator() { CHECK_EQ(spec0.Size(), spec1.Size()); Block coded; - InMemoryEncodeDecode(spec0, spec1, &coded, Options()); + InMemoryEncodeDecode(spec0, spec1, &coded); Delta delta(coded); CHECK_EQ(0, delta.AddedBytes()); @@ -698,9 +581,8 @@ void TestOverwriteMutator() { CHECK(memcmp(b0.Data() + 30, b1.Data() + 30, Constants::BLOCK_SIZE - 30) == 0); - xoff_t zero = 0; cl1.clear(); - cl1.push_back(Change(Change::COPYOVER, 10, 20, zero)); + cl1.push_back(Change(Change::COPYOVER, 10, 20, (xoff_t)0)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); CHECK_EQ(spec0.Size(), spec1.Size()); @@ -714,7 +596,7 @@ void TestOverwriteMutator() { // Note: this test is written to expose a problem, but the problem was // only exposed with BLOCK_SIZE = 128. -void TestNonBlocking() { +void TestNonBlockingProgress() { MTRandom rand; FileSpec spec0(&rand); FileSpec spec1(&rand); @@ -753,7 +635,7 @@ void TestNonBlocking() { spec0.ModifyTo(ChangeListMutator(ctl), &spec2); - InMemoryEncodeDecode(spec1, spec2, NULL, Options()); + InMemoryEncodeDecode(spec1, spec2, NULL); } void TestEmptyInMemory() { @@ -765,7 +647,7 @@ void TestEmptyInMemory() { spec0.GenerateFixedSize(0); spec1.GenerateFixedSize(0); - InMemoryEncodeDecode(spec0, spec1, &block, Options()); + InMemoryEncodeDecode(spec0, spec1, &block); Delta delta(block); CHECK_LT(0, block.Size()); @@ -781,224 +663,94 @@ void TestBlockInMemory() { spec0.GenerateFixedSize(Constants::BLOCK_SIZE); spec1.GenerateFixedSize(Constants::BLOCK_SIZE); - InMemoryEncodeDecode(spec0, spec1, &block, Options()); + InMemoryEncodeDecode(spec0, spec1, &block); Delta delta(block); CHECK_EQ(spec1.Blocks(Constants::WINDOW_SIZE), delta.Windows()); } -void TestSmallStride() { +void TestHalfBlockCopy() { MTRandom rand; FileSpec spec0(&rand); - usize_t size = Constants::BLOCK_SIZE * 4; - spec0.GenerateFixedSize(size); - - // Note: Not very good performance due to hash collisions, note 3x - // multiplier below. - for (int s = 15; s < 101; s++) { - usize_t changes = 0; - ChangeList cl; - for (usize_t j = s; j < size; j += s, ++changes) - { - cl.push_back(Change(Change::MODIFY, 1, j)); - } - - FileSpec spec1(&rand); - spec0.ModifyTo(ChangeListMutator(cl), &spec1); - - Options options; - options.encode_srcwin_maxsz = size; - options.iopt_size = 128; - options.smatch_cfg = XD3_SMATCH_SLOW; - options.size_known = false; - - Block block; - InMemoryEncodeDecode(spec0, spec1, &block, options); - Delta delta(block); - - IF_DEBUG1(DP(RINT "[stride=%d] changes=%" W "u adds=%" Q "u\n", - s, changes, delta.AddedBytes())); - double allowance = Constants::BLOCK_SIZE < 8192 || s < 30 ? 3.0 : 1.1; - CHECK_GE(allowance * changes, (double)delta.AddedBytes()); - } -} - -void TestCopyWindow() { - // Construct an input that has many copies, to fill the IOPT buffer - // and force a source window decision. "srclen" may be set to a - // value that goes beyond the end-of-source. - const int clen = 16; - const int size = 4096; - const int nmov = size / clen; - const int iters = 16; - uint32_t added_01 = 0; - uint32_t added_10 = 0; - for (int i = 1; i <= iters; i++) { - MTRandom rand(MTRandom::TEST_SEED1 * i); - FileSpec spec0(&rand); - ChangeList cl; - - spec0.GenerateFixedSize(size); - - for (int j = 0; j < nmov; j += 2) - { - cl.push_back(Change(Change::MOVE, - clen, (j + 1) * clen, j * clen)); - } - - FileSpec spec1(&rand); - spec0.ModifyTo(ChangeListMutator(cl), &spec1); - - Options options; - options.encode_srcwin_maxsz = size; - options.iopt_size = 128; - options.smatch_cfg = XD3_SMATCH_SLOW; - - Block block1; - InMemoryEncodeDecode(spec0, spec1, &block1, options); - Delta delta1(block1); - // Allow one missed window (e.g., hash collisions) - added_01 += delta1.AddedBytes(); - - Block block2; - InMemoryEncodeDecode(spec1, spec0, &block2, options); - Delta delta2(block2); - // Allow one missed window (e.g., hash collisions) - added_10 += delta2.AddedBytes(); - - Block block3; - Block block4; - EncodeDecodeAPI(spec0, spec1, &block3, options); - EncodeDecodeAPI(spec1, spec0, &block4, options); - } - // Average less than 0.5 misses (of length clen) per iteration. - CHECK_GE(clen * iters / 2, added_01); - CHECK_GE(clen * iters / 2, added_10); -} - -void TestCopyFromEnd() { - // Copies from the end of the source buffer, which reach a block - // boundary end-of-file. - const int size = 4096; - const int clen = 16; - const int nmov = (size / 2) / clen; - const int iters = 16; - uint32_t added_01 = 0; - uint32_t added_10 = 0; - for (int i = 1; i <= iters; i++) { - MTRandom rand(MTRandom::TEST_SEED1 * i); - FileSpec spec0(&rand); - ChangeList cl; - - spec0.GenerateFixedSize(size); - - cl.push_back(Change(Change::MODIFY, 2012, 2048)); - - for (int j = 0; j < nmov; j += 2) - { - cl.push_back(Change(Change::MOVE, - clen, (j + 1) * clen, j * clen)); - } - - cl.push_back(Change(Change::COPYOVER, 28, 4068, 3000)); - cl.push_back(Change(Change::COPYOVER, 30, 4066, 3100)); - cl.push_back(Change(Change::COPYOVER, 32, 4064, 3200)); - - FileSpec spec1(&rand); - spec0.ModifyTo(ChangeListMutator(cl), &spec1); + FileSpec spec1(&rand); - Options options; - options.encode_srcwin_maxsz = size; - options.iopt_size = 128; - options.smatch_cfg = XD3_SMATCH_SLOW; + spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 4); - Block block1; - InMemoryEncodeDecode(spec0, spec1, &block1, options); - Delta delta1(block1); - added_01 += delta1.AddedBytes(); + // Create a half-block copy, 2.5 blocks apart, from the second half + // of the source version to the first half of the target version. + // 0 1 2 3 + // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbbb] + // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] + ChangeList cl1; + cl1.push_back(Change(Change::MODIFY, + Constants::BLOCK_SIZE / 2, // size + 0)); + cl1.push_back(Change(Change::COPYOVER, + Constants::BLOCK_SIZE / 2, // size + Constants::BLOCK_SIZE * 3, // offset + Constants::BLOCK_SIZE / 2)); + cl1.push_back(Change(Change::MODIFY, + Constants::BLOCK_SIZE * 3, + Constants::BLOCK_SIZE)); + spec0.ModifyTo(ChangeListMutator(cl1), &spec1); - Block block2; - InMemoryEncodeDecode(spec1, spec0, &block2, options); - Delta delta2(block2); - added_10 += delta2.AddedBytes(); + const int onecopy_adds = + 4 * Constants::BLOCK_SIZE - Constants::BLOCK_SIZE / 2; + const int nocopy_adds = 4 * Constants::BLOCK_SIZE; - Block block3; - Block block4; - EncodeDecodeAPI(spec0, spec1, &block3, options); - EncodeDecodeAPI(spec1, spec0, &block4, options); - } - CHECK_GE(2000 * iters, added_01); - CHECK_LE(2000 * iters, added_10); -} - -void TestHalfBlockCopy() { - // Create a half-block copy, 7.5 blocks apart, in a pair of files: - // 0 1 ... 6 7 - // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbb_] - // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_] - // where stage= - // 0: the final block is full - // a. (source)spec1->(target)spec0 copies block C: reads 8 source - // blocks during target block 0. - // b. (source)spec0->(target)spec1 does not copy block C b/c attempt - // to read past EOF empties block 0 from (virtual) block cache - // 1: the final block is less than full. - // a. (same) copies block C - // b. (same) copies block C, unlike 0a, no attempt to read past EOF - // - // "virtual" above refers to XD3_TOOFARBACK, since there is no caching - // in the API, there is simply a promise not to request blocks that are - // beyond source->max_winsize from the last known source file position. - for (int stage = 0; stage < 2; stage++) + // Note the case b=4 is contrived: the caller should use a single block + // containing the entire source, if possible. + for (int b = 1; b <= 4; b++) { - IF_DEBUG1 (DP(RINT "half_block_copy stage %d\n", stage)); - - MTRandom rand; - FileSpec spec0(&rand); - FileSpec spec1(&rand); - - spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 8 - stage); - - ChangeList cl1; - cl1.push_back(Change(Change::MODIFY, - Constants::BLOCK_SIZE / 2, // size - 0)); - cl1.push_back(Change(Change::COPYOVER, - Constants::BLOCK_SIZE / 2, // size - Constants::BLOCK_SIZE * 7, // offset - Constants::BLOCK_SIZE / 2)); - cl1.push_back(Change(Change::MODIFY, - Constants::BLOCK_SIZE * 7, - Constants::BLOCK_SIZE - stage)); - spec0.ModifyTo(ChangeListMutator(cl1), &spec1); - Options options; - options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 8; + options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * b; Block block0; Block block1; InMemoryEncodeDecode(spec0, spec1, &block0, options); InMemoryEncodeDecode(spec1, spec0, &block1, options); - Delta delta0(block0); Delta delta1(block1); - const int yes = - Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; - const int no = - Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; - - if (stage == 0) - { - CHECK_EQ(yes, delta0.AddedBytes()); - CHECK_EQ(no, delta1.AddedBytes()); - } + // The first block never copies from the last source block, by + // design, because if the last source block is available when + // the first target block is ready, the caller is expected to + // use a single block. + CHECK_EQ(nocopy_adds, delta0.AddedBytes()); + if (Constants::BLOCK_SIZE < 8192 || b > 2) + { + // For small-block inputs, the entire file is read into one + // block (the min source window size is 16kB). + // + // For large blocks, at least 3 blocks of source window are + // needed. + CHECK_EQ(onecopy_adds, delta1.AddedBytes()); + } else - { - CHECK_EQ(yes, delta0.AddedBytes()); - CHECK_EQ(yes, delta1.AddedBytes()); - } + { + // When there are fewer than 3 source blocks. + CHECK_EQ(nocopy_adds, delta1.AddedBytes()); + } + // XPR(NT "0=%zu 1=%zu\n", delta0.AddedBytes(), delta1.AddedBytes()); } + + Options options; + options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 4; + options.block_size = Constants::BLOCK_SIZE * 4; + + // Test the whole-buffer case. + Block block0; + Block block1; + InMemoryEncodeDecode(spec0, spec1, &block0, options); + InMemoryEncodeDecode(spec1, spec0, &block1, options); + Delta delta0(block0); + Delta delta1(block1); + // This <= >= are only for blocksize = 512, which has irregular readsize. + CHECK_LE(onecopy_adds, delta0.AddedBytes()); + CHECK_GE(onecopy_adds + 1, delta0.AddedBytes()); + + CHECK_EQ(onecopy_adds, delta1.AddedBytes()); + // XPR(NT "0=%zu 1=%zu\n", delta0.AddedBytes(), delta1.AddedBytes()); } void FourWayMergeTest(const FileSpec &spec0, @@ -1008,7 +760,7 @@ void FourWayMergeTest(const FileSpec &spec0, TmpFile f0, f1, f2, f3; ExtFile d01, d12, d23; Options options; - options.encode_srcwin_maxsz = + options.encode_srcwin_maxsz = std::max(spec0.Size(), options.encode_srcwin_maxsz); spec0.WriteTmpFile(&f0); @@ -1131,7 +883,7 @@ void TestMergeCommand1() { } cl1.push_back(Change(Change::ADD, change1, add1_pos)); - cl2.push_back(Change(Change::DELRANGE, change1, del2_pos)); + cl2.push_back(Change(Change::DELETE, change1, del2_pos)); cl3.push_back(Change(Change::MODIFY, change3, change3_pos)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); @@ -1185,9 +937,9 @@ void TestMergeCommand2() { ChangeList cl1, cl2, cl3; - cl1.push_back(Change(Change::DELRANGE, size0 - size1, 0)); - cl2.push_back(Change(Change::DELRANGE, size0 - size2, 0)); - cl3.push_back(Change(Change::DELRANGE, size0 - size3, 0)); + cl1.push_back(Change(Change::DELETE, size0 - size1, 0)); + cl2.push_back(Change(Change::DELETE, size0 - size2, 0)); + cl3.push_back(Change(Change::DELETE, size0 - size3, 0)); spec0.ModifyTo(ChangeListMutator(cl1), &spec1); spec0.ModifyTo(ChangeListMutator(cl2), &spec2); @@ -1201,44 +953,6 @@ void TestMergeCommand2() { } } -void TestLastFrontierBlock() { - // This test constructs an input that can expose - // https://github.com/jmacd/xdelta/issues/188 - // when run through the command-line with source via a FIFO. - // That is not tested here, but the test stays. - if (Constants::WINDOW_SIZE < XD3_ALLOCSIZE) - { - return; - } - - MTRandom rand; - FileSpec spec0(&rand); - FileSpec spec1(&rand); - const xoff_t size = XD3_ALLOCSIZE * 64; // == XD3_MINSRCWINSZ * 2 - const xoff_t edit = XD3_ALLOCSIZE; - - Options options; - options.encode_srcwin_maxsz = XD3_MINSRCWINSZ; - options.block_size = XD3_ALLOCSIZE; - options.window_size = XD3_MINSRCWINSZ; - options.size_known = false; - - spec0.GenerateFixedSize(size); - - ChangeList cl; - - // Modify the 0th byte in order to induce indexing of subsequent - // bytes, but allow copying most of the file to keep the test fast. - cl.push_back(Change(Change::MODIFY, 1, edit * 31)); - cl.push_back(Change(Change::COPYOVER, edit, edit * 31, edit * 63)); - - spec0.ModifyTo(ChangeListMutator(cl), &spec1); - - Block noblock; - InMemoryEncodeDecode(spec0, spec1, &noblock, options); - InMemoryEncodeDecode(spec1, spec0, &noblock, options); -} - }; // class Regtest<Constants> #define TEST(x) XPR(NTR #x "...\n"); regtest.x() @@ -1247,7 +961,6 @@ void TestLastFrontierBlock() { template <class T> void UnitTest() { Regtest<T> regtest; - TEST(TestPrintf); TEST(TestRandomNumbers); TEST(TestRandomFile); TEST(TestFirstByte); @@ -1262,24 +975,20 @@ void UnitTest() { // These are Xdelta tests. template <class T> void MainTest() { - XPR(NT "Blocksize %" Q "u windowsize %" Z "u\n", - T::BLOCK_SIZE, T::WINDOW_SIZE); + XPR(NT "Blocksize %"Q"u readsize %"Q"u windowsize %"Q"u\n", + T::BLOCK_SIZE, T::READ_SIZE, T::WINDOW_SIZE); Regtest<T> regtest; TEST(TestEmptyInMemory); TEST(TestBlockInMemory); - TEST(TestSmallStride); - TEST(TestCopyWindow); - TEST(TestCopyFromEnd); - TEST(TestNonBlocking); + TEST(TestNonBlockingProgress); TEST(TestHalfBlockCopy); - TEST(TestLastFrontierBlock); TEST(TestMergeCommand1); TEST(TestMergeCommand2); } #undef TEST -int main(int argc, char **argv) +int main(int argc, char **argv) { vector<const char*> mcmd; string pn; @@ -1295,6 +1004,7 @@ int main(int argc, char **argv) UnitTest<SmallBlock>(); MainTest<SmallBlock>(); MainTest<MixedBlock>(); + MainTest<PrimeBlock>(); MainTest<OversizeBlock>(); MainTest<LargeBlock>(); @@ -1303,4 +1013,3 @@ int main(int argc, char **argv) return 0; } - diff --git a/testing/run_release.sh b/testing/run_release.sh deleted file mode 100755 index 85ed1f7..0000000 --- a/testing/run_release.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -(cd .. && ./run_release.sh) diff --git a/testing/sizes.h b/testing/sizes.h index 223d359..18f46e9 100644 --- a/testing/sizes.h +++ b/testing/sizes.h @@ -77,35 +77,54 @@ const size_t BaseConstants::TEST_ROUNDS = 10; struct SmallBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; + static const size_t READ_SIZE; typedef SmallSizes Sizes; }; +const size_t SmallBlock::READ_SIZE = 1<<7; const xoff_t SmallBlock::BLOCK_SIZE = 1<<7; const size_t SmallBlock::WINDOW_SIZE = 1<<7; struct LargeBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; + static const size_t READ_SIZE; typedef LargeSizes Sizes; }; +const size_t LargeBlock::READ_SIZE = (1 << 13); const xoff_t LargeBlock::BLOCK_SIZE = (1 << 13); const size_t LargeBlock::WINDOW_SIZE = (1 << 13); struct MixedBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; + static const size_t READ_SIZE; typedef SmallSizes Sizes; }; +const size_t MixedBlock::READ_SIZE = 1<<6; const xoff_t MixedBlock::BLOCK_SIZE = 1<<7; const size_t MixedBlock::WINDOW_SIZE = 1<<8; struct OversizeBlock : public BaseConstants { static const xoff_t BLOCK_SIZE; static const size_t WINDOW_SIZE; + static const size_t READ_SIZE; typedef SmallSizes Sizes; }; +const size_t OversizeBlock::READ_SIZE = (1<<6) + (1<<7); const xoff_t OversizeBlock::BLOCK_SIZE = 1<<8; const size_t OversizeBlock::WINDOW_SIZE = 1<<7; + +struct PrimeBlock : public BaseConstants { + static const xoff_t BLOCK_SIZE; + static const size_t WINDOW_SIZE; + static const size_t READ_SIZE; + typedef SmallSizes Sizes; +}; + +const size_t PrimeBlock::READ_SIZE = 71; +const xoff_t PrimeBlock::BLOCK_SIZE = 512; // Must be a power-of-2 +const size_t PrimeBlock::WINDOW_SIZE = 73; diff --git a/testing/test.h b/testing/test.h index 7de24fb..d1f1a22 100644 --- a/testing/test.h +++ b/testing/test.h @@ -18,12 +18,12 @@ extern "C" { #define CHECK_OP(x,y,OP) \ do { \ - __typeof__(x) _x(x); \ - __typeof__(x) _y(y); \ + typeof(x) _x(x); \ + typeof(x) _y(y); \ if (!(_x OP _y)) { \ cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \ - cerr << __FILE__ << ":" << __LINE__ << " {0} " << _x << endl; \ - cerr << __FILE__ << ":" << __LINE__ << " {1} " << _y << endl; \ + cerr << __FILE__ << ":" << __LINE__ << " Expected: " << _x << endl; \ + cerr << __FILE__ << ":" << __LINE__ << " Actual: " << _y << endl; \ abort(); \ } } while (false) #undef CHECK @@ -68,3 +68,5 @@ pair<T, U> make_pair(const T& t, const U& u) { using std::min; using std::max; + + |