[base] Factor out sequence_generator
This commit is contained in:
parent
e62022a200
commit
105b8ec1cf
@ -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 \
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "base/io_generator.h"
|
||||
#include "base/run_set.h"
|
||||
#include "base/sequence_generator.h"
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -26,150 +26,6 @@ namespace {
|
||||
|
||||
//--------------------------------
|
||||
|
||||
class sequence_generator {
|
||||
public:
|
||||
typedef std::shared_ptr<sequence_generator> 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<uint64_t> rand_map_;
|
||||
uint64_t nr_generated_;
|
||||
forward_sequence_generator forward_gen_;
|
||||
};
|
||||
|
||||
//--------------------------------
|
||||
|
||||
class op_generator {
|
||||
public:
|
||||
typedef std::shared_ptr<op_generator> 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
|
||||
|
165
base/sequence_generator.cc
Normal file
165
base/sequence_generator.cc
Normal file
@ -0,0 +1,165 @@
|
||||
#include "base/run_set.h"
|
||||
#include "base/sequence_generator.h"
|
||||
#include <stdexcept>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
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<uint64_t> 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));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
27
base/sequence_generator.h
Normal file
27
base/sequence_generator.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef BASE_SEQUENCE_GENERATOR_H
|
||||
#define BASE_SEQUENCE_GENERATOR_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace base {
|
||||
class sequence_generator {
|
||||
public:
|
||||
typedef std::shared_ptr<sequence_generator> 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
|
Loading…
Reference in New Issue
Block a user