#include "trim.h"
#include "filelock.h"
#include "smalloc.h"
+#include "blktrace.h"
static int iolog_flush(struct io_log *log);
{
uint64_t usec = utime_since_now(&td->last_issue);
uint64_t this_delay;
- struct timeval tv;
+ struct timespec ts;
if (delay < td->time_offset) {
td->time_offset = 0;
delay -= usec;
- fio_gettime(&tv, NULL);
+ fio_gettime(&ts, NULL);
while (delay && !td->terminate) {
this_delay = delay;
if (this_delay > 500000)
delay -= this_delay;
}
- usec = utime_since_now(&tv);
+ usec = utime_since_now(&ts);
if (usec > delay)
td->time_offset = usec - delay;
else
switch (ipo->file_action) {
case FIO_LOG_OPEN_FILE:
+ if (td->o.replay_redirect && fio_file_open(f)) {
+ dprint(FD_FILE, "iolog: ignoring re-open of file %s\n",
+ f->file_name);
+ break;
+ }
ret = td_io_open_file(td, f);
if (!ret)
break;
overlap = 1;
if (overlap) {
- dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu",
+ dprint(FD_IO, "iolog: overlap %llu/%lu, %llu/%lu\n",
__ipo->offset, __ipo->len,
ipo->offset, ipo->len);
td->io_hist_len--;
unsigned long long offset;
unsigned int bytes;
int reads, writes, waits, fileno = 0, file_action = 0; /* stupid gcc */
- char *fname, *act;
+ char *rfname, *fname, *act;
char *str, *p;
enum fio_ddir rw;
* for doing verifications.
*/
str = malloc(4096);
- fname = malloc(256+16);
+ rfname = fname = malloc(256+16);
act = malloc(256+16);
reads = writes = waits = 0;
struct io_piece *ipo;
int r;
- r = sscanf(p, "%256s %256s %llu %u", fname, act, &offset,
+ r = sscanf(p, "%256s %256s %llu %u", rfname, act, &offset,
&bytes);
+
+ if (td->o.replay_redirect)
+ fname = td->o.replay_redirect;
+
if (r == 4) {
/*
* Check action first
} else if (r == 2) {
rw = DDIR_INVAL;
if (!strcmp(act, "add")) {
- fileno = add_file(td, fname, 0, 1);
- file_action = FIO_LOG_ADD_FILE;
+ if (td->o.replay_redirect &&
+ get_fileno(td, fname) != -1) {
+ dprint(FD_FILE, "iolog: ignoring"
+ " re-add of file %s\n", fname);
+ } else {
+ fileno = add_file(td, fname, 0, 1);
+ file_action = FIO_LOG_ADD_FILE;
+ }
continue;
} else if (!strcmp(act, "open")) {
fileno = get_fileno(td, fname);
continue;
}
} else {
- log_err("bad iolog2: %s", p);
+ log_err("bad iolog2: %s\n", p);
continue;
}
continue;
writes++;
} else if (rw == DDIR_WAIT) {
+ if (td->o.no_stall)
+ continue;
waits++;
} else if (rw == DDIR_INVAL) {
} else if (!ddir_sync(rw)) {
if (rw == DDIR_WAIT) {
ipo->delay = offset;
} else {
- ipo->offset = offset;
+ if (td->o.replay_scale)
+ ipo->offset = offset / td->o.replay_scale;
+ else
+ ipo->offset = offset;
+ ipo_bytes_align(td->o.replay_align, ipo);
+
ipo->len = bytes;
if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
td->o.max_bs[rw] = bytes;
free(str);
free(act);
- free(fname);
+ free(rfname);
if (writes && read_only) {
log_err("fio: <%s> skips replay of %d writes due to"
l->log_gz = 0;
else if (l->log_gz || l->log_gz_store) {
mutex_init_pshared(&l->chunk_lock);
+ mutex_init_pshared(&l->deferred_free_lock);
p->td->flags |= TD_F_COMPRESS_LOG;
}
sfree(log);
}
-inline unsigned long hist_sum(int j, int stride, unsigned int *io_u_plat,
+unsigned long hist_sum(int j, int stride, unsigned int *io_u_plat,
unsigned int *io_u_plat_last)
{
unsigned long sum;
for (i = 0; i < nr_samples; i++) {
s = __get_sample(samples, log_offset, i);
- entry = (struct io_u_plat_entry *) s->val;
+ entry = s->data.plat_entry;
io_u_plat = entry->io_u_plat;
entry_before = flist_first_entry(&entry->list, struct io_u_plat_entry, list);
s = __get_sample(samples, log_offset, i);
if (!log_offset) {
- fprintf(f, "%lu, %lu, %u, %u\n",
+ fprintf(f, "%lu, %" PRId64 ", %u, %u\n",
(unsigned long) s->time,
- (unsigned long) s->val,
+ s->data.val,
io_sample_ddir(s), s->bs);
} else {
struct io_sample_offset *so = (void *) s;
- fprintf(f, "%lu, %lu, %u, %u, %llu\n",
+ fprintf(f, "%lu, %" PRId64 ", %u, %u, %llu\n",
(unsigned long) s->time,
- (unsigned long) s->val,
+ s->data.val,
io_sample_ddir(s), s->bs,
(unsigned long long) so->offset);
}
cur_log = flist_first_entry(&log->io_logs, struct io_logs, list);
flist_del_init(&cur_log->list);
- if (log == log->td->clat_hist_log)
+ if (log->td && log == log->td->clat_hist_log)
flush_hist_samples(f, log->hist_coarseness, cur_log->log,
log_sample_sz(log, cur_log));
else
#ifdef CONFIG_ZLIB
+static bool warned_on_drop;
+
+static void iolog_put_deferred(struct io_log *log, void *ptr)
+{
+ if (!ptr)
+ return;
+
+ pthread_mutex_lock(&log->deferred_free_lock);
+ if (log->deferred < IOLOG_MAX_DEFER) {
+ log->deferred_items[log->deferred] = ptr;
+ log->deferred++;
+ } else if (!warned_on_drop) {
+ log_err("fio: had to drop log entry free\n");
+ warned_on_drop = true;
+ }
+ pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
+static void iolog_free_deferred(struct io_log *log)
+{
+ int i;
+
+ if (!log->deferred)
+ return;
+
+ pthread_mutex_lock(&log->deferred_free_lock);
+
+ for (i = 0; i < log->deferred; i++) {
+ free(log->deferred_items[i]);
+ log->deferred_items[i] = NULL;
+ }
+
+ log->deferred = 0;
+ pthread_mutex_unlock(&log->deferred_free_lock);
+}
+
static int gz_work(struct iolog_flush_data *data)
{
struct iolog_compress *c = NULL;
data->log->filename);
do {
if (c)
- dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+ dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq,
+ (unsigned long) c->len);
c = get_new_chunk(seq);
stream.avail_out = GZ_CHUNK;
stream.next_out = c->buf;
total -= c->len;
c->len = GZ_CHUNK - stream.avail_out;
total += c->len;
- dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+ dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, (unsigned long) c->len);
if (ret != Z_STREAM_END) {
do {
c->len = GZ_CHUNK - stream.avail_out;
total += c->len;
flist_add_tail(&c->list, &list);
- dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq, c->len);
+ dprint(FD_COMPRESS, "seq=%d, chunk=%lu\n", seq,
+ (unsigned long) c->len);
} while (ret != Z_STREAM_END);
}
if (ret != Z_OK)
log_err("fio: deflateEnd %d\n", ret);
- free(data->samples);
+ iolog_put_deferred(data->log, data->samples);
if (!flist_empty(&list)) {
pthread_mutex_lock(&data->log->chunk_lock);
ret = 0;
done:
if (data->free)
- free(data);
+ sfree(data);
return ret;
err:
while (!flist_empty(&list)) {
{
struct iolog_flush_data *data;
- data = malloc(sizeof(*data));
+ data = smalloc(sizeof(*data));
if (!data)
return 1;
cur_log->log = NULL;
workqueue_enqueue(&log->td->log_compress_wq, &data->work);
+
+ iolog_free_deferred(log);
+
return 0;
}
#else