For buffered IO, the rwmix split can often be grossly unfair
towards reads, because dirtying tons of memory is done much
faster than reading data. Improve the split for such workloads
by not only looking at time.
Note that it'll still be somewhat unfair, there's only so much
we can reliably do. But it's better.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
* read/write mixed workload state
*/
os_random_state_t rwmix_state;
* read/write mixed workload state
*/
os_random_state_t rwmix_state;
+ unsigned long long rwmix_bytes;
struct timeval rwmix_switch;
enum fio_ddir rwmix_ddir;
struct timeval rwmix_switch;
enum fio_ddir rwmix_ddir;
+static void set_rwmix_bytes(struct thread_data *td)
+{
+ unsigned long long rbytes;
+ unsigned int diff;
+
+ /*
+ * we do time or byte based switch. this is needed because
+ * buffered writes may issue a lot quicker than they complete,
+ * whereas reads do not.
+ */
+ rbytes = td->io_bytes[td->rwmix_ddir] - td->rwmix_bytes;
+ diff = td->o.rwmixread;
+ if (td->rwmix_ddir == DDIR_WRITE)
+ diff = 100 - diff;
+
+ td->rwmix_bytes = td->io_bytes[td->rwmix_ddir] + (rbytes * (100 - diff)) / diff;
+}
+
/*
* Return the data direction for the next io_u. If the job is a
* mixed read/write workload, check the rwmix cycle and switch if
/*
* Return the data direction for the next io_u. If the job is a
* mixed read/write workload, check the rwmix cycle and switch if
if (td_rw(td)) {
struct timeval now;
unsigned long elapsed;
if (td_rw(td)) {
struct timeval now;
unsigned long elapsed;
fio_gettime(&now, NULL);
elapsed = mtime_since_now(&td->rwmix_switch);
fio_gettime(&now, NULL);
elapsed = mtime_since_now(&td->rwmix_switch);
+ cycle = td->o.rwmixcycle;
+ if (!td->rwmix_bytes)
+ cycle /= 10;
+
/*
* Check if it's time to seed a new data direction.
*/
/*
* Check if it's time to seed a new data direction.
*/
- if (elapsed >= td->o.rwmixcycle) {
+ if (elapsed >= cycle &&
+ td->io_bytes[td->rwmix_ddir] >= td->rwmix_bytes) {
unsigned int v;
long r;
r = os_random_long(&td->rwmix_state);
v = 1 + (int) (100.0 * (r / (RAND_MAX + 1.0)));
unsigned int v;
long r;
r = os_random_long(&td->rwmix_state);
v = 1 + (int) (100.0 * (r / (RAND_MAX + 1.0)));
- if (v < td->o.rwmixread)
+ if (v < td->o.rwmixread) {
+ if (td->rwmix_ddir != DDIR_READ)
+ set_rwmix_bytes(td);
td->rwmix_ddir = DDIR_READ;
td->rwmix_ddir = DDIR_READ;
+ } else {
+ if (td->rwmix_ddir != DDIR_WRITE)
+ set_rwmix_bytes(td);
td->rwmix_ddir = DDIR_WRITE;
td->rwmix_ddir = DDIR_WRITE;
memcpy(&td->rwmix_switch, &now, sizeof(now));
}
return td->rwmix_ddir;
memcpy(&td->rwmix_switch, &now, sizeof(now));
}
return td->rwmix_ddir;