X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=io_u.c;h=ebd75c1b6ebba517e617e004290713610b6f0608;hp=af3b415160609d9dbb5317ef27c4d67d004be23b;hb=9e98688960347b9b733db9426fb7747f22d3a77e;hpb=5c94b00876437a27f1761e47437166780c3c3b93 diff --git a/io_u.c b/io_u.c index af3b4151..ebd75c1b 100644 --- a/io_u.c +++ b/io_u.c @@ -68,6 +68,9 @@ static uint64_t last_block(struct thread_data *td, struct fio_file *f, if (td->o.zone_range) max_size = td->o.zone_range; + if (td->o.min_bs[ddir] > td->o.ba[ddir]) + max_size -= td->o.min_bs[ddir] - td->o.ba[ddir]; + max_blocks = max_size / (uint64_t) td->o.ba[ddir]; if (!max_blocks) return 0; @@ -83,32 +86,26 @@ struct rand_off { static int __get_next_rand_offset(struct thread_data *td, struct fio_file *f, enum fio_ddir ddir, uint64_t *b) { - uint64_t r, lastb; - - lastb = last_block(td, f, ddir); - if (!lastb) - return 1; + uint64_t r; if (td->o.random_generator == FIO_RAND_GEN_TAUSWORTHE) { - uint64_t rmax; + uint64_t lastb; - rmax = td->o.use_os_rand ? OS_RAND_MAX : FRAND_MAX; + lastb = last_block(td, f, ddir); + if (!lastb) + return 1; - if (td->o.use_os_rand) { - rmax = OS_RAND_MAX; - r = os_random_long(&td->random_state); - } else { - rmax = FRAND_MAX; - r = __rand(&td->__random_state); - } + r = __rand(&td->random_state); dprint(FD_RANDOM, "off rand %llu\n", (unsigned long long) r); - *b = lastb * (r / ((uint64_t) rmax + 1.0)); + *b = lastb * (r / ((uint64_t) FRAND_MAX + 1.0)); } else { uint64_t off = 0; - if (lfsr_next(&f->lfsr, &off, lastb)) + assert(fio_file_lfsr(f)); + + if (lfsr_next(&f->lfsr, &off)) return 1; *b = off; @@ -152,6 +149,15 @@ static int __get_next_rand_offset_pareto(struct thread_data *td, return 0; } +static int __get_next_rand_offset_gauss(struct thread_data *td, + struct fio_file *f, enum fio_ddir ddir, + uint64_t *b) +{ + *b = gauss_next(&f->gauss); + return 0; +} + + static int flist_cmp(void *data, struct flist_head *a, struct flist_head *b) { struct rand_off *r1 = flist_entry(a, struct rand_off, list); @@ -169,6 +175,8 @@ static int get_off_from_method(struct thread_data *td, struct fio_file *f, return __get_next_rand_offset_zipf(td, f, ddir, b); else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) return __get_next_rand_offset_pareto(td, f, ddir, b); + else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS) + return __get_next_rand_offset_gauss(td, f, ddir, b); log_err("fio: unknown random distribution: %d\n", td->o.random_distribution); return 1; @@ -200,13 +208,8 @@ static int should_do_random(struct thread_data *td, enum fio_ddir ddir) if (td->o.perc_rand[ddir] == 100) return 1; - if (td->o.use_os_rand) { - r = os_random_long(&td->seq_rand_state[ddir]); - v = 1 + (int) (100.0 * (r / (OS_RAND_MAX + 1.0))); - } else { - r = __rand(&td->__seq_rand_state[ddir]); - v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); - } + r = __rand(&td->seq_rand_state[ddir]); + v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); return v <= td->o.perc_rand[ddir]; } @@ -221,7 +224,6 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, return get_off_from_method(td, f, ddir, b); if (!flist_empty(&td->next_rand_list)) { - struct rand_off *r; fetch: r = flist_first_entry(&td->next_rand_list, struct rand_off, list); flist_del(&r->list); @@ -263,7 +265,7 @@ static int get_next_rand_block(struct thread_data *td, struct fio_file *f, } dprint(FD_IO, "%s: rand offset failed, last=%llu, size=%llu\n", - f->file_name, (unsigned long long) f->last_pos, + f->file_name, (unsigned long long) f->last_pos[ddir], (unsigned long long) f->real_file_size); return 1; } @@ -271,20 +273,32 @@ static int get_next_rand_block(struct thread_data *td, struct fio_file *f, static int get_next_seq_offset(struct thread_data *td, struct fio_file *f, enum fio_ddir ddir, uint64_t *offset) { + struct thread_options *o = &td->o; + assert(ddir_rw(ddir)); - if (f->last_pos >= f->io_size + get_start_offset(td, f) && td->o.time_based) - f->last_pos = f->last_pos - f->io_size; + if (f->last_pos[ddir] >= f->io_size + get_start_offset(td, f) && + o->time_based) + f->last_pos[ddir] = f->last_pos[ddir] - f->io_size; - if (f->last_pos < f->real_file_size) { + if (f->last_pos[ddir] < f->real_file_size) { uint64_t pos; - if (f->last_pos == f->file_offset && td->o.ddir_seq_add < 0) - f->last_pos = f->real_file_size; + if (f->last_pos[ddir] == f->file_offset && o->ddir_seq_add < 0) + f->last_pos[ddir] = f->real_file_size; - pos = f->last_pos - f->file_offset; - if (pos) - pos += td->o.ddir_seq_add; + pos = f->last_pos[ddir] - f->file_offset; + if (pos && o->ddir_seq_add) { + pos += o->ddir_seq_add; + + /* + * If we reach beyond the end of the file + * with holed IO, wrap around to the + * beginning again. + */ + if (pos >= f->real_file_size) + pos = f->file_offset; + } *offset = pos; return 0; @@ -332,8 +346,8 @@ static int get_next_block(struct thread_data *td, struct io_u *io_u, *is_random = 0; } } else if (td->o.rw_seq == RW_SEQ_IDENT) { - if (f->last_start != -1ULL) - offset = f->last_start - f->file_offset; + if (f->last_start[ddir] != -1ULL) + offset = f->last_start[ddir] - f->file_offset; else offset = 0; ret = 0; @@ -424,7 +438,7 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u, int ddir = io_u->ddir; unsigned int buflen = 0; unsigned int minbs, maxbs; - unsigned long r, rand_max; + unsigned long r; assert(ddir_rw(ddir)); @@ -443,20 +457,12 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u, if (!io_u_fits(td, io_u, minbs)) return 0; - if (td->o.use_os_rand) - rand_max = OS_RAND_MAX; - else - rand_max = FRAND_MAX; - do { - if (td->o.use_os_rand) - r = os_random_long(&td->bsrange_state); - else - r = __rand(&td->__bsrange_state); + r = __rand(&td->bsrange_state); if (!td->o.bssplit_nr[ddir]) { buflen = 1 + (unsigned int) ((double) maxbs * - (r / (rand_max + 1.0))); + (r / (FRAND_MAX + 1.0))); if (buflen < minbs) buflen = minbs; } else { @@ -468,7 +474,7 @@ static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u, buflen = bsp->bs; perc += bsp->perc; - if ((r <= ((rand_max / 100L) * perc)) && + if ((r <= ((FRAND_MAX / 100L) * perc)) && io_u_fits(td, io_u, buflen)) break; } @@ -517,13 +523,8 @@ static inline enum fio_ddir get_rand_ddir(struct thread_data *td) unsigned int v; unsigned long r; - if (td->o.use_os_rand) { - r = os_random_long(&td->rwmix_state); - v = 1 + (int) (100.0 * (r / (OS_RAND_MAX + 1.0))); - } else { - r = __rand(&td->__rwmix_state); - v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); - } + r = __rand(&td->rwmix_state); + v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); if (v <= td->o.rwmix[DDIR_READ]) return DDIR_READ; @@ -542,6 +543,12 @@ void io_u_quiesce(struct thread_data *td) * io's that have been actually submitted to an async engine, * and cur_depth is meaningless for sync engines. */ + if (td->io_u_queued || td->cur_depth) { + int fio_unused ret; + + ret = td_io_commit(td); + } + while (td->io_u_in_flight) { int fio_unused ret; @@ -552,7 +559,6 @@ void io_u_quiesce(struct thread_data *td) static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) { enum fio_ddir odir = ddir ^ 1; - struct timeval t; long usec; assert(ddir_rw(ddir)); @@ -587,9 +593,7 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) io_u_quiesce(td); - fio_gettime(&t, NULL); - usec_sleep(td, usec); - usec = utime_since_now(&t); + usec = usec_sleep(td, usec); td->rate_pending_usleep[ddir] -= usec; @@ -597,9 +601,6 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) if (td_rw(td) && __should_check_rate(td, odir)) td->rate_pending_usleep[odir] -= usec; - if (ddir_trim(ddir)) - return ddir; - return ddir; } @@ -667,7 +668,17 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td) static void set_rw_ddir(struct thread_data *td, struct io_u *io_u) { - io_u->ddir = io_u->acct_ddir = get_rw_ddir(td); + enum fio_ddir ddir = get_rw_ddir(td); + + if (td_trimwrite(td)) { + struct fio_file *f = io_u->file; + if (f->last_pos[DDIR_WRITE] == f->last_pos[DDIR_TRIM]) + ddir = DDIR_TRIM; + else + ddir = DDIR_WRITE; + } + + io_u->ddir = io_u->acct_ddir = ddir; if (io_u->ddir == DDIR_WRITE && (td->io_ops->flags & FIO_BARRIER) && td->o.barrier_blocks && @@ -748,9 +759,17 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u) * See if it's time to switch to a new zone */ if (td->zone_bytes >= td->o.zone_size && td->o.zone_skip) { + struct fio_file *f = io_u->file; + td->zone_bytes = 0; - io_u->file->file_offset += td->o.zone_range + td->o.zone_skip; - io_u->file->last_pos = io_u->file->file_offset; + f->file_offset += td->o.zone_range + td->o.zone_skip; + + /* + * Wrap from the beginning, if we exceed the file size + */ + if (f->file_offset >= f->real_file_size) + f->file_offset = f->real_file_size - f->file_offset; + f->last_pos[io_u->ddir] = f->file_offset; td->io_skip_bytes += td->o.zone_skip; } @@ -967,15 +986,9 @@ static struct fio_file *get_next_file_rand(struct thread_data *td, int opened = 0; unsigned long r; - if (td->o.use_os_rand) { - r = os_random_long(&td->next_file_state); - fno = (unsigned int) ((double) td->o.nr_files - * (r / (OS_RAND_MAX + 1.0))); - } else { - r = __rand(&td->__next_file_state); - fno = (unsigned int) ((double) td->o.nr_files + r = __rand(&td->next_file_state); + fno = (unsigned int) ((double) td->o.nr_files * (r / (FRAND_MAX + 1.0))); - } f = td->files[fno]; if (fio_file_done(f)) @@ -1281,7 +1294,7 @@ void lat_target_check(struct thread_data *td) * If latency target is enabled, we might be ramping up or down and not * using the full queue depth available. */ -int queue_full(struct thread_data *td) +int queue_full(const struct thread_data *td) { const int qempty = io_u_qempty(&td->io_u_freelist); @@ -1297,6 +1310,9 @@ struct io_u *__get_io_u(struct thread_data *td) { struct io_u *io_u = NULL; + if (td->stop_io) + return NULL; + td_io_u_lock(td); again: @@ -1481,13 +1497,14 @@ 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; + f->last_start[io_u->ddir] = io_u->offset; + f->last_pos[io_u->ddir] = io_u->offset + io_u->buflen; if (io_u->ddir == DDIR_WRITE) { if (td->flags & TD_F_REFILL_BUFFERS) { io_u_fill_buffer(td, io_u, - io_u->xfer_buflen, io_u->xfer_buflen); + td->o.min_bs[DDIR_WRITE], + io_u->xfer_buflen); } else if ((td->flags & TD_F_SCRAMBLE_BUFFERS) && !(td->flags & TD_F_COMPRESS)) do_scramble = 1; @@ -1589,6 +1606,19 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u, if (!gtod_reduce(td)) add_iops_sample(td, idx, bytes, &icd->time); + + if (td->ts.nr_block_infos && io_u->ddir == DDIR_TRIM) { + uint32_t *info = io_u_block_info(td, io_u); + if (BLOCK_INFO_STATE(*info) < BLOCK_STATE_TRIM_FAILURE) { + if (io_u->ddir == DDIR_TRIM) { + *info = BLOCK_INFO(BLOCK_STATE_TRIMMED, + BLOCK_INFO_TRIMS(*info) + 1); + } else if (io_u->ddir == DDIR_WRITE) { + *info = BLOCK_INFO_SET_STATE(BLOCK_STATE_WRITTEN, + *info); + } + } + } } static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir) @@ -1656,13 +1686,22 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr, if (!(io_u->flags & IO_U_F_VER_LIST)) td->this_io_bytes[ddir] += bytes; - if (ddir == DDIR_WRITE && f) { - if (f->first_write == -1ULL || - io_u->offset < f->first_write) - f->first_write = io_u->offset; - if (f->last_write == -1ULL || - ((io_u->offset + bytes) > f->last_write)) - f->last_write = io_u->offset + bytes; + if (ddir == DDIR_WRITE) { + if (f) { + if (f->first_write == -1ULL || + io_u->offset < f->first_write) + f->first_write = io_u->offset; + if (f->last_write == -1ULL || + ((io_u->offset + bytes) > f->last_write)) + f->last_write = io_u->offset + bytes; + } + if (td->last_write_comp) { + int idx = td->last_write_idx++; + + td->last_write_comp[idx] = io_u->offset; + if (td->last_write_idx == td->o.iodepth) + td->last_write_idx = 0; + } } if (ramp_time_over(td) && (td->runstate == TD_RUNNING || @@ -1838,6 +1877,8 @@ static struct frand_state *get_buf_state(struct thread_data *td) if (!td->o.dedupe_percentage) return &td->buf_state; + else if (td->o.dedupe_percentage == 100) + return &td->buf_state_prev; r = __rand(&td->dedupe_state); v = 1 + (int) (100.0 * (r / (FRAND_MAX + 1.0))); @@ -1857,29 +1898,41 @@ static void save_buf_state(struct thread_data *td, struct frand_state *rs) void fill_io_buffer(struct thread_data *td, void *buf, unsigned int min_write, unsigned int max_bs) { - if (td->o.buffer_pattern_bytes) - fill_buffer_pattern(td, buf, max_bs); - else if (!td->o.zero_buffers) { + struct thread_options *o = &td->o; + + if (o->compress_percentage || o->dedupe_percentage) { unsigned int perc = td->o.compress_percentage; struct frand_state *rs; + unsigned int left = max_bs; - rs = get_buf_state(td); + do { + rs = get_buf_state(td); - if (perc) { - unsigned int seg = min_write; + min_write = min(min_write, left); - seg = min(min_write, td->o.compress_chunk); - if (!seg) - seg = min_write; + if (perc) { + unsigned int seg = min_write; - fill_random_buf_percentage(rs, buf, perc, seg,max_bs); - save_buf_state(td, rs); - } else { - fill_random_buf(rs, buf, max_bs); + seg = min(min_write, td->o.compress_chunk); + if (!seg) + seg = min_write; + + fill_random_buf_percentage(rs, buf, perc, seg, + min_write, o->buffer_pattern, + o->buffer_pattern_bytes); + } else + fill_random_buf(rs, buf, min_write); + + buf += min_write; + left -= min_write; save_buf_state(td, rs); - } - } else + } while (left); + } else if (o->buffer_pattern_bytes) + fill_buffer_pattern(td, buf, max_bs); + else if (o->zero_buffers) memset(buf, 0, max_bs); + else + fill_random_buf(get_buf_state(td), buf, max_bs); } /*