Streamline thread_data data direction setting and checking

Currently it's a mess of ->ddir, ->iomix and ->sequential. Add
a TD_DDIR_* for each of these, so we can store them as one value.

A prerequisite for the next parsing cleanup.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/engines/mmap.c b/engines/mmap.c
index d429914..bd59b28 100644
--- a/engines/mmap.c
+++ b/engines/mmap.c
@@ -47,7 +47,7 @@
 	struct fio_file *f;
 	int i;
 
-	if (td->ddir == DDIR_READ && !td_rw(td))
+	if (!td_write(td))
 		return 0;
 
 	/*
diff --git a/engines/net.c b/engines/net.c
index 55b2128..60a6877 100644
--- a/engines/net.c
+++ b/engines/net.c
@@ -223,7 +223,7 @@
 		return 1;
 	}
 
-	if (td->iomix) {
+	if (td_rw(td)) {
 		log_err("fio: network connections must be read OR write\n");
 		return 1;
 	}
@@ -241,7 +241,7 @@
 	strcpy(host, buf);
 	port = atoi(sep);
 
-	if (td->ddir == DDIR_READ) {
+	if (td_read(td)) {
 		send_to_net(td) = 0;
 		ret = fio_netio_setup_listen(td, port);
 	} else {
diff --git a/eta.c b/eta.c
index 8e17d20..960bf4d 100644
--- a/eta.c
+++ b/eta.c
@@ -26,20 +26,20 @@
 			break;
 		case TD_RUNNING:
 			if (td_rw(td)) {
-				if (td->sequential)
-					c = 'M';
-				else
+				if (td_random(td))
 					c = 'm';
+				else
+					c = 'M';
 			} else if (td_read(td)) {
-				if (td->sequential)
-					c = 'R';
-				else
+				if (td_random(td))
 					c = 'r';
-			} else {
-				if (td->sequential)
-					c = 'W';
 				else
+					c = 'R';
+			} else {
+				if (td_random(td))
 					c = 'w';
+				else
+					c = 'W';
 			}
 			break;
 		case TD_VERIFYING:
diff --git a/filesetup.c b/filesetup.c
index 11138b7..356580e 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -113,8 +113,7 @@
 		for_each_file(td, f, i) {
 			int file_there = !file_ok(td, f);
 
-			if (file_there && td->ddir == DDIR_WRITE &&
-			    !td->overwrite) {
+			if (file_there && td_write(td) && !td->overwrite) {
 				unlink(f->file_name);
 				file_there = 0;
 			}
@@ -279,7 +278,7 @@
 	if (td->invalidate_cache && file_invalidate_cache(td, f))
 		return 1;
 
-	if (td->sequential) {
+	if (!td_random(td)) {
 		if (madvise(f->mmap, f->file_size, MADV_SEQUENTIAL) < 0) {
 			td_verror(td, errno, "madvise");
 			return 1;
@@ -313,7 +312,7 @@
 	if (td->invalidate_cache && file_invalidate_cache(td, f))
 		return 1;
 
-	if (td->sequential) {
+	if (!td_random(td)) {
 		if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_SEQUENTIAL) < 0) {
 			td_verror(td, errno, "fadvise");
 			return 1;
diff --git a/fio.c b/fio.c
index 9206393..58e03f9 100644
--- a/fio.c
+++ b/fio.c
@@ -98,7 +98,6 @@
 {
 	unsigned long spent;
 	unsigned long rate;
-	int ddir = td->ddir;
 
 	/*
 	 * allow a 2 second settle period in the beginning
@@ -110,18 +109,30 @@
 	 * if rate blocks is set, sample is running
 	 */
 	if (td->rate_bytes) {
+		unsigned long long bytes = 0;
+
 		spent = mtime_since(&td->lastrate, now);
 		if (spent < td->ratecycle)
 			return 0;
 
-		rate = (td->this_io_bytes[ddir] - td->rate_bytes) / spent;
-		if (rate < td->ratemin) {
-			fprintf(f_out, "%s: min rate %u not met, got %luKiB/sec\n", td->name, td->ratemin, rate);
+		if (td_read(td))
+			bytes += td->this_io_bytes[DDIR_READ];
+		if (td_write(td))
+			bytes += td->this_io_bytes[DDIR_WRITE];
+
+		if (bytes < td->rate_bytes) {
+			fprintf(f_out, "%s: min rate %u not met\n", td->name, td->ratemin);
 			return 1;
+		} else {
+			rate = (bytes - td->rate_bytes) / spent;
+			if (rate < td->ratemin || bytes < td->rate_bytes) {
+				fprintf(f_out, "%s: min rate %u not met, got %luKiB/sec\n", td->name, td->ratemin, rate);
+				return 1;
+			}
 		}
+		td->rate_bytes = bytes;
 	}
 
-	td->rate_bytes = td->this_io_bytes[ddir];
 	memcpy(&td->lastrate, now, sizeof(*now));
 	return 0;
 }
@@ -458,7 +469,7 @@
 		 */
 		usec = utime_since(&s, &comp_time);
 
-		rate_throttle(td, usec, bytes_done, td->ddir);
+		rate_throttle(td, usec, bytes_done);
 
 		if (check_min_rate(td, &comp_time)) {
 			if (exitall_on_terminate)
@@ -736,10 +747,11 @@
 		else
 			do_io(td);
 
-		runtime[td->ddir] += utime_since_now(&td->start);
-		if (td_rw(td) && td->io_bytes[td->ddir ^ 1])
-			runtime[td->ddir ^ 1] = runtime[td->ddir];
-
+		if (td_read(td) && td->io_bytes[DDIR_READ])
+			runtime[DDIR_READ] += utime_since_now(&td->start);
+		if (td_write(td) && td->io_bytes[DDIR_WRITE])
+			runtime[DDIR_WRITE] += utime_since_now(&td->start);
+		
 		if (td->error || td->terminate)
 			break;
 
diff --git a/fio.h b/fio.h
index 8c46b3f..8880ea6 100644
--- a/fio.h
+++ b/fio.h
@@ -28,6 +28,13 @@
 	DDIR_SYNC,
 };
 
+enum td_ddir {
+	TD_DDIR_READ	= 1 << 0,
+	TD_DDIR_WRITE	= 1 << 1,
+	TD_DDIR_RAND	= 1 << 2,
+	TD_DDIR_RW	= TD_DDIR_READ | TD_DDIR_WRITE,
+};
+
 /*
  * Use for maintaining statistics
  */
@@ -290,12 +297,10 @@
 	size_t orig_buffer_size;
 	volatile int terminate;
 	volatile int runstate;
-	enum fio_ddir ddir;
-	unsigned int iomix;
+	enum td_ddir td_ddir;
 	unsigned int ioprio;
 	unsigned int last_was_sync;
 
-	unsigned int sequential;
 	unsigned int odirect;
 	unsigned int invalidate_cache;
 	unsigned int create_serialize;
@@ -482,9 +487,10 @@
 
 extern struct thread_data *threads;
 
-#define td_read(td)		((td)->ddir == DDIR_READ)
-#define td_write(td)		((td)->ddir == DDIR_WRITE)
-#define td_rw(td)		((td)->iomix != 0)
+#define td_read(td)		((td)->td_ddir & TD_DDIR_READ)
+#define td_write(td)		((td)->td_ddir & TD_DDIR_WRITE)
+#define td_rw(td)		(((td)->td_ddir & TD_DDIR_RW) == TD_DDIR_RW)
+#define td_random(td)		((td)->td_ddir & TD_DDIR_RAND)
 
 #define BLOCKS_PER_MAP		(8 * sizeof(long))
 #define TO_MAP_BLOCK(td, f, b)	((b) - ((f)->file_offset / (td)->rw_min_bs))
@@ -588,7 +594,7 @@
 extern unsigned long mtime_since_genesis(void);
 extern void __usec_sleep(unsigned int);
 extern void usec_sleep(struct thread_data *, unsigned long);
-extern void rate_throttle(struct thread_data *, unsigned long, unsigned int, int);
+extern void rate_throttle(struct thread_data *, unsigned long, unsigned int);
 extern void fill_start_time(struct timeval *);
 extern void fio_gettime(struct timeval *, void *);
 extern void set_genesis_time(void);
diff --git a/init.c b/init.c
index 01e615f..9ed99d7 100644
--- a/init.c
+++ b/init.c
@@ -618,7 +618,7 @@
 	/*
 	 * only really works for sequential io for now, and with 1 file
 	 */
-	if (td->zone_size && !td->sequential && td->nr_files == 1)
+	if (td->zone_size && td_random(td) && td->nr_files == 1)
 		td->zone_size = 0;
 
 	/*
@@ -695,10 +695,10 @@
  */
 static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
 {
-	const char *ddir_str[] = { "read", "write", "randread", "randwrite",
-				   "rw", NULL, "randrw" };
+	const char *ddir_str[] = { NULL, "read", "write", "rw", NULL,
+				   "randread", "randwrite", "randrw" };
 	struct stat sb;
-	int numjobs, ddir, i;
+	int numjobs, i;
 	struct fio_file *f;
 
 	/*
@@ -795,8 +795,6 @@
 	if (!td->name)
 		td->name = strdup(jobname);
 
-	ddir = td->ddir + (!td->sequential << 1) + (td->iomix << 2);
-
 	if (!terse_output) {
 		if (!job_add_num) {
 			if (td->io_ops->flags & FIO_CPUIO)
@@ -809,7 +807,7 @@
 				c3 = to_kmg(td->min_bs[DDIR_WRITE]);
 				c4 = to_kmg(td->max_bs[DDIR_WRITE]);
 
-				fprintf(f_out, "%s: (g=%d): rw=%s, bs=%s-%s/%s-%s, ioengine=%s, iodepth=%u\n", td->name, td->groupid, ddir_str[ddir], c1, c2, c3, c4, td->io_ops->name, td->iodepth);
+				fprintf(f_out, "%s: (g=%d): rw=%s, bs=%s-%s/%s-%s, ioengine=%s, iodepth=%u\n", td->name, td->groupid, ddir_str[td->td_ddir], c1, c2, c3, c4, td->io_ops->name, td->iodepth);
 
 				free(c1);
 				free(c2);
@@ -874,9 +872,11 @@
 	os_random_seed(seeds[0], &td->bsrange_state);
 	os_random_seed(seeds[1], &td->verify_state);
 	os_random_seed(seeds[2], &td->rwmix_state);
-	os_random_seed(seeds[3], &td->next_file_state);
 
-	if (td->sequential)
+	if (td->file_service_type == FIO_FSERVICE_RANDOM)
+		os_random_seed(seeds[3], &td->next_file_state);
+
+	if (!td_random(td))
 		return 0;
 
 	if (td->rand_repeatable)
@@ -931,30 +931,22 @@
 	struct thread_data *td = data;
 
 	if (!strncmp(mem, "read", 4) || !strncmp(mem, "0", 1)) {
-		td->ddir = DDIR_READ;
-		td->sequential = 1;
+		td->td_ddir = TD_DDIR_READ;
 		return 0;
 	} else if (!strncmp(mem, "randread", 8)) {
-		td->ddir = DDIR_READ;
-		td->sequential = 0;
+		td->td_ddir = TD_DDIR_READ | TD_DDIR_RAND;
 		return 0;
 	} else if (!strncmp(mem, "write", 5) || !strncmp(mem, "1", 1)) {
-		td->ddir = DDIR_WRITE;
-		td->sequential = 1;
+		td->td_ddir = TD_DDIR_WRITE;
 		return 0;
 	} else if (!strncmp(mem, "randwrite", 9)) {
-		td->ddir = DDIR_WRITE;
-		td->sequential = 0;
+		td->td_ddir = TD_DDIR_WRITE | TD_DDIR_RAND;
 		return 0;
 	} else if (!strncmp(mem, "rw", 2)) {
-		td->ddir = DDIR_READ;
-		td->iomix = 1;
-		td->sequential = 1;
+		td->td_ddir = TD_DDIR_RW;
 		return 0;
 	} else if (!strncmp(mem, "randrw", 6)) {
-		td->ddir = DDIR_READ;
-		td->iomix = 1;
-		td->sequential = 0;
+		td->td_ddir = TD_DDIR_RW | TD_DDIR_RAND;
 		return 0;
 	}
 
diff --git a/io_u.c b/io_u.c
index 6fb754e..48d4076 100644
--- a/io_u.c
+++ b/io_u.c
@@ -106,7 +106,7 @@
 	unsigned long long b, rb;
 	long r;
 
-	if (!td->sequential) {
+	if (td_random(td)) {
 		unsigned long long max_blocks = f->file_size / td->min_bs[ddir];
 		int loops = 5;
 
@@ -253,7 +253,7 @@
 	/*
 	 * mark entry before potentially trimming io_u
 	 */
-	if (!td->read_iolog && !td->sequential && !td->norandommap)
+	if (!td->read_iolog && td_random(td) && !td->norandommap)
 		mark_random_map(td, f, io_u);
 
 	/*
diff --git a/log.c b/log.c
index dd63c38..513128d 100644
--- a/log.c
+++ b/log.c
@@ -56,7 +56,7 @@
 	 * be laid out with the block scattered as written. it's faster to
 	 * read them in in that order again, so don't sort
 	 */
-	if (td->sequential || !td->overwrite) {
+	if (!td_random(td) || !td->overwrite) {
 		list_add_tail(&ipo->list, &td->io_hist_list);
 		return;
 	}
@@ -137,11 +137,11 @@
 	if (!reads && !writes)
 		return 1;
 	else if (reads && !writes)
-		td->ddir = DDIR_READ;
+		td->td_ddir = TD_DDIR_READ;
 	else if (!reads && writes)
-		td->ddir = DDIR_READ;
+		td->td_ddir = TD_DDIR_READ;
 	else
-		td->iomix = 1;
+		td->td_ddir = TD_DDIR_RW;
 
 	return 0;
 }
diff --git a/stat.c b/stat.c
index 352ba48..34b2b6a 100644
--- a/stat.c
+++ b/stat.c
@@ -454,9 +454,10 @@
 	else
 		fprintf(f_out, "%s: (groupid=%d): err=%2d (%s): pid=%d\n",td->name, td->groupid, td->error, td->verror, td->pid);
 
-	show_ddir_status(td, rs, td->ddir);
-	if (td->io_bytes[td->ddir ^ 1])
-		show_ddir_status(td, rs, td->ddir ^ 1);
+	if (td_read(td))
+		show_ddir_status(td, rs, DDIR_READ);
+	if (td_write(td))
+		show_ddir_status(td, rs, DDIR_WRITE);
 
 	runtime = mtime_since(&td->epoch, &td->end_time);
 	if (runtime) {
diff --git a/time.c b/time.c
index 11ee0e0..4bf68a9 100644
--- a/time.c
+++ b/time.c
@@ -109,14 +109,14 @@
 }
 
 void rate_throttle(struct thread_data *td, unsigned long time_spent,
-		   unsigned int bytes, int ddir)
+		   unsigned int bytes)
 {
 	unsigned long usec_cycle;
 
 	if (!td->rate)
 		return;
 
-	usec_cycle = td->rate_usec_cycle * (bytes / td->min_bs[ddir]);
+	usec_cycle = td->rate_usec_cycle * (bytes / td->rw_min_bs);
 
 	if (time_spent < usec_cycle) {
 		unsigned long s = usec_cycle - time_spent;