From 35c7c72601cee9692846de13117411d80b3d13f6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 27 Nov 2024 20:10:19 -0500 Subject: ioq: Add an ioq_nop() operation for benchmarking --- src/bftw.c | 4 ++++ src/ioq.c | 28 ++++++++++++++++++++++++++++ src/ioq.h | 30 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) (limited to 'src') diff --git a/src/bftw.c b/src/bftw.c index 61193d5..5725825 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -1051,6 +1051,10 @@ static int bftw_ioq_pop(struct bftw_state *state, bool block) { bftw_queue_attach(&state->fileq, file, true); break; + + default: + bfs_bug("Unexpected ioq op %d", (int)op); + break; } ioq_free(ioq, ent); diff --git a/src/ioq.c b/src/ioq.c index 1c5524e..5668a83 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -136,6 +136,7 @@ #include #include #include +#include #if BFS_WITH_LIBURING # include @@ -532,6 +533,14 @@ static bool ioq_check_cancel(struct ioq *ioq, struct ioq_ent *ent) { /** Dispatch a single request synchronously. */ static void ioq_dispatch_sync(struct ioq *ioq, struct ioq_ent *ent) { switch (ent->op) { + case IOQ_NOP: + if (ent->nop.type == IOQ_NOP_HEAVY) { + // A fast, no-op syscall + getpid(); + } + ent->result = 0; + return; + case IOQ_CLOSE: ent->result = try(xclose(ent->close.fd)); return; @@ -587,6 +596,13 @@ static struct io_uring_sqe *ioq_dispatch_async(struct ioq_ring_state *state, str struct io_uring_sqe *sqe = NULL; switch (ent->op) { + case IOQ_NOP: + if (ent->nop.type == IOQ_NOP_HEAVY) { + sqe = io_uring_get_sqe(ring); + io_uring_prep_nop(sqe); + } + return sqe; + case IOQ_CLOSE: if (ops & IOQ_RING_CLOSE) { sqe = io_uring_get_sqe(ring); @@ -1010,6 +1026,18 @@ static struct ioq_ent *ioq_request(struct ioq *ioq, enum ioq_op op, void *ptr) { return ent; } +int ioq_nop(struct ioq *ioq, enum ioq_nop_type type, void *ptr) { + struct ioq_ent *ent = ioq_request(ioq, IOQ_NOP, ptr); + if (!ent) { + return -1; + } + + ent->nop.type = type; + + ioqq_push(ioq->pending, ent); + return 0; +} + int ioq_close(struct ioq *ioq, int fd, void *ptr) { struct ioq_ent *ent = ioq_request(ioq, IOQ_CLOSE, ptr); if (!ent) { diff --git a/src/ioq.h b/src/ioq.h index cb14be4..fce1d7f 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -22,6 +22,8 @@ struct ioq; * I/O queue operations. */ enum ioq_op { + /** ioq_nop(). */ + IOQ_NOP, /** ioq_close(). */ IOQ_CLOSE, /** ioq_opendir(). */ @@ -32,6 +34,16 @@ enum ioq_op { IOQ_STAT, }; +/** + * ioq_nop() types. + */ +enum ioq_nop_type { + /** A lightweight nop that avoids syscalls. */ + IOQ_NOP_LIGHT, + /** A heavyweight nop that involves a syscall. */ + IOQ_NOP_HEAVY, +}; + /** * The I/O queue implementation needs two tag bits in each pointer to a struct * ioq_ent, so we need to ensure at least 4-byte alignment. The natural @@ -54,6 +66,10 @@ struct ioq_ent { /** Operation-specific arguments. */ union { + /** ioq_nop() args. */ + struct ioq_nop { + enum ioq_nop_type type; + } nop; /** ioq_close() args. */ struct ioq_close { int fd; @@ -97,6 +113,20 @@ struct ioq *ioq_create(size_t depth, size_t nthreads); */ size_t ioq_capacity(const struct ioq *ioq); +/** + * A no-op, for benchmarking. + * + * @ioq + * The I/O queue. + * @type + * The type of operation to perform. + * @ptr + * An arbitrary pointer to associate with the request. + * @return + * 0 on success, or -1 on failure. + */ +int ioq_nop(struct ioq *ioq, enum ioq_nop_type type, void *ptr); + /** * Asynchronous close(). * -- cgit v1.2.3