#include "smalloc.h"
#include "blktrace.h"
#include "pshared.h"
+#include "lib/roundup.h"
#include <netinet/in.h>
#include <netinet/tcp.h>
while (!flist_empty(&td->io_log_list)) {
int ret;
- if (td->o.read_iolog_chunked) {
+
+ if (!td->io_log_blktrace && td->o.read_iolog_chunked) {
if (td->io_log_checkmark == td->io_log_current) {
if (!read_iolog2(td))
return 1;
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);
void write_iolog_close(struct thread_data *td)
{
+ if (!td->iolog_f)
+ return;
+
fflush(td->iolog_f);
fclose(td->iolog_f);
free(td->iolog_buf);
td->iolog_buf = NULL;
}
+static int64_t iolog_items_to_fetch(struct thread_data *td)
+{
+ struct timespec now;
+ uint64_t elapsed;
+ uint64_t for_1s;
+ int64_t items_to_fetch;
+
+ if (!td->io_log_highmark)
+ return 10;
+
+
+ fio_gettime(&now, NULL);
+ elapsed = ntime_since(&td->io_log_highmark_time, &now);
+ if (elapsed) {
+ for_1s = (td->io_log_highmark - td->io_log_current) * 1000000000 / elapsed;
+ items_to_fetch = for_1s - td->io_log_current;
+ if (items_to_fetch < 0)
+ items_to_fetch = 0;
+ } else
+ items_to_fetch = 0;
+
+ td->io_log_highmark = td->io_log_current + items_to_fetch;
+ td->io_log_checkmark = (td->io_log_highmark + 1) / 2;
+ fio_gettime(&td->io_log_highmark_time, NULL);
+
+ return items_to_fetch;
+}
+
/*
* Read version 2 iolog data. It is enhanced to include per-file logging,
* syncs, etc.
char *rfname, *fname, *act;
char *str, *p;
enum fio_ddir rw;
+ bool realloc = false;
int64_t items_to_fetch = 0;
if (td->o.read_iolog_chunked) {
- if (td->io_log_highmark == 0) {
- items_to_fetch = 10;
- } else {
- struct timespec now;
- uint64_t elapsed;
- uint64_t for_1s;
- fio_gettime(&now, NULL);
- elapsed = ntime_since(&td->io_log_highmark_time, &now);
- for_1s = (td->io_log_highmark - td->io_log_current) * 1000000000 / elapsed;
- items_to_fetch = for_1s - td->io_log_current;
- if (items_to_fetch < 0)
- items_to_fetch = 0;
- td->io_log_highmark = td->io_log_current + items_to_fetch;
- td->io_log_checkmark = (td->io_log_highmark + 1) / 2;
- fio_gettime(&td->io_log_highmark_time, NULL);
- if (items_to_fetch == 0)
- return true;
- }
+ items_to_fetch = iolog_items_to_fetch(td);
+ if (!items_to_fetch)
+ return true;
}
+
/*
* Read in the read iolog and store it, reuse the infrastructure
* for doing verifications.
dprint(FD_FILE, "iolog: ignoring"
" re-add of file %s\n", fname);
} else {
- fileno = add_file(td, fname, 0, 1);
+ fileno = add_file(td, fname, td->subjob_number, 1);
file_action = FIO_LOG_ADD_FILE;
}
continue;
ipo_bytes_align(td->o.replay_align, ipo);
ipo->len = bytes;
- if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
+ if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw]) {
+ realloc = true;
td->o.max_bs[rw] = bytes;
+ }
ipo->fileno = fileno;
ipo->file_action = file_action;
td->o.size += bytes;
return false;
}
td->o.td_ddir = TD_DDIR_RW;
+ if (realloc && td->orig_buffer)
+ {
+ io_u_quiesce(td);
+ free_io_mem(td);
+ init_io_u_buffers(td);
+ }
return true;
}
static bool is_socket(const char *path)
{
struct stat buf;
- int r = stat(path, &buf);
+ int r;
+
+ r = stat(path, &buf);
if (r == -1)
return false;
static int open_socket(const char *path)
{
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
+ int ret, fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0)
return fd;
+
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, path, sizeof(addr.sun_path));
- if (connect(fd, (const struct sockaddr *)&addr, strlen(path) + sizeof(addr.sun_family)) == 0)
+ if (snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path) >=
+ sizeof(addr.sun_path)) {
+ log_err("%s: path name %s is too long for a Unix socket\n",
+ __func__, path);
+ }
+
+ ret = connect(fd, (const struct sockaddr *)&addr, strlen(path) + sizeof(addr.sun_family));
+ if (!ret)
return fd;
- else
- close(fd);
+
+ close(fd);
return -1;
}
/*
* 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;
FILE *f = NULL;
- bool ret;
- if (is_socket(td->o.read_iolog_file)) {
- int fd = open_socket(td->o.read_iolog_file);
- if (fd >= 0) {
+
+ dprint(FD_IO, "iolog: name=%s\n", fname);
+
+ if (is_socket(fname)) {
+ int fd;
+
+ fd = open_socket(fname);
+ if (fd >= 0)
f = fdopen(fd, "r");
- }
+ } else if (!strcmp(fname, "-")) {
+ f = stdin;
} else
- f = fopen(td->o.read_iolog_file, "r");
+ f = fopen(fname, "r");
+
+ free(fname);
+
if (!f) {
perror("fopen read iolog");
return false;
fclose(f);
return false;
}
- td->io_log_rfile = f;
+
/*
* version 2 of the iolog stores a specific string as the
* first line, check for that
*/
if (!strncmp(iolog_ver2, buffer, strlen(iolog_ver2))) {
free_release_files(td);
- ret = read_iolog2(td);
- }
- else {
- log_err("fio: iolog version 1 is no longer supported\n");
- ret = false;
+ td->io_log_rfile = f;
+ return read_iolog2(td);
}
- return ret;
+ log_err("fio: iolog version 1 is no longer supported\n");
+ fclose(f);
+ return false;
}
/*
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 = load_blktrace(td, fname, need_swap);
+ } else {
+ td->io_log_blktrace = 0;
+ ret = init_iolog_read(td, fname);
+ }
} else if (td->o.write_iolog_file)
ret = init_iolog_write(td);
else
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;
}
if (l->td && l->td->o.io_submit_mode != IO_MODE_OFFLOAD) {
+ unsigned int def_samples = DEF_LOG_ENTRIES;
struct io_logs *__p;
__p = calloc(1, sizeof(*l->pending));
- __p->max_samples = DEF_LOG_ENTRIES;
+ if (l->td->o.iodepth > DEF_LOG_ENTRIES)
+ def_samples = roundup_pow2(l->td->o.iodepth);
+ __p->max_samples = def_samples;
__p->log = calloc(__p->max_samples, log_entry_sz(l));
l->pending = __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);
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\n",
- (unsigned long) s->time,
- s->data.val,
- io_sample_ddir(s), (unsigned long long) s->bs);
+ 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\n",
- (unsigned long) s->time,
- s->data.val,
- io_sample_ddir(s), (unsigned long long) s->bs,
- (unsigned long long) so->offset);
+ 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);
}
}
}