X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=iolog.c;h=f6023ee2ce6241398138d39134eaafe26e140998;hb=315bbf01119ea783554d274add04db98c0a3b433;hp=4af10da3cddebb112d042d8c9040e435ec9545b0;hpb=b5aba537d844f73187eb931179ac59e7da570e7c;p=fio.git diff --git a/iolog.c b/iolog.c index 4af10da3..f6023ee2 100644 --- a/iolog.c +++ b/iolog.c @@ -31,6 +31,7 @@ static int iolog_flush(struct io_log *log); static const char iolog_ver2[] = "fio version 2 iolog"; +static const char iolog_ver3[] = "fio version 3 iolog"; void queue_io_piece(struct thread_data *td, struct io_piece *ipo) { @@ -116,6 +117,10 @@ static int ipo_special(struct thread_data *td, struct io_piece *ipo) f = td->files[ipo->fileno]; + if (ipo->delay) + iolog_delay(td, ipo->delay); + if (fio_fill_issue_time(td)) + fio_gettime(&td->last_issue, NULL); switch (ipo->file_action) { case FIO_LOG_OPEN_FILE: if (td->o.replay_redirect && fio_file_open(f)) { @@ -134,6 +139,11 @@ static int ipo_special(struct thread_data *td, struct io_piece *ipo) case FIO_LOG_UNLINK_FILE: td_io_unlink_file(td, f); break; + case FIO_LOG_ADD_FILE: + /* + * Nothing to do + */ + break; default: log_err("fio: bad file action %d\n", ipo->file_action); break; @@ -142,7 +152,25 @@ static int ipo_special(struct thread_data *td, struct io_piece *ipo) return 1; } -static bool read_iolog2(struct thread_data *td); +static bool read_iolog(struct thread_data *td); + +unsigned long long delay_since_ttime(const struct thread_data *td, + unsigned long long time) +{ + double tmp; + double scale; + const unsigned long long *last_ttime = &td->io_log_last_ttime; + + if (!*last_ttime || td->o.no_stall || time < *last_ttime) + return 0; + else if (td->o.replay_time_scale == 100) + return time - *last_ttime; + + + scale = (double) 100.0 / (double) td->o.replay_time_scale; + tmp = time - *last_ttime; + return tmp * scale; +} int read_iolog_get(struct thread_data *td, struct io_u *io_u) { @@ -151,10 +179,16 @@ int read_iolog_get(struct thread_data *td, struct io_u *io_u) while (!flist_empty(&td->io_log_list)) { int ret; + if (td->o.read_iolog_chunked) { if (td->io_log_checkmark == td->io_log_current) { - if (!read_iolog2(td)) - return 1; + if (td->io_log_blktrace) { + if (!read_blktrace(td)) + return 1; + } else { + if (!read_iolog(td)) + return 1; + } } td->io_log_current--; } @@ -174,6 +208,7 @@ int read_iolog_get(struct thread_data *td, struct io_u *io_u) io_u->ddir = ipo->ddir; if (ipo->ddir != DDIR_WAIT) { io_u->offset = ipo->offset; + io_u->verify_offset = ipo->offset; io_u->buflen = ipo->len; io_u->file = td->files[ipo->fileno]; get_file(io_u->file); @@ -353,7 +388,7 @@ void write_iolog_close(struct thread_data *td) td->iolog_buf = NULL; } -static int64_t iolog_items_to_fetch(struct thread_data *td) +int64_t iolog_items_to_fetch(struct thread_data *td) { struct timespec now; uint64_t elapsed; @@ -381,20 +416,27 @@ static int64_t iolog_items_to_fetch(struct thread_data *td) return items_to_fetch; } +#define io_act(_td, _r) (((_td)->io_log_version == 3 && (r) == 5) || \ + ((_td)->io_log_version == 2 && (r) == 4)) +#define file_act(_td, _r) (((_td)->io_log_version == 3 && (r) == 3) || \ + ((_td)->io_log_version == 2 && (r) == 2)) + /* - * Read version 2 iolog data. It is enhanced to include per-file logging, + * Read version 2 and 3 iolog data. It is enhanced to include per-file logging, * syncs, etc. */ -static bool read_iolog2(struct thread_data *td) +static bool read_iolog(struct thread_data *td) { unsigned long long offset; unsigned int bytes; + unsigned long long delay = 0; int reads, writes, waits, fileno = 0, file_action = 0; /* stupid gcc */ char *rfname, *fname, *act; char *str, *p; enum fio_ddir rw; bool realloc = false; int64_t items_to_fetch = 0; + int syncs; if (td->o.read_iolog_chunked) { items_to_fetch = iolog_items_to_fetch(td); @@ -410,18 +452,32 @@ static bool read_iolog2(struct thread_data *td) rfname = fname = malloc(256+16); act = malloc(256+16); - reads = writes = waits = 0; + syncs = reads = writes = waits = 0; while ((p = fgets(str, 4096, td->io_log_rfile)) != NULL) { struct io_piece *ipo; int r; + unsigned long long ttime; - r = sscanf(p, "%256s %256s %llu %u", rfname, act, &offset, - &bytes); + if (td->io_log_version == 3) { + r = sscanf(p, "%llu %256s %256s %llu %u", &ttime, rfname, act, + &offset, &bytes); + delay = delay_since_ttime(td, ttime); + td->io_log_last_ttime = ttime; + /* + * "wait" is not allowed with version 3 + */ + if (!strcmp(act, "wait")) { + log_err("iolog: ignoring wait command with" + " version 3 for file %s\n", fname); + continue; + } + } else /* version 2 */ + r = sscanf(p, "%256s %256s %llu %u", rfname, act, &offset, &bytes); if (td->o.replay_redirect) fname = td->o.replay_redirect; - if (r == 4) { + if (io_act(td, r)) { /* * Check action first */ @@ -443,7 +499,7 @@ static bool read_iolog2(struct thread_data *td) continue; } fileno = get_fileno(td, fname); - } else if (r == 2) { + } else if (file_act(td, r)) { rw = DDIR_INVAL; if (!strcmp(act, "add")) { if (td->o.replay_redirect && @@ -454,7 +510,6 @@ static bool read_iolog2(struct thread_data *td) fileno = add_file(td, fname, td->subjob_number, 1); file_action = FIO_LOG_ADD_FILE; } - continue; } else if (!strcmp(act, "open")) { fileno = get_fileno(td, fname); file_action = FIO_LOG_OPEN_FILE; @@ -467,7 +522,7 @@ static bool read_iolog2(struct thread_data *td) continue; } } else { - log_err("bad iolog2: %s\n", p); + log_err("bad iolog%d: %s\n", td->io_log_version, p); continue; } @@ -485,7 +540,9 @@ static bool read_iolog2(struct thread_data *td) continue; waits++; } else if (rw == DDIR_INVAL) { - } else if (!ddir_sync(rw)) { + } else if (ddir_sync(rw)) { + syncs++; + } else { log_err("bad ddir: %d\n", rw); continue; } @@ -496,6 +553,8 @@ static bool read_iolog2(struct thread_data *td) ipo = calloc(1, sizeof(*ipo)); init_ipo(ipo); ipo->ddir = rw; + if (td->io_log_version == 3) + ipo->delay = delay; if (rw == DDIR_WAIT) { ipo->delay = offset; } else { @@ -540,6 +599,8 @@ static bool read_iolog2(struct thread_data *td) " read-only\n", td->o.name, writes); writes = 0; } + if (syncs) + td->flags |= TD_F_SYNCS; if (td->o.read_iolog_chunked) { if (td->io_log_current == 0) { @@ -606,12 +667,11 @@ static int open_socket(const char *path) /* * open iolog, check version, and call appropriate parser */ -static bool init_iolog_read(struct thread_data *td) +static bool init_iolog_read(struct thread_data *td, char *fname) { - char buffer[256], *p, *fname; + char buffer[256], *p; FILE *f = NULL; - fname = get_name_by_idx(td->o.read_iolog_file, td->subjob_number); dprint(FD_IO, "iolog: name=%s\n", fname); if (is_socket(fname)) { @@ -620,11 +680,11 @@ static bool init_iolog_read(struct thread_data *td) fd = open_socket(fname); if (fd >= 0) f = fdopen(fd, "r"); + } else if (!strcmp(fname, "-")) { + f = stdin; } else f = fopen(fname, "r"); - free(fname); - if (!f) { perror("fopen read iolog"); return false; @@ -639,18 +699,22 @@ static bool init_iolog_read(struct thread_data *td) } /* - * version 2 of the iolog stores a specific string as the + * versions 2 and 3 of the iolog store a specific string as the * first line, check for that */ - if (!strncmp(iolog_ver2, buffer, strlen(iolog_ver2))) { - free_release_files(td); - td->io_log_rfile = f; - return read_iolog2(td); + if (!strncmp(iolog_ver2, buffer, strlen(iolog_ver2))) + td->io_log_version = 2; + else if (!strncmp(iolog_ver3, buffer, strlen(iolog_ver3))) + td->io_log_version = 3; + else { + log_err("fio: iolog version 1 is no longer supported\n"); + fclose(f); + return false; } - log_err("fio: iolog version 1 is no longer supported\n"); - fclose(f); - return false; + free_release_files(td); + td->io_log_rfile = f; + return read_iolog(td); } /* @@ -698,15 +762,20 @@ bool init_iolog(struct thread_data *td) if (td->o.read_iolog_file) { int need_swap; + char * fname = get_name_by_idx(td->o.read_iolog_file, td->subjob_number); /* * 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, &need_swap)) - ret = load_blktrace(td, td->o.read_iolog_file, need_swap); - else - ret = init_iolog_read(td); + if (is_blktrace(fname, &need_swap)) { + td->io_log_blktrace = 1; + ret = init_blktrace_read(td, fname, need_swap); + } else { + td->io_log_blktrace = 0; + ret = init_iolog_read(td, fname); + } + free(fname); } else if (td->o.write_iolog_file) ret = init_iolog_write(td); else @@ -730,6 +799,7 @@ void setup_log(struct io_log **log, struct log_params *p, INIT_FLIST_HEAD(&l->io_logs); l->log_type = p->log_type; l->log_offset = p->log_offset; + l->log_prio = p->log_prio; l->log_gz = p->log_gz; l->log_gz_store = p->log_gz_store; l->avg_msec = p->avg_msec; @@ -762,6 +832,8 @@ void setup_log(struct io_log **log, struct log_params *p, if (l->log_offset) l->log_ddir_mask = LOG_OFFSET_SAMPLE_BIT; + if (l->log_prio) + l->log_ddir_mask |= LOG_PRIO_SAMPLE_BIT; INIT_FLIST_HEAD(&l->chunk_list); @@ -888,33 +960,55 @@ static void flush_hist_samples(FILE *f, int hist_coarseness, void *samples, void flush_samples(FILE *f, void *samples, uint64_t sample_size) { struct io_sample *s; - int log_offset; + int log_offset, log_prio; uint64_t i, nr_samples; + unsigned int prio_val; + const char *fmt; if (!sample_size) return; s = __get_sample(samples, 0, 0); log_offset = (s->__ddir & LOG_OFFSET_SAMPLE_BIT) != 0; + log_prio = (s->__ddir & LOG_PRIO_SAMPLE_BIT) != 0; + + if (log_offset) { + if (log_prio) + fmt = "%lu, %" PRId64 ", %u, %llu, %llu, 0x%04x\n"; + else + fmt = "%lu, %" PRId64 ", %u, %llu, %llu, %u\n"; + } else { + if (log_prio) + fmt = "%lu, %" PRId64 ", %u, %llu, 0x%04x\n"; + else + fmt = "%lu, %" PRId64 ", %u, %llu, %u\n"; + } nr_samples = sample_size / __log_entry_sz(log_offset); for (i = 0; i < nr_samples; i++) { s = __get_sample(samples, log_offset, i); + if (log_prio) + prio_val = s->priority; + else + prio_val = ioprio_value_is_class_rt(s->priority); + if (!log_offset) { - fprintf(f, "%lu, %" PRId64 ", %u, %llu, %u\n", - (unsigned long) s->time, - s->data.val, - io_sample_ddir(s), (unsigned long long) s->bs, s->priority_bit); + fprintf(f, fmt, + (unsigned long) s->time, + s->data.val, + io_sample_ddir(s), (unsigned long long) s->bs, + prio_val); } else { struct io_sample_offset *so = (void *) s; - fprintf(f, "%lu, %" PRId64 ", %u, %llu, %llu, %u\n", - (unsigned long) s->time, - s->data.val, - io_sample_ddir(s), (unsigned long long) s->bs, - (unsigned long long) so->offset, s->priority_bit); + fprintf(f, fmt, + (unsigned long) s->time, + s->data.val, + io_sample_ddir(s), (unsigned long long) s->bs, + (unsigned long long) so->offset, + prio_val); } } }