X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=iolog.c;h=96afec665c73a81c7c37286b77e2b3143e38be53;hp=9bcf0d8e2982e37ce5d48fbd64e9653872e54ea0;hb=518dac097ec305d76fab3f0f45ce785a3849d8b5;hpb=b7f487cf80a8299a656df9c2214ff73e72956d71 diff --git a/iolog.c b/iolog.c index 9bcf0d8e..96afec66 100644 --- a/iolog.c +++ b/iolog.c @@ -10,6 +10,7 @@ #include "fio.h" #include "verify.h" #include "trim.h" +#include "filelock.h" static const char iolog_ver2[] = "fio version 2 iolog"; @@ -57,6 +58,7 @@ void log_file(struct thread_data *td, struct fio_file *f, static void iolog_delay(struct thread_data *td, unsigned long delay) { unsigned long usec = utime_since_now(&td->last_issue); + unsigned long this_delay; if (delay < usec) return; @@ -69,7 +71,14 @@ static void iolog_delay(struct thread_data *td, unsigned long delay) if (delay < 100) return; - usec_sleep(td, delay); + while (delay && !td->terminate) { + this_delay = delay; + if (this_delay > 500000) + this_delay = 500000; + + usec_sleep(td, this_delay); + delay -= this_delay; + } } static int ipo_special(struct thread_data *td, struct io_piece *ipo) @@ -188,6 +197,10 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u) ipo->file = io_u->file; ipo->offset = io_u->offset; ipo->len = io_u->buflen; + ipo->numberio = io_u->numberio; + ipo->flags = IP_F_IN_FLIGHT; + + io_u->ipo = ipo; if (io_u_should_trim(td, io_u)) { flist_add_tail(&ipo->trim_list, &td->trim_list); @@ -208,7 +221,7 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u) * drop the old one, which we rely on the rb insert/lookup for * handling. */ - if ((!td_random(td) || !td->o.overwrite) && + if (((!td->o.verifysort) || !td_random(td) || !td->o.overwrite) && (file_randommap(td, ipo->file) || td->o.verify == VERIFY_NONE)) { INIT_FLIST_HEAD(&ipo->list); flist_add_tail(&ipo->list, &td->io_hist_list); @@ -255,6 +268,33 @@ restart: td->io_hist_len++; } +void unlog_io_piece(struct thread_data *td, struct io_u *io_u) +{ + struct io_piece *ipo = io_u->ipo; + + if (!ipo) + return; + + if (ipo->flags & IP_F_ONRB) + rb_erase(&ipo->rb_node, &td->io_hist_tree); + else if (ipo->flags & IP_F_ONLIST) + flist_del(&ipo->list); + + free(ipo); + io_u->ipo = NULL; + td->io_hist_len--; +} + +void trim_io_piece(struct thread_data *td, struct io_u *io_u) +{ + struct io_piece *ipo = io_u->ipo; + + if (!ipo) + return; + + ipo->len = io_u->xfer_buflen - io_u->resid; +} + void write_iolog_close(struct thread_data *td) { fflush(td->iolog_f); @@ -319,8 +359,7 @@ static int read_iolog2(struct thread_data *td, FILE *f) } else if (r == 2) { rw = DDIR_INVAL; if (!strcmp(act, "add")) { - td->o.nr_files++; - fileno = add_file(td, fname); + fileno = add_file(td, fname, 0, 1); file_action = FIO_LOG_ADD_FILE; continue; } else if (!strcmp(act, "open")) { @@ -367,10 +406,11 @@ static int read_iolog2(struct thread_data *td, FILE *f) } else { ipo->offset = offset; ipo->len = bytes; - if (bytes > td->o.max_bs[rw]) + if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw]) td->o.max_bs[rw] = bytes; ipo->fileno = fileno; ipo->file_action = file_action; + td->o.size += bytes; } queue_io_piece(td, ipo); @@ -480,21 +520,27 @@ int init_iolog(struct thread_data *td) int ret = 0; if (td->o.read_iolog_file) { + int need_swap; + /* * Check if it's a blktrace file and load that if possible. * Otherwise assume it's a normal log file and load that. */ - if (is_blktrace(td->o.read_iolog_file)) - ret = load_blktrace(td, td->o.read_iolog_file); + if (is_blktrace(td->o.read_iolog_file, &need_swap)) + ret = load_blktrace(td, td->o.read_iolog_file, need_swap); else ret = init_iolog_read(td); } else if (td->o.write_iolog_file) ret = init_iolog_write(td); + if (ret) + td_verror(td, EINVAL, "failed initializing iolog"); + return ret; } -void setup_log(struct io_log **log, unsigned long avg_msec, int log_type) +void setup_log(struct io_log **log, unsigned long avg_msec, int log_type, + int log_offset, const char *filename) { struct io_log *l = malloc(sizeof(*l)); @@ -502,51 +548,218 @@ void setup_log(struct io_log **log, unsigned long avg_msec, int log_type) l->nr_samples = 0; l->max_samples = 1024; l->log_type = log_type; - l->log = malloc(l->max_samples * sizeof(struct io_sample)); + l->log_offset = log_offset; + l->log = malloc(l->max_samples * log_entry_sz(l)); l->avg_msec = avg_msec; + l->filename = strdup(filename); *log = l; } -void __finish_log(struct io_log *log, const char *name) +#ifdef CONFIG_SETVBUF +static void *set_file_buffer(FILE *f) { - unsigned int i; + size_t size = 1048576; + void *buf; + + buf = malloc(size); + setvbuf(f, buf, _IOFBF, size); + return buf; +} + +static void clear_file_buffer(void *buf) +{ + free(buf); +} +#else +static void *set_file_buffer(FILE *f) +{ + return NULL; +} + +static void clear_file_buffer(void *buf) +{ +} +#endif + +void free_log(struct io_log *log) +{ + free(log->log); + free(log->filename); + free(log); +} + +void __finish_log(struct io_log *log) +{ + uint64_t i; + void *buf; FILE *f; - f = fopen(name, "a"); + f = fopen(log->filename, "a"); if (!f) { perror("fopen log"); return; } + buf = set_file_buffer(f); + for (i = 0; i < log->nr_samples; i++) { - fprintf(f, "%lu, %lu, %u, %u\n", - (unsigned long) log->log[i].time, - (unsigned long) log->log[i].val, - log->log[i].ddir, log->log[i].bs); + struct io_sample *s = get_sample(log, i); + + if (!log->log_offset) { + fprintf(f, "%lu, %lu, %u, %u\n", + (unsigned long) s->time, + (unsigned long) s->val, + s->ddir, s->bs); + } else { + struct io_sample_offset *so = (void *) s; + + fprintf(f, "%lu, %lu, %u, %u, %llu\n", + (unsigned long) s->time, + (unsigned long) s->val, + s->ddir, s->bs, + (unsigned long long) so->offset); + } } fclose(f); - free(log->log); - free(log); + clear_file_buffer(buf); } -void finish_log_named(struct thread_data *td, struct io_log *log, - const char *prefix, const char *postfix) +static int finish_log(struct thread_data *td, struct io_log *log, int trylock) { - char file_name[256], *p; - - snprintf(file_name, sizeof(file_name), "%s_%s.log", prefix, postfix); - p = basename(file_name); + if (trylock) { + if (fio_trylock_file(log->filename)) + return 1; + } else + fio_lock_file(log->filename); if (td->client_type == FIO_CLIENT_TYPE_GUI) { - fio_send_iolog(td, log, p); - free(log->log); - free(log); + fio_send_iolog(td, log, log->filename); } else - __finish_log(log, p); + __finish_log(log); + + fio_unlock_file(log->filename); + free_log(log); + return 0; +} + +static int write_iops_log(struct thread_data *td, int try) +{ + struct io_log *log = td->iops_log; + + if (!log) + return 0; + + return finish_log(td, log, try); +} + +static int write_slat_log(struct thread_data *td, int try) +{ + struct io_log *log = td->slat_log; + + if (!log) + return 0; + + return finish_log(td, log, try); +} + +static int write_clat_log(struct thread_data *td, int try) +{ + struct io_log *log = td->clat_log; + + if (!log) + return 0; + + return finish_log(td, log, try); } -void finish_log(struct thread_data *td, struct io_log *log, const char *name) +static int write_lat_log(struct thread_data *td, int try) { - finish_log_named(td, log, td->o.name, name); + struct io_log *log = td->lat_log; + + if (!log) + return 0; + + return finish_log(td, log, try); +} + +static int write_bandw_log(struct thread_data *td, int try) +{ + struct io_log *log = td->bw_log; + + if (!log) + return 0; + + return finish_log(td, log, try); +} + +enum { + BW_LOG_MASK = 1, + LAT_LOG_MASK = 2, + SLAT_LOG_MASK = 4, + CLAT_LOG_MASK = 8, + IOPS_LOG_MASK = 16, + + ALL_LOG_NR = 5, +}; + +struct log_type { + unsigned int mask; + int (*fn)(struct thread_data *, int); +}; + +static struct log_type log_types[] = { + { + .mask = BW_LOG_MASK, + .fn = write_bandw_log, + }, + { + .mask = LAT_LOG_MASK, + .fn = write_lat_log, + }, + { + .mask = SLAT_LOG_MASK, + .fn = write_slat_log, + }, + { + .mask = CLAT_LOG_MASK, + .fn = write_clat_log, + }, + { + .mask = IOPS_LOG_MASK, + .fn = write_iops_log, + }, +}; + +void fio_writeout_logs(struct thread_data *td) +{ + unsigned int log_mask = 0; + unsigned int log_left = ALL_LOG_NR; + int old_state, i; + + old_state = td_bump_runstate(td, TD_FINISHING); + + finalize_logs(td); + + while (log_left) { + int prev_log_left = log_left; + + for (i = 0; i < ALL_LOG_NR && log_left; i++) { + struct log_type *lt = &log_types[i]; + int ret; + + if (!(log_mask & lt->mask)) { + ret = lt->fn(td, log_left != 1); + if (!ret) { + log_left--; + log_mask |= lt->mask; + } + } + } + + if (prev_log_left == log_left) + usleep(5000); + } + + td_restore_runstate(td, old_state); }