diff options
author | Kent Overstreet <koverstreet@google.com> | 2013-06-26 15:36:12 -0700 |
---|---|---|
committer | Kent Overstreet <koverstreet@google.com> | 2013-06-26 15:36:12 -0700 |
commit | 697dae6fc5c8bc31a33e9914234b5da247cb4f6f (patch) | |
tree | 2782ae3bbe91f9fdb64425cce8494b6c77592297 |
Initial commit
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | aio-cancel-old.c | 124 | ||||
-rw-r--r-- | aio-cancel.c | 190 |
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; +} |