[io_generator] Support mixed sequential and random io pattern
This commit is contained in:
		| @@ -44,25 +44,45 @@ namespace { | ||||
| 			: begin_(begin), | ||||
| 			  end_(begin + (size / step) * step), | ||||
| 			  step_(step), | ||||
| 			  current_(begin) { | ||||
| 			  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) | ||||
| @@ -73,21 +93,25 @@ namespace { | ||||
| 		// TODO: load random seeds | ||||
| 		random_sequence_generator(uint64_t begin, | ||||
| 					  uint64_t size, | ||||
| 					  uint64_t step) | ||||
| 					  uint64_t step, | ||||
| 					  unsigned seq_nr = 1) | ||||
| 			: begin_(begin), | ||||
| 			  nr_steps_(size / step), | ||||
| 			  step_(step), | ||||
| 			  nr_generated_(0) { | ||||
| 			  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() { | ||||
| 			uint64_t step_idx; | ||||
|  | ||||
| 			bool found = true; | ||||
| 			while (found) { | ||||
| 				step_idx = std::rand() % nr_steps_; | ||||
| 				found = rand_map_.member(step_idx); | ||||
| 			} | ||||
| 			// 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_; | ||||
|  | ||||
| @@ -101,12 +125,47 @@ namespace { | ||||
| 		} | ||||
|  | ||||
| 	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_; | ||||
| 	}; | ||||
|  | ||||
| 	//-------------------------------- | ||||
| @@ -187,7 +246,8 @@ namespace { | ||||
|  | ||||
| 		if (opts.pattern_.is_random()) | ||||
| 			gen = new random_sequence_generator(opts.offset_, | ||||
| 					opts.size_, opts.block_size_); | ||||
| 					opts.size_, opts.block_size_, | ||||
| 					opts.nr_seq_blocks_); | ||||
| 		else | ||||
| 			gen = new forward_sequence_generator(opts.offset_, | ||||
| 					opts.size_, opts.block_size_); | ||||
|   | ||||
| @@ -36,6 +36,7 @@ namespace base { | ||||
| 		sector_t block_size_; | ||||
| 		sector_t size_; | ||||
| 		sector_t io_size_; | ||||
| 		unsigned nr_seq_blocks_; | ||||
| 	}; | ||||
|  | ||||
| 	class io_generator { | ||||
|   | ||||
| @@ -47,6 +47,7 @@ namespace { | ||||
| 		base::sector_t offset; | ||||
| 		boost::optional<base::sector_t> size; | ||||
| 		boost::optional<base::sector_t> io_size; | ||||
| 		boost::optional<unsigned> nr_seq_blocks; | ||||
| 	}; | ||||
|  | ||||
| 	bool flags::check_conformance() { | ||||
| @@ -65,6 +66,14 @@ namespace { | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		if (nr_seq_blocks) { | ||||
| 			if (!pattern.is_random()) { | ||||
| 				cerr << "Cannot specify the sequence size" | ||||
| 					" while doing non-random IO" << endl; | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		check_output_file_requirements(*output); | ||||
|  | ||||
| 		return true; | ||||
| @@ -90,6 +99,7 @@ namespace { | ||||
| 		opts.offset_ = fs.offset; | ||||
| 		opts.size_ = *fs.size; | ||||
| 		opts.io_size_ = !fs.io_size ? *fs.size : *fs.io_size; | ||||
| 		opts.nr_seq_blocks_ = !fs.nr_seq_blocks ? 1 : *fs.nr_seq_blocks; | ||||
| 		io_generator::ptr gen = create_io_generator(opts); | ||||
|  | ||||
| 		base::io io; | ||||
| @@ -133,6 +143,7 @@ thin_generate_mappings_cmd::usage(std::ostream &out) const | ||||
| 	    << "  {--io-size} <io-size in sectors>\n" | ||||
| 	    << "  {--rw write|trim|randwrite|randtrim|randtw}\n" | ||||
| 	    << "  {--size} <size in sectors>\n" | ||||
| 	    << "  {--seq-nr} <max nr. of sequential ios>\n" | ||||
| 	    << "  {-V|--version}" << endl; | ||||
| } | ||||
|  | ||||
| @@ -150,6 +161,7 @@ thin_generate_mappings_cmd::run(int argc, char **argv) | ||||
| 		{ "offset", required_argument, NULL, 3 }, | ||||
| 		{ "size", required_argument, NULL, 4 }, | ||||
| 		{ "io-size", required_argument, NULL, 5 }, | ||||
| 		{ "seq-nr", required_argument, NULL, 6 }, | ||||
| 		{ "version", no_argument, NULL, 'V' }, | ||||
| 		{ NULL, no_argument, NULL, 0 } | ||||
| 	}; | ||||
| @@ -184,6 +196,10 @@ thin_generate_mappings_cmd::run(int argc, char **argv) | ||||
| 			fs.io_size = parse_uint64(optarg, "io_size"); | ||||
| 			break; | ||||
|  | ||||
| 		case 6: | ||||
| 			fs.nr_seq_blocks = parse_uint64(optarg, "seq_nr"); | ||||
| 			break; | ||||
|  | ||||
| 		case 'V': | ||||
| 			cout << THIN_PROVISIONING_TOOLS_VERSION << endl; | ||||
| 			return 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user