From: Jens Axboe Date: Tue, 20 Jul 2010 20:46:00 +0000 (-0600) Subject: Add rw_sequencer option X-Git-Tag: fio-1.43-rc1~16 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=38dad62d5154ffaad445bd0231b271b9a46a5190;hp=5736c10dccc4124d99178b94e6759386420e5251 Add rw_sequencer option Signed-off-by: Jens Axboe --- diff --git a/HOWTO b/HOWTO index bd5bebfc..0ef7ca42 100644 --- a/HOWTO +++ b/HOWTO @@ -313,13 +313,30 @@ rw=str Type of io pattern. Accepted values are: For the mixed io types, the default is to split them 50/50. For certain types of io the result may still be skewed a bit, since the speed may be different. It is possible to specify - a number of IO's to do before getting a new offset - this - is only useful for random IO, where fio would normally - generate a new random offset for every IO. If you append - eg 8 to randread, you would get a new random offset for + a number of IO's to do before getting a new offset, this is + one by appending a ':' to the end of the string given. + For a random read, it would look like 'rw=randread:8' for + passing in an offset modifier with a value of 8. See the + 'rw_sequencer' option. + +rw_sequencer=str If an offset modifier is given by appending a number to + the rw= line, then this option controls how that + number modifies the IO offset being generated. Accepted + values are: + + sequential Generate sequential offset + identical Generate the same offset + + 'sequential' is only useful for random IO, where fio would + normally generate a new random offset for every IO. If you + append eg 8 to randread, you would get a new random offset for every 8 IO's. The result would be a seek for only every 8 IO's, instead of for every IO. Use rw=randread:8 to specify - that. + that. As sequential IO is already sequential, setting + 'sequential' for that would not result in any differences. + 'identical' behaves in a similar fashion, except it sends + the same offset 8 number of times before generating a new + offset. kb_base=int The base unit for a kilobyte. The defacto base is 2^10, 1024. Storage manufacturers like to use 10^3 or 1000 as a base diff --git a/file.h b/file.h index 30293fc9..3b4ed0b9 100644 --- a/file.h +++ b/file.h @@ -73,6 +73,7 @@ struct fio_file { unsigned long long io_size; unsigned long long last_pos; + unsigned long long last_start; unsigned long long first_write; unsigned long long last_write; @@ -155,6 +156,7 @@ static inline void fio_file_reset(struct fio_file *f) { f->last_free_lookup = 0; f->last_pos = f->file_offset; + f->last_start = -1ULL; f->file_pos = -1ULL; if (f->file_map) memset(f->file_map, 0, f->num_maps * sizeof(int)); diff --git a/filesetup.c b/filesetup.c index f0883901..d2b74d7f 100644 --- a/filesetup.c +++ b/filesetup.c @@ -909,6 +909,7 @@ int add_file(struct thread_data *td, const char *fname) } f->fd = -1; + fio_file_reset(f); if (td->files_size <= td->files_index) { int new_size = td->o.nr_files + 1; @@ -1136,6 +1137,7 @@ void dup_files(struct thread_data *td, struct thread_data *org) assert(0); } __f->fd = -1; + fio_file_reset(__f); if (f->file_name) { __f->file_name = smalloc_strdup(f->file_name); diff --git a/fio.1 b/fio.1 index 77773a0c..c5c10af4 100644 --- a/fio.1 +++ b/fio.1 @@ -172,11 +172,39 @@ Mixed sequential reads and writes. Mixed random reads and writes. .RE .P -For mixed I/O, the default split is 50/50. For random I/O, the number of I/Os -to perform before getting a new offset can be specified by appending -`:\fIint\fR' to the pattern type. The default is 1. +For mixed I/O, the default split is 50/50. For certain types of io the result +may still be skewed a bit, since the speed may be different. It is possible to +specify a number of IO's to do before getting a new offset, this is one by +appending a `:\fI\fR to the end of the string given. For a random read, it +would look like \fBrw=randread:8\fR for passing in an offset modifier with a +value of 8. See the \fBrw_sequencer\fR option. .RE .TP +.BI rw_sequencer \fR=\fPstr +If an offset modifier is given by appending a number to the \fBrw=\fR line, +then this option controls how that number modifies the IO offset being +generated. Accepted values are: +.RS +.RS +.TP +.B sequential +Generate sequential offset +.TP +.B identical +Generate the same offset +.RE +.P +\fBsequential\fR is only useful for random IO, where fio would normally +generate a new random offset for every IO. If you append eg 8 to randread, you +would get a new random offset for every 8 IO's. The result would be a seek for +only every 8 IO's, instead of for every IO. Use \fBrw=randread:8\fR to specify +that. As sequential IO is already sequential, setting \fBsequential\fR for that +would not result in any differences. \fBidentical\fR behaves in a similar +fashion, except it sends the same offset 8 number of times before generating a +new offset. +.RE +.P +.TP .BI kb_base \fR=\fPint The base unit for a kilobyte. The defacto base is 2^10, 1024. Storage manufacturers like to use 10^3 or 1000 as a base ten unit instead, for obvious diff --git a/fio.h b/fio.h index e9fdc68f..de76e659 100644 --- a/fio.h +++ b/fio.h @@ -60,6 +60,14 @@ enum fio_memtype { MEM_MMAPHUGE, /* memory mapped huge file */ }; +/* + * offset generator types + */ +enum { + RW_SEQ_SEQ = 0, + RW_SEQ_IDENT, +}; + /* * How many depth levels to log */ @@ -145,6 +153,7 @@ struct thread_options { char *opendir; char *ioengine; enum td_ddir td_ddir; + unsigned int rw_seq; unsigned int kb_base; unsigned int ddir_seq_nr; unsigned int iodepth; diff --git a/init.c b/init.c index bc1bb933..09b9152a 100644 --- a/init.c +++ b/init.c @@ -557,7 +557,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num) td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX; td->ts.lat_stat[0].min_val = td->ts.lat_stat[1].min_val = ULONG_MAX; td->ts.bw_stat[0].min_val = td->ts.bw_stat[1].min_val = ULONG_MAX; - td->ddir_seq_nr = td->o.ddir_seq_nr; + td->ddir_seq_nr = td->o.ddir_seq_nr + 1; if ((td->o.stonewall || td->o.new_group) && prev_group_jobs) { prev_group_jobs = 0; diff --git a/io_u.c b/io_u.c index bb00559c..3eeade26 100644 --- a/io_u.c +++ b/io_u.c @@ -41,10 +41,12 @@ static void mark_random_map(struct thread_data *td, struct io_u *io_u) struct fio_file *f = io_u->file; unsigned long long block; unsigned int blocks, nr_blocks; + int busy_check; block = (io_u->offset - f->file_offset) / (unsigned long long) min_bs; nr_blocks = (io_u->buflen + min_bs - 1) / min_bs; blocks = 0; + busy_check = !(io_u->flags & IO_U_F_BUSY_OK); while (nr_blocks) { unsigned int this_blocks, mask; @@ -54,6 +56,10 @@ static void mark_random_map(struct thread_data *td, struct io_u *io_u) * If we have a mixed random workload, we may * encounter blocks we already did IO to. */ + if (!busy_check) { + blocks = nr_blocks; + break; + } if ((td->o.ddir_seq_nr == 1) && !random_map_free(f, block)) break; @@ -190,6 +196,62 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, return get_next_free_block(td, f, ddir, b); } +static int get_next_rand_block(struct thread_data *td, struct fio_file *f, + enum fio_ddir ddir, unsigned long long *b) +{ + if (get_next_rand_offset(td, f, ddir, b)) { + dprint(FD_IO, "%s: rand offset failed, last=%llu, size=%llu\n", + f->file_name, f->last_pos, f->real_file_size); + return 1; + } + + return 0; +} + +static int get_next_seq_block(struct thread_data *td, struct fio_file *f, + enum fio_ddir ddir, unsigned long long *b) +{ + if (f->last_pos < f->real_file_size) { + *b = (f->last_pos - f->file_offset) / td->o.min_bs[ddir]; + return 0; + } + + return 1; +} + +static int get_next_block(struct thread_data *td, struct io_u *io_u, + enum fio_ddir ddir, int rw_seq, unsigned long long *b) +{ + struct fio_file *f = io_u->file; + int ret; + + if (rw_seq) { + if (td_random(td)) + ret = get_next_rand_block(td, f, ddir, b); + else + ret = get_next_seq_block(td, f, ddir, b); + } else { + io_u->flags |= IO_U_F_BUSY_OK; + + if (td->o.rw_seq == RW_SEQ_SEQ) { + ret = get_next_seq_block(td, f, ddir, b); + if (ret) + ret = get_next_rand_block(td, f, ddir, b); + } else if (td->o.rw_seq == RW_SEQ_IDENT) { + if (f->last_start != -1ULL) + *b = (f->last_start - f->file_offset) / td->o.min_bs[ddir]; + else + *b = 0; + ret = 0; + } else { + log_err("fio: unknown rw_seq=%d\n", td->o.rw_seq); + ret = 1; + } + } + + return ret; +} + /* * For random io, generate a random new block and see if it's used. Repeat * until we find a free one. For sequential io, just return the end of @@ -200,26 +262,16 @@ static int __get_next_offset(struct thread_data *td, struct io_u *io_u) struct fio_file *f = io_u->file; unsigned long long b; enum fio_ddir ddir = io_u->ddir; + int rw_seq_hit = 0; - if (td_random(td) && (td->o.ddir_seq_nr && !--td->ddir_seq_nr)) { + if (td->o.ddir_seq_nr && !--td->ddir_seq_nr) { + rw_seq_hit = 1; td->ddir_seq_nr = td->o.ddir_seq_nr; + } - if (get_next_rand_offset(td, f, ddir, &b)) { - dprint(FD_IO, "%s: getting rand offset failed\n", - f->file_name); - return 1; - } - } else { - if (f->last_pos >= f->real_file_size) { - if (!td_random(td) || - get_next_rand_offset(td, f, ddir, &b)) { - dprint(FD_IO, "%s: pos %llu > size %llu\n", - f->file_name, f->last_pos, - f->real_file_size); - return 1; - } - } else - b = (f->last_pos - f->file_offset) / td->o.min_bs[ddir]; + if (get_next_block(td, io_u, ddir, rw_seq_hit, &b)) { + printf("fail\n"); + return 1; } io_u->offset = b * td->o.ba[ddir]; @@ -977,6 +1029,7 @@ struct io_u *get_io_u(struct thread_data *td) goto err_put; } + f->last_start = io_u->offset; f->last_pos = io_u->offset + io_u->buflen; if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_WRITE) @@ -1042,7 +1095,7 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, td_io_u_lock(td); assert(io_u->flags & IO_U_F_FLIGHT); - io_u->flags &= ~IO_U_F_FLIGHT; + io_u->flags &= ~(IO_U_F_FLIGHT | IO_U_F_BUSY_OK); td_io_u_unlock(td); if (ddir_sync(io_u->ddir)) { diff --git a/ioengine.h b/ioengine.h index ff3069bf..389e95a5 100644 --- a/ioengine.h +++ b/ioengine.h @@ -8,6 +8,7 @@ enum { IO_U_F_FLIGHT = 1 << 1, IO_U_F_FREE_DEF = 1 << 2, IO_U_F_IN_CUR_DEPTH = 1 << 3, + IO_U_F_BUSY_OK = 1 << 4, }; /* diff --git a/options.c b/options.c index c9fb8862..10e58dba 100644 --- a/options.c +++ b/options.c @@ -881,6 +881,24 @@ static struct fio_option options[FIO_MAX_OPTS] = { }, }, }, + { + .name = "rw_sequencer", + .type = FIO_OPT_STR, + .off1 = td_var_offset(rw_seq), + .help = "IO offset generator modifier", + .def = "sequential", + .posval = { + { .ival = "sequential", + .oval = RW_SEQ_SEQ, + .help = "Generate sequential offsets", + }, + { .ival = "identical", + .oval = RW_SEQ_IDENT, + .help = "Generate identical offsets", + }, + }, + }, + { .name = "ioengine", .type = FIO_OPT_STR_STORE,