struct io_sample *log;
};
+struct io_piece {
+ struct list_head list;
+ unsigned long long offset;
+ unsigned int len;
+};
+
#define FIO_HDR_MAGIC 0xf00baaef
struct verify_header {
struct io_log *bw_log;
struct timeval start;
+
+ struct list_head io_hist_list;
};
static struct thread_data *threads;
long r;
if (!td->sequential) {
+ int min_bs_kb = td->min_bs >> 10;
+
lrand48_r(&td->random_state, &r);
kb = (1+(double) (td->kb-1) * r / (RAND_MAX+1.0));
+ kb = (kb + min_bs_kb - 1) & ~(min_bs_kb - 1);
} else
kb = td->last_kb;
add_stat_sample(td, &td->slat_stat, msec);
}
-static void add_bw_sample(struct thread_data *td, unsigned long msec)
+static void add_bw_sample(struct thread_data *td)
{
unsigned long spent = mtime_since_now(&td->stat_sample_time);
unsigned long rate;
static void fill_random_bytes(struct thread_data *td,
unsigned char *p, unsigned int len)
{
+ unsigned int todo;
double r;
- int todo;
while (len) {
drand48_r(&td->verify_state, &r);
}
}
-static int verify_io_u(struct thread_data *td, struct io_u *io_u)
+static int verify_io_u(struct io_u *io_u)
{
struct verify_header *hdr = (struct verify_header *) io_u->buf;
unsigned char *p = (unsigned char *) io_u->buf;
return memcmp(hdr->md5_digest, md5_ctx.hash, sizeof(md5_ctx.hash));
}
-static int verify_io_us(struct thread_data *td, struct io_u *io_u, int *back)
-{
- struct verify_header *hdr;
- unsigned int left;
- struct io_u i;
- char *buf;
- off_t off;
-
- if (back)
- *back = 0;
-
- left = io_u->buflen;
- buf = io_u->buf;
- off = io_u->offset;
- while (left) {
- hdr = (struct verify_header *) buf;
- i.buf = buf;
- i.buflen = hdr->len;
-
- if (hdr->len > left) {
- if (back)
- *back = left;
- return 0;
- }
-
- if (verify_io_u(td, &i)) {
- printf("failed verify at offset %lu\n", (unsigned long) off);
- td->error = EBADMSG;
- return 1;
- }
-
- buf += hdr->len;
- left -= hdr->len;
- off += hdr->len;
- }
-
- return 0;
-}
-
/*
* fill body of io_u->buf with random data and add a header with the
* (eg) sha1sum of that data.
td->runstate = runstate;
}
+static int get_next_verify(struct thread_data *td,
+ unsigned long long *offset, unsigned int *len)
+{
+ struct io_piece *ipo;
+
+ if (list_empty(&td->io_hist_list))
+ return 1;
+
+ ipo = list_entry(td->io_hist_list.next, struct io_piece, list);
+ list_del(&ipo->list);
+
+ *offset = ipo->offset;
+ *len = ipo->len;
+ free(ipo);
+ return 0;
+}
+
static void do_sync_verify(struct thread_data *td)
{
struct timeval t;
struct io_u *io_u = NULL;
- loff_t off = 0;
- int back, ret;
+ int ret;
td_set_runstate(td, TD_VERIFYING);
io_u = __get_io_u(td);
- if (lseek(td->fd, 0, SEEK_SET) < 0) {
- td->error = errno;
- goto out;
- }
-
if (!td->odirect) {
unsigned long size = td->kb << 10;
if (runtime_exceeded(td, &t))
break;
- io_u->offset = off;
- io_u->buflen = td->max_bs;
+ if (get_next_verify(td, &io_u->offset, &io_u->buflen))
+ break;
+
+ if (td->cur_off != io_u->offset) {
+ if (lseek(td->fd, io_u->offset, SEEK_SET) == -1) {
+ td->error = errno;
+ break;
+ }
+ }
ret = read(td->fd, io_u->buf, io_u->buflen);
if (ret < (int) io_u->buflen) {
io_u->buflen = ret;
}
- if (verify_io_us(td, io_u, &back))
+ if (verify_io_u(io_u))
break;
- if (back) {
- printf("will seek %d %d\n", ret, back);
- ret -= back;
- if (lseek(td->fd, -back, SEEK_CUR) < 0) {
- td->error = errno;
- break;
- }
- }
-
- off += ret;
+ td->cur_off = io_u->offset + io_u->buflen;
} while (1);
out:
put_io_u(td, io_u);
}
+/*
+ * log a succesful write, so we can unwind the log for verify
+ */
+static void log_io_piece(struct thread_data *td, struct io_u *io_u)
+{
+ struct io_piece *ipo = malloc(sizeof(*ipo));
+ struct list_head *entry;
+
+ INIT_LIST_HEAD(&ipo->list);
+ ipo->offset = io_u->offset;
+ ipo->len = io_u->buflen;
+
+ if (td->sequential) {
+ list_add_tail(&ipo->list, &td->io_hist_list);
+ return;
+ }
+
+ /*
+ * for random io, sort the list so verify will run faster
+ */
+ entry = &td->io_hist_list;
+ while ((entry = entry->prev) != &td->io_hist_list) {
+ struct io_piece *__ipo = list_entry(entry, struct io_piece, list);
+
+ if (__ipo->offset == ipo->offset &&
+ __ipo->len == ipo->len) {
+ free(ipo);
+ ipo = NULL;
+ break;
+ } else if (__ipo->offset < ipo->offset)
+ break;
+ }
+
+ if (ipo)
+ list_add(&ipo->list, entry);
+}
+
static void do_sync_io(struct thread_data *td)
{
unsigned long msec, usec;
break;
}
+ if (!td_read(td))
+ log_io_piece(td, io_u);
+
td->io_blocks++;
td->io_kb += io_u->buflen >> 10;
td->this_io_kb += io_u->buflen >> 10;
msec = usec / 1000;
add_clat_sample(td, msec);
- add_bw_sample(td, msec);
+ add_bw_sample(td);
if (runtime_exceeded(td, &e))
break;
msec = mtime_since(&io_u->issue_time, &e);
add_clat_sample(td, msec);
- add_bw_sample(td, msec);
+ add_bw_sample(td);
+
+ if (!td_read(td))
+ log_io_piece(td, io_u);
bytes_done += io_u->buflen;
put_io_u(td, io_u);
int ret = 0;
if (v_io_u) {
- ret = verify_io_us(td, v_io_u, NULL);
+ ret = verify_io_u(v_io_u);
put_io_u(td, v_io_u);
*io_u = NULL;
}
{
struct timeval t;
struct io_u *io_u, *v_io_u = NULL;
- struct verify_header *hdr;
- int ret, back;
- char *p;
+ int ret;
td_set_runstate(td, TD_VERIFYING);
if (!io_u)
break;
- io_u->offset = td->cur_off;
- io_u->buflen = td->max_bs;
-
- if (io_u->offset + io_u->buflen > (td->kb << 10)) {
- io_u->buflen = (td->kb << 10) - io_u->offset;
- if (!io_u->buflen) {
- put_io_u(td, io_u);
- break;
- }
+ if (get_next_verify(td, &io_u->offset, &io_u->buflen)) {
+ put_io_u(td, io_u);
+ break;
}
io_prep_pread(&io_u->iocb, td->fd, io_u->buf, io_u->buflen, io_u->offset);
break;
}
- /*
- * got our io_u to verify, find back offset so we can
- * submit the next one before verifying this one
- */
v_io_u = ev_to_iou(td->aio_events);
- p = v_io_u->buf;
- back = v_io_u->buflen;
- do {
- hdr = (struct verify_header *) p;
-
- if (hdr->len > back)
- break;
-
- back -= hdr->len;
- p += hdr->len;
- } while (back);
- td->cur_off += (v_io_u->buflen - back);
+ td->cur_off = v_io_u->offset + v_io_u->buflen;
/*
* if we can't submit more io, we need to verify now
INIT_LIST_HEAD(&td->io_u_freelist);
INIT_LIST_HEAD(&td->io_u_busylist);
+ INIT_LIST_HEAD(&td->io_hist_list);
p = ALIGN(td->orig_buffer);
for (i = 0; i < max_units; i++) {
{
char file_name[128];
FILE *f;
- int i;
+ unsigned int i;
sprintf(file_name, "client%d_%s.log", td->thread_number, name);
f = fopen(file_name, "w");
static int create_file(struct thread_data *td)
{
unsigned long long left;
+ unsigned int bs;
char *b;
- int r, bs;
+ int r;
/*
* unless specifically asked for overwrite, let normal io extend it
r = write(td->fd, b, bs);
- if (r == bs) {
+ if (r == (int) bs) {
left -= bs;
continue;
} else {
if (td->use_aio && !td->aio_depth)
td->aio_depth = 1;
- if (td->min_bs == -1)
+ if (td->min_bs == -1U)
td->min_bs = td->bs;
- if (td->max_bs == -1)
+ if (td->max_bs == -1U)
td->max_bs = td->bs;
- if (td_read(td) || !td->sequential)
+ if (td_read(td))
td->verify = 0;
if (setup_rate(td))