X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=io_u.c;h=23037f1a8c227114bbcf90b8c0372d8ca5ce108d;hb=refs%2Ftags%2Ffio-1.39-rc1;hp=41b5cdbb04894192cb06e2d86a49bdf28d48be9d;hpb=5f9099ea8adf423d0db01274ef0d7e65629c0e1c;p=fio.git diff --git a/io_u.c b/io_u.c index 41b5cdbb..23037f1a 100644 --- a/io_u.c +++ b/io_u.c @@ -8,6 +8,7 @@ #include "fio.h" #include "hash.h" #include "verify.h" +#include "lib/rand.h" struct io_completion_data { int nr; /* input */ @@ -187,7 +188,7 @@ static int get_next_rand_offset(struct thread_data *td, struct fio_file *f, * until we find a free one. For sequential io, just return the end of * the last io issued. */ -static int get_next_offset(struct thread_data *td, struct io_u *io_u) +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; @@ -231,12 +232,17 @@ static int get_next_offset(struct thread_data *td, struct io_u *io_u) return 0; } -static inline int is_power_of_2(unsigned int val) +static int get_next_offset(struct thread_data *td, struct io_u *io_u) { - return (val != 0 && ((val & (val - 1)) == 0)); + struct prof_io_ops *ops = &td->prof_io_ops; + + if (ops->fill_io_u_off) + return ops->fill_io_u_off(td, io_u); + + return __get_next_offset(td, io_u); } -static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) +static unsigned int __get_next_buflen(struct thread_data *td, struct io_u *io_u) { const int ddir = io_u->ddir; unsigned int uninitialized_var(buflen); @@ -281,6 +287,16 @@ static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) return buflen; } +static unsigned int get_next_buflen(struct thread_data *td, struct io_u *io_u) +{ + struct prof_io_ops *ops = &td->prof_io_ops; + + if (ops->fill_io_u_size) + return ops->fill_io_u_size(td, io_u); + + return __get_next_buflen(td, io_u); +} + static void set_rwmix_bytes(struct thread_data *td) { unsigned int diff; @@ -350,7 +366,7 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) odir = ddir ^ 1; if (td_rw(td) && __should_check_rate(td, odir)) td->rate_pending_usleep[odir] -= usec; - + return ddir; } @@ -379,6 +395,14 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td) td->io_issues[DDIR_WRITE] && should_fsync(td)) return DDIR_DATASYNC; + /* + * see if it's time to sync_file_range + */ + if (td->sync_file_range_nr && + !(td->io_issues[DDIR_WRITE] % td->sync_file_range_nr) && + td->io_issues[DDIR_WRITE] && should_fsync(td)) + return DDIR_SYNC_FILE_RANGE; + if (td_rw(td)) { /* * Check if it's time to seed a new data direction. @@ -406,7 +430,7 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td) return td->rwmix_ddir; } -static void put_file_log(struct thread_data *td, struct fio_file *f) +void put_file_log(struct thread_data *td, struct fio_file *f) { int ret = put_file(td, f); @@ -416,16 +440,21 @@ static void put_file_log(struct thread_data *td, struct fio_file *f) void put_io_u(struct thread_data *td, struct io_u *io_u) { - assert((io_u->flags & IO_U_F_FREE) == 0); + td_io_u_lock(td); + io_u->flags |= IO_U_F_FREE; + io_u->flags &= ~IO_U_F_FREE_DEF; if (io_u->file) put_file_log(td, io_u->file); io_u->file = NULL; - flist_del(&io_u->list); + if (io_u->flags & IO_U_F_IN_CUR_DEPTH) + td->cur_depth--; + flist_del_init(&io_u->list); flist_add(&io_u->list, &td->io_u_freelist); - td->cur_depth--; + td_io_u_unlock(td); + td_io_u_free_notify(td); } void clear_io_u(struct thread_data *td, struct io_u *io_u) @@ -440,15 +469,18 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u) dprint(FD_IO, "requeue %p\n", __io_u); + td_io_u_lock(td); + __io_u->flags |= IO_U_F_FREE; if ((__io_u->flags & IO_U_F_FLIGHT) && !ddir_sync(__io_u->ddir)) td->io_issues[__io_u->ddir]--; __io_u->flags &= ~IO_U_F_FLIGHT; - + if (__io_u->flags & IO_U_F_IN_CUR_DEPTH) + td->cur_depth--; flist_del(&__io_u->list); flist_add_tail(&__io_u->list, &td->io_u_requeues); - td->cur_depth--; + td_io_u_unlock(td); *io_u = NULL; } @@ -751,7 +783,8 @@ static struct fio_file *get_next_file_rr(struct thread_data *td, int goodf, opened = 1; } - dprint(FD_FILE, "goodf=%x, badf=%x, ff=%x\n", goodf, badf, f->flags); + dprint(FD_FILE, "goodf=%x, badf=%x, ff=%x\n", goodf, badf, + f->flags); if ((!goodf || (f->flags & goodf)) && !(f->flags & badf)) break; @@ -765,7 +798,7 @@ static struct fio_file *get_next_file_rr(struct thread_data *td, int goodf, return f; } -static struct fio_file *get_next_file(struct thread_data *td) +static struct fio_file *__get_next_file(struct thread_data *td) { struct fio_file *f; @@ -800,6 +833,16 @@ out: return f; } +static struct fio_file *get_next_file(struct thread_data *td) +{ + struct prof_io_ops *ops = &td->prof_io_ops; + + if (ops->get_next_file) + return ops->get_next_file(td); + + return __get_next_file(td); +} + static int set_io_u_file(struct thread_data *td, struct io_u *io_u) { struct fio_file *f; @@ -820,7 +863,8 @@ static int set_io_u_file(struct thread_data *td, struct io_u *io_u) io_u->file = NULL; fio_file_set_done(f); td->nr_done_files++; - dprint(FD_FILE, "%s: is done (%d of %d)\n", f->file_name, td->nr_done_files, td->o.nr_files); + dprint(FD_FILE, "%s: is done (%d of %d)\n", f->file_name, + td->nr_done_files, td->o.nr_files); } while (1); return 0; @@ -831,6 +875,9 @@ struct io_u *__get_io_u(struct thread_data *td) { struct io_u *io_u = NULL; + td_io_u_lock(td); + +again: if (!flist_empty(&td->io_u_requeues)) io_u = flist_entry(td->io_u_requeues.next, struct io_u, list); else if (!queue_full(td)) { @@ -844,14 +891,23 @@ struct io_u *__get_io_u(struct thread_data *td) if (io_u) { assert(io_u->flags & IO_U_F_FREE); - io_u->flags &= ~IO_U_F_FREE; + io_u->flags &= ~(IO_U_F_FREE | IO_U_F_FREE_DEF); io_u->error = 0; flist_del(&io_u->list); flist_add(&io_u->list, &td->io_u_busylist); td->cur_depth++; + io_u->flags |= IO_U_F_IN_CUR_DEPTH; + } else if (td->o.verify_async) { + /* + * We ran out, wait for async verify threads to finish and + * return one + */ + pthread_cond_wait(&td->free_cond, &td->io_u_lock); + goto again; } + td_io_u_unlock(td); return io_u; } @@ -948,14 +1004,22 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, * initialized, silence that warning. */ unsigned long uninitialized_var(usec); + struct fio_file *f; dprint_io_u(io_u, "io complete"); + td_io_u_lock(td); assert(io_u->flags & IO_U_F_FLIGHT); io_u->flags &= ~IO_U_F_FLIGHT; + td_io_u_unlock(td); if (ddir_sync(io_u->ddir)) { td->last_was_sync = 1; + f = io_u->file; + if (f) { + f->first_write = -1ULL; + f->last_write = -1ULL; + } return; } @@ -964,36 +1028,49 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, if (!io_u->error) { unsigned int bytes = io_u->buflen - io_u->resid; const enum fio_ddir idx = io_u->ddir; + const enum fio_ddir odx = io_u->ddir ^ 1; int ret; td->io_blocks[idx]++; td->io_bytes[idx] += bytes; td->this_io_bytes[idx] += bytes; + if (idx == DDIR_WRITE) { + f = io_u->file; + 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 (ramp_time_over(td)) { unsigned long uninitialized_var(lusec); - unsigned long uninitialized_var(rusec); if (!td->o.disable_clat || !td->o.disable_bw) lusec = utime_since(&io_u->issue_time, &icd->time); - if (__should_check_rate(td, idx) || - __should_check_rate(td, idx ^ 1)) - rusec = utime_since(&io_u->start_time, - &icd->time); if (!td->o.disable_clat) { - add_clat_sample(td, idx, usec, bytes); + add_clat_sample(td, idx, lusec, bytes); io_u_mark_latency(td, lusec); } if (!td->o.disable_bw) add_bw_sample(td, idx, bytes, &icd->time); if (__should_check_rate(td, idx)) { - td->rate_pending_usleep[idx] += - (long) td->rate_usec_cycle[idx] - rusec; + td->rate_pending_usleep[idx] = + ((td->this_io_bytes[idx] * + td->rate_nsec_cycle[idx]) / 1000 - + utime_since_now(&td->start)); } if (__should_check_rate(td, idx ^ 1)) - td->rate_pending_usleep[idx ^ 1] -= rusec; + td->rate_pending_usleep[odx] = + ((td->this_io_bytes[odx] * + td->rate_nsec_cycle[odx]) / 1000 - + utime_since_now(&td->start)); } if (td_write(td) && idx == DDIR_WRITE && @@ -1047,7 +1124,9 @@ static void ios_completed(struct thread_data *td, io_u = td->io_ops->event(td, i); io_completed(td, io_u, icd); - put_io_u(td, io_u); + + if (!(io_u->flags & IO_U_F_FREE_DEF)) + put_io_u(td, io_u); } } @@ -1061,7 +1140,9 @@ int io_u_sync_complete(struct thread_data *td, struct io_u *io_u, init_icd(td, &icd, 1); io_completed(td, io_u, &icd); - put_io_u(td, io_u); + + if (!(io_u->flags & IO_U_F_FREE_DEF)) + put_io_u(td, io_u); if (icd.error) { td_verror(td, icd.error, "io_u_sync_complete"); @@ -1136,9 +1217,16 @@ void io_u_fill_buffer(struct thread_data *td, struct io_u *io_u, long *ptr = io_u->buf; if (!td->o.zero_buffers) { + unsigned long r = __rand(&__fio_rand_state); + + if (sizeof(int) != sizeof(*ptr)) + r *= (unsigned long) __rand(&__fio_rand_state); + while ((void *) ptr - io_u->buf < max_bs) { - *ptr = rand() * GOLDEN_RATIO_PRIME; + *ptr = r; ptr++; + r *= GOLDEN_RATIO_PRIME; + r >>= 3; } } else memset(ptr, 0, max_bs);