From 4916320ec374cc5d2b4062c48d2e4c576472b739 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 17 Apr 2019 17:38:14 +0000 Subject: Separate test cases from examples Also adds a runtests makefile target. --- Makefile | 4 + examples/Makefile | 17 ++++ examples/io_uring-cp.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++ examples/io_uring-test.c | 91 +++++++++++++++++ test/Makefile | 16 ++- test/io_uring-cp.c | 249 ----------------------------------------------- test/io_uring-test.c | 91 ----------------- 7 files changed, 368 insertions(+), 349 deletions(-) create mode 100644 examples/Makefile create mode 100644 examples/io_uring-cp.c create mode 100644 examples/io_uring-test.c delete mode 100644 test/io_uring-cp.c delete mode 100644 test/io_uring-test.c diff --git a/Makefile b/Makefile index fe4fcb4..e78c990 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ default: all all: @$(MAKE) -C src @$(MAKE) -C test + @$(MAKE) -C examples + +runtests: + @$(MAKE) -C test runtests config-host.mak: configure @if [ ! -e "$@" ]; then \ diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..067fb94 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,17 @@ +CFLAGS ?= -g -O2 -Wall -D_GNU_SOURCE -L../src/ + +all_targets += io_uring-test io_uring-cp + +all: $(all_targets) + +test_srcs := io_uring-test.c io_uring-cp.c + +test_objs := $(patsubst %.c,%.ol,$(test_srcs)) + +io_uring-test: io_uring-test.c + $(CC) $(CFLAGS) -o $@ io_uring-test.c -luring +io_uring-cp: io_uring-cp.c + $(CC) $(CFLAGS) -o $@ io_uring-cp.c -luring + +clean: + rm -f $(all_targets) $(test_objs) diff --git a/examples/io_uring-cp.c b/examples/io_uring-cp.c new file mode 100644 index 0000000..f704ff6 --- /dev/null +++ b/examples/io_uring-cp.c @@ -0,0 +1,249 @@ +/* + * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-cp io_uring-cp.c -luring + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../src/liburing.h" + +#define QD 64 +#define BS (32*1024) + +static int infd, outfd; + +struct io_data { + int read; + off_t first_offset, offset; + size_t first_len; + struct iovec iov; +}; + +static int setup_context(unsigned entries, struct io_uring *ring) +{ + int ret; + + ret = io_uring_queue_init(entries, ring, 0); + if (ret < 0) { + fprintf(stderr, "queue_init: %s\n", strerror(-ret)); + return -1; + } + + return 0; +} + +static int get_file_size(int fd, off_t *size) +{ + struct stat st; + + if (fstat(fd, &st) < 0) + return -1; + if (S_ISREG(st.st_mode)) { + *size = st.st_size; + return 0; + } else if (S_ISBLK(st.st_mode)) { + unsigned long long bytes; + + if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) + return -1; + + *size = bytes; + return 0; + } + + return -1; +} + +static void queue_prepped(struct io_uring *ring, struct io_data *data) +{ + struct io_uring_sqe *sqe; + + sqe = io_uring_get_sqe(ring); + assert(sqe); + + if (data->read) + io_uring_prep_readv(sqe, infd, &data->iov, 1, data->offset); + else + io_uring_prep_writev(sqe, outfd, &data->iov, 1, data->offset); + + io_uring_sqe_set_data(sqe, data); +} + +static int queue_read(struct io_uring *ring, off_t size, off_t offset) +{ + struct io_uring_sqe *sqe; + struct io_data *data; + + sqe = io_uring_get_sqe(ring); + if (!sqe) + return 1; + + data = malloc(size + sizeof(*data)); + data->read = 1; + data->offset = data->first_offset = offset; + + data->iov.iov_base = data + 1; + data->iov.iov_len = size; + data->first_len = size; + + io_uring_prep_readv(sqe, infd, &data->iov, 1, offset); + io_uring_sqe_set_data(sqe, data); + return 0; +} + +static void queue_write(struct io_uring *ring, struct io_data *data) +{ + data->read = 0; + data->offset = data->first_offset; + + data->iov.iov_base = data + 1; + data->iov.iov_len = data->first_len; + + queue_prepped(ring, data); + io_uring_submit(ring); +} + +static int copy_file(struct io_uring *ring, off_t insize) +{ + unsigned long reads, writes; + struct io_uring_cqe *cqe; + off_t write_left, offset; + int ret; + + write_left = insize; + writes = reads = offset = 0; + + while (insize || write_left) { + int had_reads, got_comp; + + /* + * Queue up as many reads as we can + */ + had_reads = reads; + while (insize) { + off_t this_size = insize; + + if (reads + writes >= QD) + break; + if (this_size > BS) + this_size = BS; + else if (!this_size) + break; + + if (queue_read(ring, this_size, offset)) + break; + + insize -= this_size; + offset += this_size; + reads++; + } + + if (had_reads != reads) { + ret = io_uring_submit(ring); + if (ret < 0) { + fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret)); + break; + } + } + + /* + * Queue is full at this point. Find at least one completion. + */ + got_comp = 0; + while (write_left) { + struct io_data *data; + + if (!got_comp) { + ret = io_uring_wait_completion(ring, &cqe); + got_comp = 1; + } else + ret = io_uring_get_completion(ring, &cqe); + if (ret < 0) { + fprintf(stderr, "io_uring_get_completion: %s\n", + strerror(-ret)); + return 1; + } + if (!cqe) + break; + + data = io_uring_cqe_get_data(cqe); + if (cqe->res < 0) { + if (cqe->res == -EAGAIN) { + queue_prepped(ring, data); + io_uring_cqe_seen(ring, cqe); + continue; + } + fprintf(stderr, "cqe failed: %s\n", + strerror(-cqe->res)); + return 1; + } else if (cqe->res != data->iov.iov_len) { + /* Short read/write, adjust and requeue */ + data->iov.iov_base += cqe->res; + data->iov.iov_len -= cqe->res; + data->offset += cqe->res; + queue_prepped(ring, data); + io_uring_cqe_seen(ring, cqe); + continue; + } + + /* + * All done. if write, nothing else to do. if read, + * queue up corresponding write. + */ + if (data->read) { + queue_write(ring, data); + write_left -= data->first_len; + reads--; + writes++; + } else { + free(data); + writes--; + } + io_uring_cqe_seen(ring, cqe); + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct io_uring ring; + off_t insize; + int ret; + + if (argc < 3) { + printf("%s: infile outfile\n", argv[0]); + return 1; + } + + infd = open(argv[1], O_RDONLY); + if (infd < 0) { + perror("open infile"); + return 1; + } + outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (outfd < 0) { + perror("open outfile"); + return 1; + } + + if (setup_context(QD, &ring)) + return 1; + if (get_file_size(infd, &insize)) + return 1; + + ret = copy_file(&ring, insize); + + close(infd); + close(outfd); + io_uring_queue_exit(&ring); + return ret; +} diff --git a/examples/io_uring-test.c b/examples/io_uring-test.c new file mode 100644 index 0000000..fe0098c --- /dev/null +++ b/examples/io_uring-test.c @@ -0,0 +1,91 @@ +/* + * Simple app that demonstrates how to setup an io_uring interface, + * submit and complete IO against it, and then tear it down. + * + * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-test io_uring-test.c -luring + */ +#include +#include +#include +#include +#include +#include "../src/liburing.h" + +#define QD 4 + +int main(int argc, char *argv[]) +{ + struct io_uring ring; + int i, fd, ret, pending, done; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct iovec *iovecs; + off_t offset; + void *buf; + + if (argc < 2) { + printf("%s: file\n", argv[0]); + return 1; + } + + ret = io_uring_queue_init(QD, &ring, 0); + if (ret < 0) { + fprintf(stderr, "queue_init: %s\n", strerror(-ret)); + return 1; + } + + fd = open(argv[1], O_RDONLY | O_DIRECT); + if (fd < 0) { + perror("open"); + return 1; + } + + iovecs = calloc(QD, sizeof(struct iovec)); + for (i = 0; i < QD; i++) { + if (posix_memalign(&buf, 4096, 4096)) + return 1; + iovecs[i].iov_base = buf; + iovecs[i].iov_len = 4096; + } + + offset = 0; + i = 0; + do { + sqe = io_uring_get_sqe(&ring); + if (!sqe) + break; + io_uring_prep_readv(sqe, fd, &iovecs[i], 1, offset); + offset += iovecs[i].iov_len; + } while (1); + + ret = io_uring_submit(&ring); + if (ret < 0) { + fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret)); + return 1; + } + + done = 0; + pending = ret; + for (i = 0; i < pending; i++) { + ret = io_uring_wait_completion(&ring, &cqe); + if (ret < 0) { + fprintf(stderr, "io_uring_get_completion: %s\n", strerror(-ret)); + return 1; + } + + done++; + ret = 0; + if (cqe->res != 4096) { + fprintf(stderr, "ret=%d, wanted 4096\n", cqe->res); + ret = 1; + } + io_uring_cqe_seen(&ring, cqe); + if (ret) + break; + } + + printf("Submitted=%d, completed=%d\n", pending, done); + close(fd); + io_uring_queue_exit(&ring); + return 0; +} diff --git a/test/Makefile b/test/Makefile index 63bf67a..08b0c42 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,20 +1,15 @@ CFLAGS ?= -g -O2 -Wall -D_GNU_SOURCE -L../src/ -all_targets += io_uring-test io_uring-cp poll poll-cancel ring-leak fsync \ - io_uring_setup io_uring_register io_uring_enter nop sq-full cq-full +all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register \ + io_uring_enter nop sq-full cq-full all: $(all_targets) -test_srcs := io_uring-test.c io_uring-cp.c poll.c poll-cancel.c ring-leak.c \ - fsync.c io_uring_setup.c io_uring_register.c io_uring_enter.c nop.c \ - sq-full.c cq-full.c +test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \ + io_uring_register.c io_uring_enter.c nop.c sq-full.c cq-full.c test_objs := $(patsubst %.c,%.ol,$(test_srcs)) -io_uring-test: io_uring-test.c - $(CC) $(CFLAGS) -o $@ io_uring-test.c -luring -io_uring-cp: io_uring-cp.c - $(CC) $(CFLAGS) -o $@ io_uring-cp.c -luring poll: poll.c $(CC) $(CFLAGS) -o $@ poll.c -luring poll-cancel: poll-cancel.c @@ -38,3 +33,6 @@ cq-full: cq-full.c clean: rm -f $(all_targets) $(test_objs) + +runtests: + @./runtests.sh $(all_targets) diff --git a/test/io_uring-cp.c b/test/io_uring-cp.c deleted file mode 100644 index f704ff6..0000000 --- a/test/io_uring-cp.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-cp io_uring-cp.c -luring - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../src/liburing.h" - -#define QD 64 -#define BS (32*1024) - -static int infd, outfd; - -struct io_data { - int read; - off_t first_offset, offset; - size_t first_len; - struct iovec iov; -}; - -static int setup_context(unsigned entries, struct io_uring *ring) -{ - int ret; - - ret = io_uring_queue_init(entries, ring, 0); - if (ret < 0) { - fprintf(stderr, "queue_init: %s\n", strerror(-ret)); - return -1; - } - - return 0; -} - -static int get_file_size(int fd, off_t *size) -{ - struct stat st; - - if (fstat(fd, &st) < 0) - return -1; - if (S_ISREG(st.st_mode)) { - *size = st.st_size; - return 0; - } else if (S_ISBLK(st.st_mode)) { - unsigned long long bytes; - - if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) - return -1; - - *size = bytes; - return 0; - } - - return -1; -} - -static void queue_prepped(struct io_uring *ring, struct io_data *data) -{ - struct io_uring_sqe *sqe; - - sqe = io_uring_get_sqe(ring); - assert(sqe); - - if (data->read) - io_uring_prep_readv(sqe, infd, &data->iov, 1, data->offset); - else - io_uring_prep_writev(sqe, outfd, &data->iov, 1, data->offset); - - io_uring_sqe_set_data(sqe, data); -} - -static int queue_read(struct io_uring *ring, off_t size, off_t offset) -{ - struct io_uring_sqe *sqe; - struct io_data *data; - - sqe = io_uring_get_sqe(ring); - if (!sqe) - return 1; - - data = malloc(size + sizeof(*data)); - data->read = 1; - data->offset = data->first_offset = offset; - - data->iov.iov_base = data + 1; - data->iov.iov_len = size; - data->first_len = size; - - io_uring_prep_readv(sqe, infd, &data->iov, 1, offset); - io_uring_sqe_set_data(sqe, data); - return 0; -} - -static void queue_write(struct io_uring *ring, struct io_data *data) -{ - data->read = 0; - data->offset = data->first_offset; - - data->iov.iov_base = data + 1; - data->iov.iov_len = data->first_len; - - queue_prepped(ring, data); - io_uring_submit(ring); -} - -static int copy_file(struct io_uring *ring, off_t insize) -{ - unsigned long reads, writes; - struct io_uring_cqe *cqe; - off_t write_left, offset; - int ret; - - write_left = insize; - writes = reads = offset = 0; - - while (insize || write_left) { - int had_reads, got_comp; - - /* - * Queue up as many reads as we can - */ - had_reads = reads; - while (insize) { - off_t this_size = insize; - - if (reads + writes >= QD) - break; - if (this_size > BS) - this_size = BS; - else if (!this_size) - break; - - if (queue_read(ring, this_size, offset)) - break; - - insize -= this_size; - offset += this_size; - reads++; - } - - if (had_reads != reads) { - ret = io_uring_submit(ring); - if (ret < 0) { - fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret)); - break; - } - } - - /* - * Queue is full at this point. Find at least one completion. - */ - got_comp = 0; - while (write_left) { - struct io_data *data; - - if (!got_comp) { - ret = io_uring_wait_completion(ring, &cqe); - got_comp = 1; - } else - ret = io_uring_get_completion(ring, &cqe); - if (ret < 0) { - fprintf(stderr, "io_uring_get_completion: %s\n", - strerror(-ret)); - return 1; - } - if (!cqe) - break; - - data = io_uring_cqe_get_data(cqe); - if (cqe->res < 0) { - if (cqe->res == -EAGAIN) { - queue_prepped(ring, data); - io_uring_cqe_seen(ring, cqe); - continue; - } - fprintf(stderr, "cqe failed: %s\n", - strerror(-cqe->res)); - return 1; - } else if (cqe->res != data->iov.iov_len) { - /* Short read/write, adjust and requeue */ - data->iov.iov_base += cqe->res; - data->iov.iov_len -= cqe->res; - data->offset += cqe->res; - queue_prepped(ring, data); - io_uring_cqe_seen(ring, cqe); - continue; - } - - /* - * All done. if write, nothing else to do. if read, - * queue up corresponding write. - */ - if (data->read) { - queue_write(ring, data); - write_left -= data->first_len; - reads--; - writes++; - } else { - free(data); - writes--; - } - io_uring_cqe_seen(ring, cqe); - } - } - - return 0; -} - -int main(int argc, char *argv[]) -{ - struct io_uring ring; - off_t insize; - int ret; - - if (argc < 3) { - printf("%s: infile outfile\n", argv[0]); - return 1; - } - - infd = open(argv[1], O_RDONLY); - if (infd < 0) { - perror("open infile"); - return 1; - } - outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (outfd < 0) { - perror("open outfile"); - return 1; - } - - if (setup_context(QD, &ring)) - return 1; - if (get_file_size(infd, &insize)) - return 1; - - ret = copy_file(&ring, insize); - - close(infd); - close(outfd); - io_uring_queue_exit(&ring); - return ret; -} diff --git a/test/io_uring-test.c b/test/io_uring-test.c deleted file mode 100644 index fe0098c..0000000 --- a/test/io_uring-test.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Simple app that demonstrates how to setup an io_uring interface, - * submit and complete IO against it, and then tear it down. - * - * gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-test io_uring-test.c -luring - */ -#include -#include -#include -#include -#include -#include "../src/liburing.h" - -#define QD 4 - -int main(int argc, char *argv[]) -{ - struct io_uring ring; - int i, fd, ret, pending, done; - struct io_uring_sqe *sqe; - struct io_uring_cqe *cqe; - struct iovec *iovecs; - off_t offset; - void *buf; - - if (argc < 2) { - printf("%s: file\n", argv[0]); - return 1; - } - - ret = io_uring_queue_init(QD, &ring, 0); - if (ret < 0) { - fprintf(stderr, "queue_init: %s\n", strerror(-ret)); - return 1; - } - - fd = open(argv[1], O_RDONLY | O_DIRECT); - if (fd < 0) { - perror("open"); - return 1; - } - - iovecs = calloc(QD, sizeof(struct iovec)); - for (i = 0; i < QD; i++) { - if (posix_memalign(&buf, 4096, 4096)) - return 1; - iovecs[i].iov_base = buf; - iovecs[i].iov_len = 4096; - } - - offset = 0; - i = 0; - do { - sqe = io_uring_get_sqe(&ring); - if (!sqe) - break; - io_uring_prep_readv(sqe, fd, &iovecs[i], 1, offset); - offset += iovecs[i].iov_len; - } while (1); - - ret = io_uring_submit(&ring); - if (ret < 0) { - fprintf(stderr, "io_uring_submit: %s\n", strerror(-ret)); - return 1; - } - - done = 0; - pending = ret; - for (i = 0; i < pending; i++) { - ret = io_uring_wait_completion(&ring, &cqe); - if (ret < 0) { - fprintf(stderr, "io_uring_get_completion: %s\n", strerror(-ret)); - return 1; - } - - done++; - ret = 0; - if (cqe->res != 4096) { - fprintf(stderr, "ret=%d, wanted 4096\n", cqe->res); - ret = 1; - } - io_uring_cqe_seen(&ring, cqe); - if (ret) - break; - } - - printf("Submitted=%d, completed=%d\n", pending, done); - close(fd); - io_uring_queue_exit(&ring); - return 0; -} -- cgit