unsigned *tail;
unsigned *ring_mask;
unsigned *ring_entries;
- struct io_uring_event *events;
+ struct io_uring_cqe *cqes;
};
#define DEPTH 32
#define BS 4096
+#define MAX_FDS 16
+
static unsigned sq_ring_mask, cq_ring_mask;
+struct file {
+ unsigned long max_blocks;
+ int fd;
+};
+
struct submitter {
pthread_t thread;
- unsigned long max_blocks;
int ring_fd;
struct drand48_data rand;
struct io_sq_ring sq_ring;
- struct io_uring_iocb *iocbs;
+ struct io_uring_sqe *sqes;
struct iovec iovecs[DEPTH];
struct io_cq_ring cq_ring;
int inflight;
unsigned long calls;
unsigned long cachehit, cachemiss;
volatile int finish;
- char filename[128];
+ struct file files[MAX_FDS];
+ unsigned nr_files;
+ unsigned cur_file;
};
static struct submitter submitters[1];
static volatile int finish;
-static int polled = 0; /* use IO polling */
+static int polled = 1; /* use IO polling */
static int fixedbufs = 0; /* use fixed user buffers */
-static int buffered = 1; /* use buffered IO, not O_DIRECT */
+static int buffered = 0; /* use buffered IO, not O_DIRECT */
static int sq_thread = 0; /* use kernel submission thread */
static int sq_thread_cpu = 0; /* pin above thread to this CPU */
static int io_uring_setup(unsigned entries, struct iovec *iovecs,
- struct io_uring_params *p)
+ unsigned nr_iovecs, struct io_uring_params *p)
{
- return syscall(__NR_sys_io_uring_setup, entries, iovecs, p);
+ return syscall(__NR_sys_io_uring_setup, entries, iovecs, nr_iovecs, p);
}
static int io_uring_enter(struct submitter *s, unsigned int to_submit,
return syscall(__NR_gettid);
}
-static void init_io(struct submitter *s, int fd, unsigned index)
+static void init_io(struct submitter *s, unsigned index)
{
- struct io_uring_iocb *iocb = &s->iocbs[index];
+ struct io_uring_sqe *sqe = &s->sqes[index];
unsigned long offset;
+ struct file *f;
long r;
- lrand48_r(&s->rand, &r);
- offset = (r % (s->max_blocks - 1)) * BS;
+ f = &s->files[s->cur_file];
+ s->cur_file++;
+ if (s->cur_file == s->nr_files)
+ s->cur_file = 0;
- if (fixedbufs)
- iocb->opcode = IORING_OP_READ_FIXED;
- else
- iocb->opcode = IORING_OP_READ;
- iocb->flags = 0;
- iocb->ioprio = 0;
- iocb->fd = fd;
- iocb->off = offset;
- iocb->addr = s->iovecs[index].iov_base;
- iocb->len = BS;
+ lrand48_r(&s->rand, &r);
+ offset = (r % (f->max_blocks - 1)) * BS;
+
+ if (fixedbufs) {
+ sqe->opcode = IORING_OP_READ_FIXED;
+ sqe->addr = s->iovecs[index].iov_base;
+ sqe->len = BS;
+ sqe->index = index;
+ } else {
+ sqe->opcode = IORING_OP_READV;
+ sqe->addr = &s->iovecs[index];
+ sqe->len = 1;
+ }
+ sqe->flags = 0;
+ sqe->ioprio = 0;
+ sqe->fd = f->fd;
+ sqe->off = offset;
}
-static int prep_more_ios(struct submitter *s, int fd, int max_ios)
+static int prep_more_ios(struct submitter *s, int max_ios)
{
struct io_sq_ring *ring = &s->sq_ring;
unsigned index, tail, next_tail, prepped = 0;
break;
index = tail & sq_ring_mask;
- init_io(s, fd, index);
+ init_io(s, index);
ring->array[index] = index;
prepped++;
tail = next_tail;
} while (prepped < max_ios);
if (*ring->tail != tail) {
- /* order tail store with writes to iocbs above */
+ /* order tail store with writes to sqes above */
barrier();
*ring->tail = tail;
barrier();
return prepped;
}
-static int get_file_size(int fd, unsigned long *blocks)
+static int get_file_size(struct file *f)
{
struct stat st;
- if (fstat(fd, &st) < 0)
+ if (fstat(f->fd, &st) < 0)
return -1;
if (S_ISBLK(st.st_mode)) {
unsigned long long bytes;
- if (ioctl(fd, BLKGETSIZE64, &bytes) != 0)
+ if (ioctl(f->fd, BLKGETSIZE64, &bytes) != 0)
return -1;
- *blocks = bytes / BS;
+ f->max_blocks = bytes / BS;
return 0;
} else if (S_ISREG(st.st_mode)) {
- *blocks = st.st_size / BS;
+ f->max_blocks = st.st_size / BS;
return 0;
}
static int reap_events(struct submitter *s)
{
struct io_cq_ring *ring = &s->cq_ring;
- struct io_uring_event *ev;
+ struct io_uring_cqe *cqe;
unsigned head, reaped = 0;
head = *ring->head;
barrier();
if (head == *ring->tail)
break;
- ev = &ring->events[head & cq_ring_mask];
- if (ev->res != BS) {
- struct io_uring_iocb *iocb = &s->iocbs[ev->index];
-
- printf("io: unexpected ret=%d\n", ev->res);
- printf("offset=%lu, size=%lu\n",
- (unsigned long) iocb->off,
- (unsigned long) iocb->len);
+ cqe = &ring->cqes[head & cq_ring_mask];
+ if (cqe->res != BS) {
+ printf("io: unexpected ret=%d\n", cqe->res);
return -1;
}
- if (ev->flags & IOEV_FLAG_CACHEHIT)
+ if (cqe->flags & IOCQE_FLAG_CACHEHIT)
s->cachehit++;
else
s->cachemiss++;
static void *submitter_fn(void *data)
{
struct submitter *s = data;
- int fd, ret, prepped, flags;
+ int ret, prepped;
printf("submitter=%d\n", gettid());
- flags = O_RDONLY;
- if (!buffered)
- flags |= O_DIRECT;
- fd = open(s->filename, flags);
- if (fd < 0) {
- perror("open");
- goto done;
- }
-
- if (get_file_size(fd, &s->max_blocks)) {
- printf("failed getting size of device/file\n");
- goto err;
- }
- if (s->max_blocks <= 1) {
- printf("Zero file/device size?\n");
- goto err;
- }
- s->max_blocks--;
-
srand48_r(pthread_self(), &s->rand);
prepped = 0;
if (!prepped && s->inflight < DEPTH) {
to_prep = min(DEPTH - s->inflight, BATCH_SUBMIT);
- prepped = prep_more_ios(s, fd, to_prep);
+ prepped = prep_more_ios(s, to_prep);
}
s->inflight += prepped;
submit_more:
break;
}
} while (!s->finish);
-err:
- close(fd);
-done:
+
finish = 1;
return NULL;
}
if (polled)
p.flags |= IORING_SETUP_IOPOLL;
- if (fixedbufs)
- p.flags |= IORING_SETUP_FIXEDBUFS;
if (buffered)
p.flags |= IORING_SETUP_SQWQ;
else if (sq_thread) {
}
if (fixedbufs)
- fd = io_uring_setup(DEPTH, s->iovecs, &p);
+ fd = io_uring_setup(DEPTH, s->iovecs, DEPTH, &p);
else
- fd = io_uring_setup(DEPTH, NULL, &p);
+ fd = io_uring_setup(DEPTH, NULL, 0, &p);
if (fd < 0) {
perror("io_uring_setup");
return 1;
sring->array = ptr + p.sq_off.array;
sq_ring_mask = *sring->ring_mask;
- s->iocbs = mmap(0, p.sq_entries * sizeof(struct io_uring_iocb),
+ s->sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
- IORING_OFF_IOCB);
- printf("iocbs ptr = 0x%p\n", s->iocbs);
+ IORING_OFF_SQES);
+ printf("sqes ptr = 0x%p\n", s->sqes);
- ptr = mmap(0, p.cq_off.events + p.cq_entries * sizeof(struct io_uring_event),
+ ptr = mmap(0, p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
IORING_OFF_CQ_RING);
printf("cq_ring ptr = 0x%p\n", ptr);
cring->tail = ptr + p.cq_off.tail;
cring->ring_mask = ptr + p.cq_off.ring_mask;
cring->ring_entries = ptr + p.cq_off.ring_entries;
- cring->events = ptr + p.cq_off.events;
+ cring->cqes = ptr + p.cq_off.cqes;
cq_ring_mask = *cring->ring_mask;
return 0;
}
{
struct submitter *s = &submitters[0];
unsigned long done, calls, reap, cache_hit, cache_miss;
- int err, i;
+ int err, i, flags, fd;
struct rlimit rlim;
void *ret;
return 1;
}
+ flags = O_RDONLY;
+ if (!buffered)
+ flags |= O_DIRECT;
+
+ i = 1;
+ while (i < argc) {
+ struct file *f = &s->files[s->nr_files];
+
+ fd = open(argv[i], flags);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ f->fd = fd;
+ if (get_file_size(f)) {
+ printf("failed getting size of device/file\n");
+ return 1;
+ }
+ if (f->max_blocks <= 1) {
+ printf("Zero file/device size?\n");
+ return 1;
+ }
+ f->max_blocks--;
+
+ printf("Added file %s\n", argv[i]);
+ s->nr_files++;
+ i++;
+ }
+
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_MEMLOCK, &rlim) < 0) {
}
printf("polled=%d, fixedbufs=%d, buffered=%d", polled, fixedbufs, buffered);
printf(" QD=%d, sq_ring=%d, cq_ring=%d\n", DEPTH, *s->sq_ring.ring_entries, *s->cq_ring.ring_entries);
- strcpy(s->filename, argv[1]);
pthread_create(&s->thread, NULL, submitter_fn, s);