From 105b8ec1cf9ed7958686730103e8704085c66537 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Mon, 27 Jul 2020 11:32:50 +0800 Subject: [PATCH] [base] Factor out sequence_generator --- Makefile.in | 1 + base/io_generator.cc | 154 ++-------------------------------- base/sequence_generator.cc | 165 +++++++++++++++++++++++++++++++++++++ base/sequence_generator.h | 27 ++++++ 4 files changed, 198 insertions(+), 149 deletions(-) create mode 100644 base/sequence_generator.cc create mode 100644 base/sequence_generator.h diff --git a/Makefile.in b/Makefile.in index b3791cd..b1fd4aa 100644 --- a/Makefile.in +++ b/Makefile.in @@ -44,6 +44,7 @@ SOURCE=\ base/file_utils.cc \ base/progress_monitor.cc \ base/rolling_hash.cc \ + base/sequence_generator.cc \ base/xml_utils.cc \ block-cache/block_cache.cc \ block-cache/copier.cc \ diff --git a/base/io_generator.cc b/base/io_generator.cc index 024f04f..918a9ed 100644 --- a/base/io_generator.cc +++ b/base/io_generator.cc @@ -1,5 +1,5 @@ #include "base/io_generator.h" -#include "base/run_set.h" +#include "base/sequence_generator.h" #include #include #include @@ -26,150 +26,6 @@ namespace { //-------------------------------- - class sequence_generator { - public: - typedef std::shared_ptr ptr; - - virtual uint64_t next() = 0; - }; - - // - The maximum generated value is not greater than (begin+size) - // - The generated values are not aligned to the step, if the begin - // value is not aligned. - class forward_sequence_generator: public sequence_generator { - public: - forward_sequence_generator(uint64_t begin, - uint64_t size, - uint64_t step) - : begin_(begin), - end_(begin + (size / step) * step), - step_(step), - current_(begin), - rounds_(0) { - if (size < step) - throw std::runtime_error("size must be greater than the step"); - } - - forward_sequence_generator() - : begin_(0), end_(1), step_(1), - current_(0), rounds_(0) { - } - - uint64_t next() { - uint64_t r = current_; - current_ += step_; - if (current_ >= end_) { - current_ = begin_; - ++rounds_; - } - return r; - } - - void reset(uint64_t begin, uint64_t size, uint64_t step = 1) { - begin_ = begin; - end_ = begin + (size / step) * step; - step_ = step; - current_ = begin; - rounds_ = 0; - } - - uint64_t get_rounds() { - return rounds_; - } - - private: - uint64_t begin_; - uint64_t end_; - uint64_t step_; - uint64_t current_; - uint64_t rounds_; - }; - - // - The maximum generated value is not greater than (begin+size) - // - The generated values are not aligned to the step, if the begin - // value is not aligned. - class random_sequence_generator: public sequence_generator { - public: - // TODO: load random seeds - random_sequence_generator(uint64_t begin, - uint64_t size, - uint64_t step, - unsigned seq_nr = 1) - : begin_(begin), - nr_steps_(size / step), - step_(step), - max_forward_steps_(seq_nr), - nr_generated_(0) - { - if (!max_forward_steps_ || max_forward_steps_ > nr_steps_) - throw std::runtime_error("invalid number of forward steps"); - - if (max_forward_steps_ > 1) - reset_forward_generator(); - } - - uint64_t next() { - // FIXME: eliminate if-else - uint64_t step_idx = (max_forward_steps_ > 1) ? - next_forward_step() : next_random_step(); - rand_map_.add(step_idx); - ++nr_generated_; - - // wrap-around - if (nr_generated_ == nr_steps_) { - rand_map_.clear(); - nr_generated_ = 0; - } - - return begin_ + step_idx * step_; - } - - private: - void reset_forward_generator() { - uint64_t begin = next_random_step(); - unsigned seq_nr = (std::rand() % max_forward_steps_) + 1; - forward_gen_.reset(begin, seq_nr); - } - - uint64_t next_forward_step() { - uint64_t step_idx; - - bool found = true; - while (found) { - step_idx = forward_gen_.next(); - found = rand_map_.member(step_idx); - - if (found || forward_gen_.get_rounds()) - reset_forward_generator(); - } - - return step_idx; - } - - uint64_t next_random_step() const { - uint64_t step_idx; - - bool found = true; - while (found) { - step_idx = std::rand() % nr_steps_; - found = rand_map_.member(step_idx); - } - - return step_idx; - } - - uint64_t begin_; - uint64_t nr_steps_; - uint64_t step_; - unsigned max_forward_steps_; - - base::run_set rand_map_; - uint64_t nr_generated_; - forward_sequence_generator forward_gen_; - }; - - //-------------------------------- - class op_generator { public: typedef std::shared_ptr ptr; @@ -242,17 +98,17 @@ namespace { sequence_generator::ptr base_io_generator::create_offset_generator(io_generator_options const &opts) { - sequence_generator *gen; + sequence_generator::ptr gen; if (opts.pattern_.is_random()) - gen = new random_sequence_generator(opts.offset_, + gen = create_random_sequence_generator(opts.offset_, opts.size_, opts.block_size_, opts.nr_seq_blocks_); else - gen = new forward_sequence_generator(opts.offset_, + gen = create_forward_sequence_generator(opts.offset_, opts.size_, opts.block_size_); - return sequence_generator::ptr(gen); + return gen; } op_generator::ptr diff --git a/base/sequence_generator.cc b/base/sequence_generator.cc new file mode 100644 index 0000000..a811b48 --- /dev/null +++ b/base/sequence_generator.cc @@ -0,0 +1,165 @@ +#include "base/run_set.h" +#include "base/sequence_generator.h" +#include + +//---------------------------------------------------------------- + +namespace { + // - The maximum generated value is not greater than (begin+size) + // - The generated values are not aligned to the step, if the begin + // value is not aligned. + class forward_sequence_generator: public base::sequence_generator { + public: + forward_sequence_generator(uint64_t begin, + uint64_t size, + uint64_t step) + : begin_(begin), + end_(begin + (size / step) * step), + step_(step), + current_(begin), + rounds_(0) { + if (size < step) + throw std::runtime_error("size must be greater than the step"); + } + + forward_sequence_generator() + : begin_(0), end_(1), step_(1), + current_(0), rounds_(0) { + } + + uint64_t next() { + uint64_t r = current_; + current_ += step_; + if (current_ >= end_) { + current_ = begin_; + ++rounds_; + } + return r; + } + + void reset(uint64_t begin, uint64_t size, uint64_t step = 1) { + begin_ = begin; + end_ = begin + (size / step) * step; + step_ = step; + current_ = begin; + rounds_ = 0; + } + + uint64_t get_rounds() { + return rounds_; + } + + private: + uint64_t begin_; + uint64_t end_; + uint64_t step_; + uint64_t current_; + uint64_t rounds_; + }; + + // - The maximum generated value is not greater than (begin+size) + // - The generated values are not aligned to the step, if the begin + // value is not aligned. + class random_sequence_generator: public base::sequence_generator { + public: + // TODO: load random seeds + random_sequence_generator(uint64_t begin, + uint64_t size, + uint64_t step, + unsigned seq_nr = 1) + : begin_(begin), + nr_steps_(size / step), + step_(step), + max_forward_steps_(seq_nr), + nr_generated_(0) + { + if (!max_forward_steps_ || max_forward_steps_ > nr_steps_) + throw std::runtime_error("invalid number of forward steps"); + + if (max_forward_steps_ > 1) + reset_forward_generator(); + } + + uint64_t next() { + // FIXME: eliminate if-else + uint64_t step_idx = (max_forward_steps_ > 1) ? + next_forward_step() : next_random_step(); + rand_map_.add(step_idx); + ++nr_generated_; + + // wrap-around + if (nr_generated_ == nr_steps_) { + rand_map_.clear(); + nr_generated_ = 0; + } + + return begin_ + step_idx * step_; + } + + private: + void reset_forward_generator() { + uint64_t begin = next_random_step(); + unsigned seq_nr = (std::rand() % max_forward_steps_) + 1; + forward_gen_.reset(begin, seq_nr); + } + + uint64_t next_forward_step() { + uint64_t step_idx; + + bool found = true; + while (found) { + step_idx = forward_gen_.next(); + found = rand_map_.member(step_idx); + + if (found || forward_gen_.get_rounds()) + reset_forward_generator(); + } + + return step_idx; + } + + uint64_t next_random_step() const { + uint64_t step_idx; + + bool found = true; + while (found) { + step_idx = std::rand() % nr_steps_; + found = rand_map_.member(step_idx); + } + + return step_idx; + } + + uint64_t begin_; + uint64_t nr_steps_; + uint64_t step_; + unsigned max_forward_steps_; + + base::run_set rand_map_; + uint64_t nr_generated_; + forward_sequence_generator forward_gen_; + }; +} + +//---------------------------------------------------------------- + +base::sequence_generator::ptr +base::create_forward_sequence_generator(uint64_t begin, + uint64_t size, + uint64_t step) +{ + return sequence_generator::ptr( + new forward_sequence_generator(begin, size, step)); +} + +base::sequence_generator::ptr +base::create_random_sequence_generator(uint64_t begin, + uint64_t size, + uint64_t step, + unsigned seq_nr) +{ + return sequence_generator::ptr( + new random_sequence_generator(begin, size, step, seq_nr)); +} + +//---------------------------------------------------------------- diff --git a/base/sequence_generator.h b/base/sequence_generator.h new file mode 100644 index 0000000..fa2150a --- /dev/null +++ b/base/sequence_generator.h @@ -0,0 +1,27 @@ +#ifndef BASE_SEQUENCE_GENERATOR_H +#define BASE_SEQUENCE_GENERATOR_H + +#include + +//---------------------------------------------------------------- + +namespace base { + class sequence_generator { + public: + typedef std::shared_ptr ptr; + + virtual uint64_t next() = 0; + }; + + sequence_generator::ptr + create_forward_sequence_generator(uint64_t begin, uint64_t size, + uint64_t step); + + sequence_generator::ptr + create_random_sequence_generator(uint64_t begin, uint64_t size, + uint64_t step, unsigned seq_nr = 1); +} + +//---------------------------------------------------------------- + +#endif