struct io_completion_data {
int nr; /* input */
+ int account; /* input */
int error; /* output */
unsigned long bytes_done[2]; /* output */
assert(ddir_rw(ddir));
if (f->last_pos < f->real_file_size) {
- *b = (f->last_pos - f->file_offset) / td->o.min_bs[ddir];
+ unsigned long long pos;
+
+ if (f->last_pos == f->file_offset && td->o.ddir_seq_add < 0)
+ f->last_pos = f->real_file_size;
+
+ pos = f->last_pos - f->file_offset;
+ if (pos)
+ pos += td->o.ddir_seq_add;
+
+ *b = pos / td->o.min_bs[ddir];
return 0;
}
} else
usec = td->rate_pending_usleep[ddir];
+ /*
+ * We are going to sleep, ensure that we flush anything pending as
+ * not to skew our latency numbers
+ */
+ if (td->cur_depth) {
+ int fio_unused ret;
+
+ ret = io_u_queued_complete(td, td->cur_depth, NULL);
+ }
+
fio_gettime(&t, NULL);
usec_sleep(td, usec);
usec = utime_since_now(&t);
return 0;
}
+/*
+ * Fill offset and start time into the buffer content, to prevent too
+ * easy compressible data for simple de-dupe attempts. Do this for every
+ * 512b block in the range, since that should be the smallest block size
+ * we can expect from a device.
+ */
+static void small_content_scramble(struct io_u *io_u)
+{
+ unsigned int i, nr_blocks = io_u->buflen / 512;
+ unsigned long long boffset;
+ unsigned int offset;
+ void *p, *end;
+
+ if (!nr_blocks)
+ return;
+
+ p = io_u->xfer_buf;
+ boffset = io_u->offset;
+
+ for (i = 0; i < nr_blocks; i++) {
+ /*
+ * Fill the byte offset into a "random" start offset of
+ * the buffer, given by the product of the usec time
+ * and the actual offset.
+ */
+ offset = (io_u->start_time.tv_usec ^ boffset) & 511;
+ offset &= ~(sizeof(unsigned long long) - 1);
+ if (offset >= 512 - sizeof(unsigned long long))
+ offset -= sizeof(unsigned long long);
+ memcpy(p + offset, &boffset, sizeof(boffset));
+
+ end = p + 512 - sizeof(io_u->start_time);
+ memcpy(end, &io_u->start_time, sizeof(io_u->start_time));
+ p += 512;
+ boffset += 512;
+ }
+}
+
/*
* Return an io_u to be processed. Gets a buflen and offset, sets direction,
* etc. The returned io_u is fully ready to be prepped and submitted.
{
struct fio_file *f;
struct io_u *io_u;
+ int do_scramble = 0;
io_u = __get_io_u(td);
if (!io_u) {
f->last_start = io_u->offset;
f->last_pos = io_u->offset + io_u->buflen;
- if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_WRITE)
- populate_verify_io_u(td, io_u);
- else if (td->o.refill_buffers && io_u->ddir == DDIR_WRITE)
- io_u_fill_buffer(td, io_u, io_u->xfer_buflen);
- else if (io_u->ddir == DDIR_READ) {
+ if (io_u->ddir == DDIR_WRITE) {
+ if (td->o.verify != VERIFY_NONE)
+ populate_verify_io_u(td, io_u);
+ else if (td->o.refill_buffers)
+ io_u_fill_buffer(td, io_u, io_u->xfer_buflen);
+ else if (td->o.scramble_buffers)
+ do_scramble = 1;
+ } else if (io_u->ddir == DDIR_READ) {
/*
* Reset the buf_filled parameters so next time if the
* buffer is used for writes it is refilled.
if (!td_io_prep(td, io_u)) {
if (!td->o.disable_slat)
fio_gettime(&io_u->start_time, NULL);
+ if (do_scramble)
+ small_content_scramble(io_u);
return io_u;
}
err_put:
td_verror(td, io_u->error, "io_u error");
}
+static void account_io_completion(struct thread_data *td, struct io_u *io_u,
+ struct io_completion_data *icd,
+ const enum fio_ddir idx, unsigned int bytes)
+{
+ unsigned long uninitialized_var(lusec);
+
+ if (!icd->account)
+ return;
+
+ if (!td->o.disable_clat || !td->o.disable_bw)
+ lusec = utime_since(&io_u->issue_time, &icd->time);
+
+ if (!td->o.disable_lat) {
+ unsigned long tusec;
+
+ tusec = utime_since(&io_u->start_time, &icd->time);
+ add_lat_sample(td, idx, tusec, bytes);
+ }
+
+ if (!td->o.disable_clat) {
+ add_clat_sample(td, idx, lusec, bytes);
+ io_u_mark_latency(td, lusec);
+ }
+
+ if (!td->o.disable_bw)
+ add_bw_sample(td, idx, bytes, &icd->time);
+
+ add_iops_sample(td, idx, &icd->time);
+}
+
static void io_completed(struct thread_data *td, struct io_u *io_u,
struct io_completion_data *icd)
{
int ret;
td->io_blocks[idx]++;
+ td->this_io_blocks[idx]++;
td->io_bytes[idx] += bytes;
td->this_io_bytes[idx] += bytes;
}
}
- if (ramp_time_over(td)) {
- unsigned long uninitialized_var(lusec);
+ if (ramp_time_over(td) && td->runstate == TD_RUNNING) {
+ account_io_completion(td, io_u, icd, idx, bytes);
- if (!td->o.disable_clat || !td->o.disable_bw)
- lusec = utime_since(&io_u->issue_time,
- &icd->time);
- if (!td->o.disable_lat) {
- unsigned long tusec;
-
- tusec = utime_since(&io_u->start_time,
- &icd->time);
- add_lat_sample(td, idx, tusec, bytes);
- }
- if (!td->o.disable_clat) {
- add_clat_sample(td, idx, lusec, bytes);
- io_u_mark_latency(td, lusec);
- }
- if (!td->o.disable_bw)
- add_bw_sample(td, idx, bytes, &icd->time);
if (__should_check_rate(td, idx)) {
td->rate_pending_usleep[idx] =
((td->this_io_bytes[idx] *
fio_gettime(&icd->time, NULL);
icd->nr = nr;
+ icd->account = 1;
icd->error = 0;
icd->bytes_done[0] = icd->bytes_done[1] = 0;
if (!(io_u->flags & IO_U_F_FREE_DEF))
put_io_u(td, io_u);
+
+ icd->account = 0;
}
}
io_u->buf_filled_len = 0;
if (!td->o.zero_buffers)
- fill_random_buf(io_u->buf, max_bs);
+ fill_random_buf(&td->buf_state, io_u->buf, max_bs);
else
memset(io_u->buf, 0, max_bs);
}