Recent changes (master)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The following changes since commit ca4eefc1b55d7f9fc03bf113d63e3d0b2d7b38ae:

  Merge branch 'evelu-fixes2' of https://github.com/ErwanAliasr1/fio (2021-10-01 13:55:52 -0600)

are available in the Git repository at:

  git://git.kernel.dk/fio.git master

for you to fetch changes up to 24a24c12a04c45174c2d68ffb7fcb3f367e40dee:

  t/io_uring: clean up aio wait loop (2021-10-04 17:04:04 -0600)

----------------------------------------------------------------
Jens Axboe (6):
      t/io_uring: remove extra add_stat() call
      t/io_uring: add support for legacy AIO
      t/io_uring: don't print partial IOPS etc output if exit signal was received
      t/io_uring: don't track IO latencies the first second of runtime
      t/io_uring: check for valid clock_index and finish state for stats
      t/io_uring: clean up aio wait loop

 t/io_uring.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 253 insertions(+), 24 deletions(-)

---

Diff of recent changes:

diff --git a/t/io_uring.c b/t/io_uring.c
index 2ec4caeb..f27a12c7 100644
--- a/t/io_uring.c
+++ b/t/io_uring.c
@@ -7,6 +7,10 @@
 #include <inttypes.h>
 #include <math.h>
 
+#ifdef CONFIG_LIBAIO
+#include <libaio.h>
+#endif
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
@@ -86,6 +90,10 @@ struct submitter {
 	int clock_index;
 	unsigned long *plat;
 
+#ifdef CONFIG_LIBAIO
+	io_context_t aio_ctx;
+#endif
+
 	struct file files[MAX_FDS];
 	unsigned nr_files;
 	unsigned cur_file;
@@ -94,6 +102,7 @@ struct submitter {
 
 static struct submitter *submitter;
 static volatile int finish;
+static int stats_running;
 
 static int depth = DEPTH;
 static int batch_submit = BATCH_SUBMIT;
@@ -108,6 +117,8 @@ static int sq_thread_cpu = -1;	/* pin above thread to this CPU */
 static int do_nop = 0;		/* no-op SQ ring commands */
 static int nthreads = 1;
 static int stats = 0;		/* generate IO stats */
+static int aio = 0;		/* use libaio */
+
 static unsigned long tsc_rate;
 
 #define TSC_RATE_FILE	"tsc-rate"
@@ -298,10 +309,12 @@ static void add_stat(struct submitter *s, int clock_index, int nr)
 	unsigned long cycles;
 	unsigned int pidx;
 
-	cycles = get_cpu_clock();
-	cycles -= s->clock_batch[clock_index];
-	pidx = plat_val_to_idx(cycles);
-	s->plat[pidx] += nr;
+	if (!s->finish && clock_index) {
+		cycles = get_cpu_clock();
+		cycles -= s->clock_batch[clock_index];
+		pidx = plat_val_to_idx(cycles);
+		s->plat[pidx] += nr;
+	}
 #endif
 }
 
@@ -432,11 +445,11 @@ static void init_io(struct submitter *s, unsigned index)
 	sqe->ioprio = 0;
 	sqe->off = offset;
 	sqe->user_data = (unsigned long) f->fileno;
-	if (stats)
+	if (stats && stats_running)
 		sqe->user_data |= ((unsigned long)s->clock_index << 32);
 }
 
-static int prep_more_ios(struct submitter *s, int max_ios)
+static int prep_more_ios_uring(struct submitter *s, int max_ios)
 {
 	struct io_sq_ring *ring = &s->sq_ring;
 	unsigned index, tail, next_tail, prepped = 0;
@@ -481,7 +494,7 @@ static int get_file_size(struct file *f)
 	return -1;
 }
 
-static int reap_events(struct submitter *s)
+static int reap_events_uring(struct submitter *s)
 {
 	struct io_cq_ring *ring = &s->cq_ring;
 	struct io_uring_cqe *cqe;
@@ -517,9 +530,8 @@ static int reap_events(struct submitter *s)
 					stat_nr = 0;
 				}
 				last_idx = clock_index;
-			}
-			stat_nr++;
-			add_stat(s, clock_index, 1);
+			} else if (clock_index)
+				stat_nr++;
 		}
 		reaped++;
 		head++;
@@ -535,11 +547,9 @@ static int reap_events(struct submitter *s)
 	return reaped;
 }
 
-static void *submitter_fn(void *data)
+static int submitter_init(struct submitter *s)
 {
-	struct submitter *s = data;
-	struct io_sq_ring *ring = &s->sq_ring;
-	int i, ret, prepped, nr_batch;
+	int i, nr_batch;
 
 	s->tid = gettid();
 	printf("submitter=%d\n", s->tid);
@@ -552,7 +562,7 @@ static void *submitter_fn(void *data)
 	if (stats) {
 		nr_batch = roundup_pow2(depth / batch_submit);
 		s->clock_batch = calloc(nr_batch, sizeof(unsigned long));
-		s->clock_index = 0;
+		s->clock_index = 1;
 
 		s->plat = calloc(PLAT_NR, sizeof(unsigned long));
 	} else {
@@ -561,6 +571,170 @@ static void *submitter_fn(void *data)
 		nr_batch = 0;
 	}
 
+	return nr_batch;
+}
+
+#ifdef CONFIG_LIBAIO
+static int prep_more_ios_aio(struct submitter *s, int max_ios, struct iocb *iocbs)
+{
+	unsigned long offset, data;
+	struct file *f;
+	unsigned index;
+	long r;
+
+	index = 0;
+	while (index < max_ios) {
+		struct iocb *iocb = &iocbs[index];
+
+		if (s->nr_files == 1) {
+			f = &s->files[0];
+		} else {
+			f = &s->files[s->cur_file];
+			if (f->pending_ios >= file_depth(s)) {
+				s->cur_file++;
+				if (s->cur_file == s->nr_files)
+					s->cur_file = 0;
+				f = &s->files[s->cur_file];
+			}
+		}
+		f->pending_ios++;
+
+		r = lrand48();
+		offset = (r % (f->max_blocks - 1)) * bs;
+		io_prep_pread(iocb, f->real_fd, s->iovecs[index].iov_base,
+				s->iovecs[index].iov_len, offset);
+
+		data = f->fileno;
+		if (stats && stats_running)
+			data |= ((unsigned long) s->clock_index << 32);
+		iocb->data = (void *) (uintptr_t) data;
+		index++;
+	}
+	return index;
+}
+
+static int reap_events_aio(struct submitter *s, struct io_event *events, int evs)
+{
+	int last_idx = -1, stat_nr = 0;
+	int reaped = 0;
+
+	while (evs) {
+		unsigned long data = (uintptr_t) events[reaped].data;
+		struct file *f = &s->files[data & 0xffffffff];
+
+		f->pending_ios--;
+		if (events[reaped].res != bs) {
+			printf("io: unexpected ret=%ld\n", events[reaped].res);
+			return -1;
+		}
+		if (stats) {
+			int clock_index = data >> 32;
+
+			if (last_idx != clock_index) {
+				if (last_idx != -1) {
+					add_stat(s, last_idx, stat_nr);
+					stat_nr = 0;
+				}
+				last_idx = clock_index;
+			} else if (clock_index)
+				stat_nr++;
+		}
+		reaped++;
+		evs--;
+	}
+
+	if (stat_nr)
+		add_stat(s, last_idx, stat_nr);
+
+	s->inflight -= reaped;
+	s->done += reaped;
+	return reaped;
+}
+
+static void *submitter_aio_fn(void *data)
+{
+	struct submitter *s = data;
+	int i, ret, prepped, nr_batch;
+	struct iocb **iocbsptr;
+	struct iocb *iocbs;
+	struct io_event *events;
+
+	nr_batch = submitter_init(s);
+
+	iocbsptr = calloc(depth, sizeof(struct iocb *));
+	iocbs = calloc(depth, sizeof(struct iocb));
+	events = calloc(depth, sizeof(struct io_event));
+
+	for (i = 0; i < depth; i++)
+		iocbsptr[i] = &iocbs[i];
+
+	prepped = 0;
+	do {
+		int to_wait, to_submit, to_prep;
+
+		if (!prepped && s->inflight < depth) {
+			to_prep = min(depth - s->inflight, batch_submit);
+			prepped = prep_more_ios_aio(s, to_prep, iocbs);
+#ifdef ARCH_HAVE_CPU_CLOCK
+			if (prepped && stats) {
+				s->clock_batch[s->clock_index] = get_cpu_clock();
+				s->clock_index = (s->clock_index + 1) & (nr_batch - 1);
+			}
+#endif
+		}
+		s->inflight += prepped;
+		to_submit = prepped;
+
+		if (to_submit && (s->inflight + to_submit <= depth))
+			to_wait = 0;
+		else
+			to_wait = min(s->inflight + to_submit, batch_complete);
+
+		ret = io_submit(s->aio_ctx, to_submit, iocbsptr);
+		s->calls++;
+		if (ret < 0) {
+			perror("io_submit");
+			break;
+		} else if (ret != to_submit) {
+			printf("submitted %d, wanted %d\n", ret, to_submit);
+			break;
+		}
+		prepped = 0;
+
+		while (to_wait) {
+			int r;
+
+			s->calls++;
+			r = io_getevents(s->aio_ctx, to_wait, to_wait, events, NULL);
+			if (r < 0) {
+				perror("io_getevents");
+				break;
+			} else if (r != to_wait) {
+				printf("r=%d, wait=%d\n", r, to_wait);
+				break;
+			}
+			r = reap_events_aio(s, events, r);
+			s->reaps += r;
+			to_wait -= r;
+		}
+	} while (!s->finish);
+
+	free(iocbsptr);
+	free(iocbs);
+	free(events);
+	finish = 1;
+	return NULL;
+}
+#endif
+
+static void *submitter_uring_fn(void *data)
+{
+	struct submitter *s = data;
+	struct io_sq_ring *ring = &s->sq_ring;
+	int ret, prepped, nr_batch;
+
+	nr_batch = submitter_init(s);
+
 	prepped = 0;
 	do {
 		int to_wait, to_submit, this_reap, to_prep;
@@ -568,7 +742,7 @@ static void *submitter_fn(void *data)
 
 		if (!prepped && s->inflight < depth) {
 			to_prep = min(depth - s->inflight, batch_submit);
-			prepped = prep_more_ios(s, to_prep);
+			prepped = prep_more_ios_uring(s, to_prep);
 #ifdef ARCH_HAVE_CPU_CLOCK
 			if (prepped && stats) {
 				s->clock_batch[s->clock_index] = get_cpu_clock();
@@ -613,7 +787,8 @@ submit:
 		this_reap = 0;
 		do {
 			int r;
-			r = reap_events(s);
+
+			r = reap_events_uring(s);
 			if (r == -1) {
 				s->finish = 1;
 				break;
@@ -693,6 +868,34 @@ static void arm_sig_int(void)
 #endif
 }
 
+static int setup_aio(struct submitter *s)
+{
+#ifdef CONFIG_LIBAIO
+	if (polled) {
+		fprintf(stderr, "aio does not support polled IO\n");
+		polled = 0;
+	}
+	if (sq_thread_poll) {
+		fprintf(stderr, "aio does not support SQPOLL IO\n");
+		sq_thread_poll = 0;
+	}
+	if (do_nop) {
+		fprintf(stderr, "aio does not support polled IO\n");
+		do_nop = 0;
+	}
+	if (fixedbufs || register_files) {
+		fprintf(stderr, "aio does not support registered files or buffers\n");
+		fixedbufs = register_files = 0;
+	}
+
+	return io_queue_init(depth, &s->aio_ctx);
+#else
+	fprintf(stderr, "Legacy AIO not available on this system/build\n");
+	errno = EINVAL;
+	return -1;
+#endif
+}
+
 static int setup_ring(struct submitter *s)
 {
 	struct io_sq_ring *sring = &s->sq_ring;
@@ -812,9 +1015,10 @@ static void usage(char *argv, int status)
 		" -O <bool> : Use O_DIRECT, default %d\n"
 		" -N <bool> : Perform just no-op requests, default %d\n"
 		" -t <bool> : Track IO latencies, default %d\n"
-		" -T <int>  : TSC rate in HZ\n",
+		" -T <int>  : TSC rate in HZ\n"
+		" -a <bool> : Use legacy aio, default %d\n",
 		argv, DEPTH, BATCH_SUBMIT, BATCH_COMPLETE, BS, polled,
-		fixedbufs, register_files, nthreads, !buffered, do_nop, stats);
+		fixedbufs, register_files, nthreads, !buffered, do_nop, stats, aio);
 	exit(status);
 }
 
@@ -874,8 +1078,11 @@ int main(int argc, char *argv[])
 	if (!do_nop && argc < 2)
 		usage(argv[0], 1);
 
-	while ((opt = getopt(argc, argv, "d:s:c:b:p:B:F:n:N:O:t:T:h?")) != -1) {
+	while ((opt = getopt(argc, argv, "d:s:c:b:p:B:F:n:N:O:t:T:a:h?")) != -1) {
 		switch (opt) {
+		case 'a':
+			aio = !!atoi(optarg);
+			break;
 		case 'd':
 			depth = atoi(optarg);
 			break;
@@ -1033,19 +1240,32 @@ int main(int argc, char *argv[])
 	for (j = 0; j < nthreads; j++) {
 		s = get_submitter(j);
 
-		err = setup_ring(s);
+		if (!aio)
+			err = setup_ring(s);
+		else
+			err = setup_aio(s);
 		if (err) {
 			printf("ring setup failed: %s, %d\n", strerror(errno), err);
 			return 1;
 		}
 	}
 	s = get_submitter(0);
-	printf("polled=%d, fixedbufs=%d, register_files=%d, buffered=%d", polled, fixedbufs, register_files, buffered);
-	printf(" QD=%d, sq_ring=%d, cq_ring=%d\n", depth, *s->sq_ring.ring_entries, *s->cq_ring.ring_entries);
+	printf("polled=%d, fixedbufs=%d, register_files=%d, buffered=%d, QD=%d\n", polled, fixedbufs, register_files, buffered, depth);
+	if (!aio)
+		printf("Engine=io_uring, sq_ring=%d, cq_ring=%d\n", *s->sq_ring.ring_entries, *s->cq_ring.ring_entries);
+#ifdef CONFIG_LIBAIO
+	else
+		printf("Engine=aio, ctx=%p\n", &s->aio_ctx);
+#endif
 
 	for (j = 0; j < nthreads; j++) {
 		s = get_submitter(j);
-		pthread_create(&s->thread, NULL, submitter_fn, s);
+		if (!aio)
+			pthread_create(&s->thread, NULL, submitter_uring_fn, s);
+#ifdef CONFIG_LIBAIO
+		else
+			pthread_create(&s->thread, NULL, submitter_aio_fn, s);
+#endif
 	}
 
 	fdepths = malloc(8 * s->nr_files * nthreads);
@@ -1058,6 +1278,15 @@ int main(int argc, char *argv[])
 		unsigned long iops, bw;
 
 		sleep(1);
+
+		/* don't print partial run, if interrupted by signal */
+		if (finish)
+			break;
+
+		/* one second in to the run, enable stats */
+		if (stats)
+			stats_running = 1;
+
 		for (j = 0; j < nthreads; j++) {
 			this_done += s->done;
 			this_call += s->calls;



[Index of Archives]     [Linux Kernel]     [Linux SCSI]     [Linux IDE]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux