From bfad1f70865272aff4bdd6798ea876c69b94d70c Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Sun, 24 May 2020 19:52:50 +0300 Subject: [PATCH] mdbx-test: redesign fitting internal parameters of "ttl" & "nested" testcases. Change-Id: I3ade4ba9d78c00ff6911c3e35738f7dcbf63de64 --- test/nested.cc | 77 +++++++++------------------ test/test.cc | 3 +- test/test.h | 34 +++++++----- test/ttl.cc | 139 +++++++++++++++++++++++++++++++++---------------- 4 files changed, 143 insertions(+), 110 deletions(-) diff --git a/test/nested.cc b/test/nested.cc index d90eae90..f273fbef 100644 --- a/test/nested.cc +++ b/test/nested.cc @@ -15,6 +15,25 @@ #include "test.h" #include +/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями: + * - организуется "скользящее окно", которое каждую транзакцию сдвигается + * вперед вдоль числовой оси. + * - по переднему краю "скользящего окна" записи добавляются в таблицу, + * а по заднему удаляются. + * - количество добавляемых/удаляемых записей псевдослучайно зависит + * от номера транзакции, но с экспоненциальным распределением. + * - размер "скользящего окна" также псевдослучайно зависит от номера + * транзакции с "отрицательным" экспоненциальным распределением + * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний + * край и удаляются записи позади него. + * - групповое добавление данных в начало окна и групповое удаление в конце, + * преимущественно выполняются во вложенных транзакциях. + * - меньшая часть запускаемых вложенных транзакций отменяется, с последующим + * продолжением итераций с состояния предыдущиего коммита. + * + * Таким образом имитируется поведение таблицы с TTL: записи стохастически + * добавляются и удаляются, и изредка происходят массивные удаления. */ + bool testcase_nested::setup() { if (!inherited::setup()) return false; @@ -56,18 +75,6 @@ bool testcase_nested::teardown() { return inherited::teardown() && ok; } -static unsigned edge2window(uint64_t edge, unsigned window_max) { - const double rnd = u64_to_double1(bleach64(edge)); - const unsigned window = window_max - std::lrint(std::pow(window_max, rnd)); - return window; -} - -static unsigned edge2count(uint64_t edge, unsigned count_max) { - const double rnd = u64_to_double1(prng64_map1_white(edge)); - const unsigned count = std::lrint(std::pow(count_max, rnd)); - return count; -} - void testcase_nested::push_txn() { MDBX_txn *txn; unsigned flags = @@ -172,7 +179,7 @@ bool testcase_nested::trim_tail(unsigned window_width) { if (unlikely(!keyvalue_maker.increment(tail_serial, 1))) failure("nested: unexpected key-space overflow on the tail"); } - report(1); + report(tail_count); } } else if (!fifo.empty()) { log_verbose("nested: purge state %" PRIu64 " - %" PRIu64 ", fifo-items %zu", @@ -220,39 +227,6 @@ retry: } bool testcase_nested::run() { - /* LY: тест "эмуляцией time-to-live" с вложенными транзакциями: - * - организуется "скользящее окно", которое каждую транзакцию сдвигается - * вперед вдоль числовой оси. - * - по переднему краю "скользящего окна" записи добавляются в таблицу, - * а по заднему удаляются. - * - количество добавляемых/удаляемых записей псевдослучайно зависит - * от номера транзакции, но с экспоненциальным распределением. - * - размер "скользящего окна" также псевдослучайно зависит от номера - * транзакции с "отрицательным" экспоненциальным распределением - * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний - * край и удаляются записи позади него. - * - групповое добавление данных в начало окна и групповое уделение в конце, - * в половине случаев выполняются во вложенных транзакциях. - * - половина запускаемых вложенных транзакций отменяется, последуюим - * повтором групповой операции. - * - * Таким образом имитируется поведение таблицы с TTL: записи стохастически - * добавляются и удаляются, но изредка происходят массивные удаления. */ - - /* LY: для параметризации используем подходящие параметры, которые не имеют - * здесь смысла в первоначальном значении. */ - const unsigned window_max_lower = 333; - const unsigned count_max_lower = 333; - - const unsigned window_max = (config.params.batch_read > window_max_lower) - ? config.params.batch_read - : window_max_lower; - const unsigned count_max = (config.params.batch_write > count_max_lower) - ? config.params.batch_write - : count_max_lower; - log_verbose("nested: using `batch_read` value %u for window_max", window_max); - log_verbose("nested: using `batch_write` value %u for count_max", count_max); - uint64_t seed = prng64_map2_white(config.params.keygen.seed) + config.actor_id; @@ -262,10 +236,9 @@ bool testcase_nested::run() { unsigned loops = 0; while (true) { const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */; - const unsigned window_width = (!should_continue() || flipcoin_x4()) - ? 0 - : edge2window(salt, window_max); - const unsigned head_count = edge2count(salt, count_max); + const unsigned window_width = + (!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt); + const unsigned head_count = edge2count(salt); log_debug("nested: step #%zu (serial %" PRIu64 ", window %u, count %u) salt %" PRIu64, nops_completed, serial, window_width, head_count, salt); @@ -301,7 +274,9 @@ bool testcase_nested::run() { } loops += 1; } else if (fifo.empty()) { - log_notice("nested: done %u whole loops", loops); + log_notice("nested: done %u whole loops, %" PRIu64 " ops, %" PRIu64 + " items", + loops, nops_completed, serial); break; } else { log_notice("nested: done, wait for empty, skip head-grow"); diff --git a/test/test.cc b/test/test.cc index 3f051092..e339d2ca 100644 --- a/test/test.cc +++ b/test/test.cc @@ -394,7 +394,8 @@ bool testcase::should_continue(bool check_timeout_only) const { result = false; } - if (!check_timeout_only && nops_target && nops_completed >= nops_target) + if (!check_timeout_only && config.params.test_nops && + nops_completed >= config.params.test_nops) result = false; if (result) diff --git a/test/test.h b/test/test.h index f9afb450..68d3968b 100644 --- a/test/test.h +++ b/test/test.h @@ -148,7 +148,6 @@ protected: bool signalled{false}; bool need_speculum_assign{false}; - unsigned nops_target{config.params.test_nops}; size_t nops_completed{0}; chrono::time start_timestamp; keygen::buffer key; @@ -229,18 +228,7 @@ public: virtual ~testcase() {} }; -class testcase_ttl : public testcase { - using inherited = testcase; - -public: - testcase_ttl(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} - bool run() override; -}; - class testcase_hill : public testcase { - using inherited = testcase; - public: testcase_hill(const actor_config &config, const mdbx_pid_t pid) : testcase(config, pid) {} @@ -293,8 +281,26 @@ public: bool run() override; }; -class testcase_nested : public testcase { +class testcase_ttl : public testcase { using inherited = testcase; + +protected: + struct { + unsigned max_window_size{0}; + unsigned max_step_size{0}; + } sliding; + unsigned edge2window(uint64_t edge); + unsigned edge2count(uint64_t edge); + +public: + testcase_ttl(const actor_config &config, const mdbx_pid_t pid) + : inherited(config, pid) {} + bool setup() override; + bool run() override; +}; + +class testcase_nested : public testcase_ttl { + using inherited = testcase_ttl; using FIFO = std::deque>; uint64_t serial{0}; @@ -317,7 +323,7 @@ class testcase_nested : public testcase { public: testcase_nested(const actor_config &config, const mdbx_pid_t pid) - : testcase(config, pid) {} + : inherited(config, pid) {} bool setup() override; bool run() override; bool teardown() override; diff --git a/test/ttl.cc b/test/ttl.cc index d095c9f6..096687d9 100644 --- a/test/ttl.cc +++ b/test/ttl.cc @@ -16,16 +16,97 @@ #include #include -static unsigned edge2window(uint64_t edge, unsigned window_max) { - const double rnd = u64_to_double1(bleach64(edge)); - const unsigned window = window_max - std::lrint(std::pow(window_max, rnd)); - return window; +/* LY: тест "эмуляцией time-to-live": + * - организуется "скользящее окно", которое двигается вперед вдоль + * числовой оси каждую транзакцию. + * - по переднему краю "скользящего окна" записи добавляются в таблицу, + * а по заднему удаляются. + * - количество добавляемых/удаляемых записей псевдослучайно зависит + * от номера транзакции, но с экспоненциальным распределением. + * - размер "скользящего окна" также псевдослучайно зависит от номера + * транзакции с "отрицательным" экспоненциальным распределением + * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний + * край и удаляются записи позади него. + * + * Таким образом имитируется поведение таблицы с TTL: записи стохастически + * добавляются и удаляются, но изредка происходит массивное удаление. + */ + +unsigned testcase_ttl::edge2count(uint64_t edge) { + const double rnd = u64_to_double1(prng64_map1_white(edge)); + const unsigned count = std::lrint(std::pow(sliding.max_step_size, rnd)); + // average value: (X - 1) / ln(X), where X = sliding.max_step_size + return count; } -static unsigned edge2count(uint64_t edge, unsigned count_max) { - const double rnd = u64_to_double1(prng64_map1_white(edge)); - const unsigned count = std::lrint(std::pow(count_max, rnd)); - return count; +unsigned testcase_ttl::edge2window(uint64_t edge) { + const double rnd = u64_to_double1(bleach64(edge)); + const unsigned size = sliding.max_window_size - + std::lrint(std::pow(sliding.max_window_size, rnd)); + // average value: Y - (Y - 1) / ln(Y), where Y = sliding.max_window_size + return size; +} + +static inline double estimate(const double x, const double y) { + /* среднее кол-во операций N = X' * Y', где X' и Y' средние значения + * размера окна и кол-ва добавляемых за один шаг записей: + * X' = (X - 1) / ln(X), где X = sliding.max_step_size + * Y' = Y - (Y - 1) / ln(Y), где Y = sliding.max_window_size */ + return (x - 1) / std::log(x) * (y - (y - 1) / std::log(y)); +} + +bool testcase_ttl::setup() { + const unsigned window_top_lower = + 7 /* нижний предел для верхней границы диапазона, в котором будет + стохастически колебаться размер окна */ + ; + const unsigned count_top_lower = + 7 /* нижний предел для верхней границы диапазона, в котором будет + стохастически колебаться кол-во записей добавляемых на одном шаге */ + ; + + /* для параметризации используем подходящие параметры, + * которые не имеют здесь смысла в первоначальном значении. */ + const double ratio = + double(config.params.batch_read ? config.params.batch_read : 1) / + double(config.params.batch_write ? config.params.batch_write : 1); + + /* проще найти двоичным поиском (вариация метода Ньютона) */ + double hi = config.params.test_nops, lo = 1; + double x = std::sqrt(hi + lo) / ratio; + while (hi > lo) { + const double n = estimate(x, x * ratio); + if (n > config.params.test_nops) + hi = x - 1; + else + lo = x + 1; + x = (hi + lo) / 2; + } + + sliding.max_step_size = std::lrint(x); + if (sliding.max_step_size < count_top_lower) + sliding.max_step_size = count_top_lower; + sliding.max_window_size = std::lrint(x * ratio); + if (sliding.max_window_size < window_top_lower) + sliding.max_window_size = window_top_lower; + + while (estimate(sliding.max_step_size, sliding.max_window_size) > + config.params.test_nops * 2.0) { + if (ratio * sliding.max_step_size > sliding.max_window_size) { + if (sliding.max_step_size < count_top_lower) + break; + sliding.max_step_size = sliding.max_step_size * 7 / 8; + } else { + if (sliding.max_window_size < window_top_lower) + break; + sliding.max_window_size = sliding.max_window_size * 7 / 8; + } + } + + log_verbose("come up window_max %u from `batch_read`", + sliding.max_window_size); + log_verbose("come up step_max %u from `batch_write`", sliding.max_step_size); + return inherited::setup(); } bool testcase_ttl::run() { @@ -35,36 +116,6 @@ bool testcase_ttl::run() { return false; } - /* LY: тест "эмуляцией time-to-live": - * - организуется "скользящее окно", которое двигается вперед вдоль - * числовой оси каждую транзакцию. - * - по переднему краю "скользящего окна" записи добавляются в таблицу, - * а по заднему удаляются. - * - количество добавляемых/удаляемых записей псевдослучайно зависит - * от номера транзакции, но с экспоненциальным распределением. - * - размер "скользящего окна" также псевдослучайно зависит от номера - * транзакции с "отрицательным" экспоненциальным распределением - * MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний - * край и удаляются записи позади него. - * - * Таким образом имитируется поведение таблицы с TTL: записи стохастически - * добавляются и удаляются, но изредка происходят массивные удаления. - */ - - /* LY: для параметризации используем подходящие параметры, которые не имеют - * здесь смысла в первоначальном значении. */ - const unsigned window_max_lower = 333; - const unsigned count_max_lower = 333; - - const unsigned window_max = (config.params.batch_read > window_max_lower) - ? config.params.batch_read - : window_max_lower; - const unsigned count_max = (config.params.batch_write > count_max_lower) - ? config.params.batch_write - : count_max_lower; - log_verbose("ttl: using `batch_read` value %u for window_max", window_max); - log_verbose("ttl: using `batch_write` value %u for count_max", count_max); - uint64_t seed = prng64_map2_white(config.params.keygen.seed) + config.actor_id; keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */); @@ -85,10 +136,9 @@ bool testcase_ttl::run() { while (true) { const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */; - const unsigned window_width = (!should_continue() || flipcoin_x4()) - ? 0 - : edge2window(salt, window_max); - unsigned head_count = edge2count(salt, count_max); + const unsigned window_width = + (!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt); + unsigned head_count = edge2count(salt); log_debug("ttl: step #%zu (serial %" PRIu64 ", window %u, count %u) salt %" PRIu64, nops_completed, serial, window_width, head_count, salt); @@ -115,7 +165,7 @@ bool testcase_ttl::run() { if (unlikely(!keyvalue_maker.increment(tail_serial, 1))) failure("ttl: unexpected key-space overflow on the tail"); } - report(1); + report(tail_count); } } else { log_trace("ttl: purge state"); @@ -185,7 +235,8 @@ bool testcase_ttl::run() { } loops += 1; } else if (fifo.empty()) { - log_notice("ttl: done %u whole loops", loops); + log_notice("ttl: done %u whole loops, %" PRIu64 " ops, %" PRIu64 " items", + loops, nops_completed, serial); rc = true; break; } else {