summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <koverstreet@google.com>2013-06-26 15:36:12 -0700
committerKent Overstreet <koverstreet@google.com>2013-06-26 15:36:12 -0700
commit697dae6fc5c8bc31a33e9914234b5da247cb4f6f (patch)
tree2782ae3bbe91f9fdb64425cce8494b6c77592297
Initial commit
-rw-r--r--.gitignore4
-rw-r--r--Makefile8
-rw-r--r--aio-cancel-old.c124
-rw-r--r--aio-cancel.c190
4 files changed, 326 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c1e4ec3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+aio-cancel
+aio-cancel-old
+.*
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..52a6944
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+CFLAGS=-g -O2
+LDLIBS=-laio
+
+all : aio-cancel
+
+.PHONY : clean
+clean :
+ -rm aio-cancel
diff --git a/aio-cancel-old.c b/aio-cancel-old.c
new file mode 100644
index 0000000..078004f
--- /dev/null
+++ b/aio-cancel-old.c
@@ -0,0 +1,124 @@
+/*
+ * Compile it with
+ * gcc aio.c -laio -o aio
+ */
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libaio.h>
+
+#define AIO_REQNUM 16
+#define AIO_REDO_BATCH 8
+#define PAGE_SIZE 4096
+#define AIO_BLKSIZE (4096 * PAGE_SIZE)
+
+static int fd;
+static long file_size;
+char buffer[AIO_BLKSIZE] __attribute__ ((aligned (PAGE_SIZE)));;
+
+static long rand_offset(void)
+{
+ long r = rand() % (file_size - AIO_BLKSIZE);
+ long offset = r - (r % PAGE_SIZE);
+ assert((offset % PAGE_SIZE) == 0);
+ assert(offset >= 0);
+ return offset;
+}
+
+int main(int argc, char const *argv[])
+{
+ io_context_t io_ctx;
+ struct iocb *iop[AIO_REQNUM];
+ struct iocb ioarray[AIO_REQNUM];
+ struct stat stat;
+ int rc;
+ int i, j;
+ unsigned long canceled = 0;
+ unsigned long completed = 0;
+ unsigned long loops;
+
+ if (argc != 3) {
+ printf("Please enter test file and number of iterations\n");
+ exit(EXIT_FAILURE);
+ }
+
+ assert((long)buffer % PAGE_SIZE == 0);
+
+ fd = open(argv[1], O_RDWR | O_DIRECT);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ loops = strtoull(argv[2], NULL, 10);
+ if (!loops) {
+ printf("Can't parse number of iterations\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fstat(fd, &stat);
+ file_size = stat.st_size;
+ printf("File size is %lu\n", file_size);
+
+ memset(&io_ctx, 0, sizeof(io_ctx));
+ io_queue_init(AIO_REQNUM, &io_ctx);
+
+ for (i = 0; i < AIO_REQNUM; ++i) {
+ struct iocb *iocbp = &ioarray[i];
+ iop[i] = iocbp;
+ io_prep_pread(iocbp, fd, buffer, AIO_BLKSIZE, rand_offset());
+ }
+
+ rc = io_submit(io_ctx, AIO_REQNUM, iop);
+ if (rc < 0)
+ fprintf(stderr, "io_submit: res = %d\n", rc);
+
+ for (j = 0; j < loops; j++) {
+ struct io_event events[AIO_REQNUM];
+ int num = io_getevents(io_ctx, 1, AIO_REDO_BATCH, events, NULL);
+
+ for (i = 0; i < num; i++) {
+ struct io_event *event = &events[i];
+ struct iocb *iocb = event->obj;
+
+ if (event->res == -ECANCELED)
+ canceled++;
+ else
+ completed++;
+
+ if ((event->res != AIO_BLKSIZE &&
+ event->res != -ECANCELED) ||
+ event->res2 != 0)
+ fprintf(stderr, "something wrong with event: res = %ld res2 = %ld\n", event->res, event->res2);
+
+ iop[i] = iocb;
+ io_prep_pread(iocb, fd, buffer, AIO_BLKSIZE, rand_offset());
+ }
+ rc = io_submit(io_ctx, num, iop);
+ if (rc < 0)
+ fprintf(stderr, "io_submit: res = %d\n", rc);
+
+ for (i = 0; i < num; i++) {
+ struct io_event cancelled;
+ rc = io_cancel(io_ctx, iop[i], &cancelled);
+ if (rc == -EINVAL)
+ fprintf(stderr, "io_cancel: %d\n", rc);
+ }
+ }
+
+ close(fd);
+
+ printf("canceled %lu completed %lu\n", canceled, completed);
+
+ return 0;
+}
diff --git a/aio-cancel.c b/aio-cancel.c
new file mode 100644
index 0000000..31cab17
--- /dev/null
+++ b/aio-cancel.c
@@ -0,0 +1,190 @@
+/*
+ * Simple AIO cancellation test. Submits random reads to the specified file and
+ * attempts to cancel as many as possible; upon completion it reports the number
+ * of IOs that were reported cancelled.
+ *
+ * Note that currently (6/26/2013), the block layer can't cancel IOs after
+ * they've been submitted to the device - it only checks if the IO has been
+ * cancelled when pulling it off the request queue, which means in practice for
+ * IO to be cancelled your queue depth has to be higher than the device's
+ * internal queue depth (for SATA disks with TCQ, I think that's 32?).
+ *
+ * Compile it with
+ * gcc -o aio-cancel aio-cancel.c -laio
+ */
+
+#define _GNU_SOURCE
+
+#include <linux/fs.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <libaio.h>
+
+#define PAGE_SIZE 4096UL
+
+static unsigned long canceled = 0, completed = 0;
+
+off_t getsize(int fd)
+{
+ off_t ret;
+ struct stat stat;
+
+ if (fstat(fd, &stat)) {
+ perror("stat error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (S_ISBLK(stat.st_mode)) {
+ if (ioctl(fd, BLKGETSIZE, &ret)) {
+ perror("ioctl error");
+ exit(EXIT_FAILURE);
+ }
+
+ ret *= 512;
+ }
+
+ return ret;
+}
+
+static void die(const char *msg, int err)
+{
+ fprintf(stderr, "%s error: %s\n", msg, strerror(err));
+ exit(EXIT_FAILURE);
+}
+
+static void usage(void)
+{
+ printf("Usage: aio-cancel <test file> <iodepth> <iterations> <iosize>\n"
+ "Simple AIO cancellation test\n");
+ exit(EXIT_FAILURE);
+}
+
+static unsigned reap_events(io_context_t io_ctx, unsigned long iosize)
+{
+ /* Wait on/reap some completions */
+ struct io_event events[16], *ev;
+ int nr_events = io_getevents(io_ctx, 1, 16, events, NULL);
+
+ //printf("reaped %i events\n", nr_events);
+
+ if (nr_events < 0)
+ die("io_getevents", -nr_events);
+
+ for (ev = events; ev < events + nr_events; ev++) {
+ if ((ev->res != iosize &&
+ ev->res != -ECANCELED) ||
+ ev->res2 != 0)
+ printf("something wrong with event: res = %ld res2 = %ld\n",
+ ev->res, ev->res2);
+
+ if (ev->res == -ECANCELED)
+ canceled++;
+ else
+ completed++;
+
+ free(ev->obj);
+ }
+
+ return nr_events;
+}
+
+static char buffer[PAGE_SIZE * 4096] __attribute__ ((aligned (PAGE_SIZE)));
+
+int main(int argc, char const *argv[])
+{
+ io_context_t io_ctx;
+ struct stat stat;
+ struct iocb *iocb;
+ struct io_event cancelled;
+ unsigned long nr_ios, iodepth, iosize, in_flight = 0;
+ off_t blocks;
+ int i, ret, fd;
+
+ if (argc != 5)
+ usage();
+
+ fd = open(argv[1], O_RDWR | O_DIRECT);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ nr_ios = strtoul(argv[2], NULL, 10);
+ if (!nr_ios) {
+ printf("Can't parse number of IOs\n");
+ usage();
+ }
+
+ iodepth = strtoul(argv[3], NULL, 10);
+ if (!iodepth) {
+ printf("Can't parse iodepth\n");
+ usage();
+ }
+
+ iosize = strtoul(argv[4], NULL, 10);
+ if (!iosize) {
+ printf("Can't parse iosize\n");
+ usage();
+ }
+
+ if (iosize % PAGE_SIZE || iosize > sizeof(buffer)) {
+ printf("Bad iosize: must be a multiple of PAGE_SIZE and not more than %zu\n",
+ sizeof(buffer));
+ exit(EXIT_FAILURE);
+ }
+
+ blocks = getsize(fd);
+
+ if (blocks < iosize) {
+ printf("File too small\n");
+ exit(EXIT_FAILURE);
+ }
+
+ blocks = (blocks - iosize) / PAGE_SIZE;
+
+ printf("Doing %lu random reads to %s with iodepth %lu, iosize %lu\n",
+ nr_ios, argv[1], iodepth, iosize);
+
+ memset(&io_ctx, 0, sizeof(io_ctx));
+ ret = io_queue_init(iodepth, &io_ctx);
+ if (ret)
+ die("io_queue_init", -ret);
+
+ while (nr_ios) {
+ while (in_flight >= iodepth)
+ in_flight -= reap_events(io_ctx, iosize);
+
+ iocb = malloc(sizeof(struct iocb));
+ io_prep_pread(iocb, fd, buffer, iosize,
+ (random() % blocks) * PAGE_SIZE);
+
+ ret = io_submit(io_ctx, 1, &iocb);
+ if (ret != 1)
+ die("io_submit", -ret);
+
+ ret = io_cancel(io_ctx, iocb, &cancelled);
+ if (ret && ret != -EINPROGRESS)
+ printf("io_cancel error: %s\n", strerror(-ret));
+
+ in_flight++;
+ nr_ios--;
+ //printf("submitted to %llu: nr_ios %lu in_flight %lu iodepth %lu\n",
+ // iocb->u.c.offset, nr_ios, in_flight, iodepth);
+ }
+
+ while (in_flight)
+ in_flight -= reap_events(io_ctx, iosize);
+
+ close(fd);
+
+ printf("canceled %lu completed %lu\n", canceled, completed);
+
+ return 0;
+}