Skip to content

Commit 02c1386

Browse files
author
Ming Lei
committed
io_uring: limit local tw done
JIRA: https://issues.redhat.com/browse/RHEL-106845 commit f46b9cd Author: David Wei <dw@davidwei.uk> Date: Wed Nov 20 14:14:52 2024 -0800 io_uring: limit local tw done Instead of eagerly running all available local tw, limit the amount of local tw done to the max of IO_LOCAL_TW_DEFAULT_MAX (20) or wait_nr. The value of 20 is chosen as a reasonable heuristic to allow enough work batching but also keep latency down. Add a retry_llist that maintains a list of local tw that couldn't be done in time. No synchronisation is needed since it is only modified within the task context. Signed-off-by: David Wei <dw@davidwei.uk> Link: https://lore.kernel.org/r/20241120221452.3762588-3-dw@davidwei.uk Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Ming Lei <ming.lei@redhat.com>
1 parent 750750e commit 02c1386

File tree

3 files changed

+34
-12
lines changed

3 files changed

+34
-12
lines changed

include/linux/io_uring_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ struct io_ring_ctx {
335335
*/
336336
struct {
337337
struct llist_head work_llist;
338+
struct llist_head retry_llist;
338339
unsigned long check_cq;
339340
atomic_t cq_wait_nr;
340341
atomic_t cq_timeouts;

io_uring/io_uring.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122

123123
#define IO_COMPL_BATCH 32
124124
#define IO_REQ_ALLOC_BATCH 8
125+
#define IO_LOCAL_TW_DEFAULT_MAX 20
125126

126127
struct io_defer_entry {
127128
struct list_head list;
@@ -1264,6 +1265,8 @@ static void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx)
12641265
struct llist_node *node = llist_del_all(&ctx->work_llist);
12651266

12661267
__io_fallback_tw(node, false);
1268+
node = llist_del_all(&ctx->retry_llist);
1269+
__io_fallback_tw(node, false);
12671270
}
12681271

12691272
static bool io_run_local_work_continue(struct io_ring_ctx *ctx, int events,
@@ -1278,37 +1281,55 @@ static bool io_run_local_work_continue(struct io_ring_ctx *ctx, int events,
12781281
return false;
12791282
}
12801283

1284+
static int __io_run_local_work_loop(struct llist_node **node,
1285+
struct io_tw_state *ts,
1286+
int events)
1287+
{
1288+
while (*node) {
1289+
struct llist_node *next = (*node)->next;
1290+
struct io_kiocb *req = container_of(*node, struct io_kiocb,
1291+
io_task_work.node);
1292+
INDIRECT_CALL_2(req->io_task_work.func,
1293+
io_poll_task_func, io_req_rw_complete,
1294+
req, ts);
1295+
*node = next;
1296+
if (--events <= 0)
1297+
break;
1298+
}
1299+
1300+
return events;
1301+
}
1302+
12811303
static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts,
12821304
int min_events)
12831305
{
12841306
struct llist_node *node;
12851307
unsigned int loops = 0;
1286-
int ret = 0;
1308+
int ret, limit;
12871309

12881310
if (WARN_ON_ONCE(ctx->submitter_task != current))
12891311
return -EEXIST;
12901312
if (ctx->flags & IORING_SETUP_TASKRUN_FLAG)
12911313
atomic_andnot(IORING_SQ_TASKRUN, &ctx->rings->sq_flags);
1314+
limit = max(IO_LOCAL_TW_DEFAULT_MAX, min_events);
12921315
again:
1316+
ret = __io_run_local_work_loop(&ctx->retry_llist.first, ts, limit);
1317+
if (ctx->retry_llist.first)
1318+
goto retry_done;
1319+
12931320
/*
12941321
* llists are in reverse order, flip it back the right way before
12951322
* running the pending items.
12961323
*/
12971324
node = llist_reverse_order(llist_del_all(&ctx->work_llist));
1298-
while (node) {
1299-
struct llist_node *next = node->next;
1300-
struct io_kiocb *req = container_of(node, struct io_kiocb,
1301-
io_task_work.node);
1302-
INDIRECT_CALL_2(req->io_task_work.func,
1303-
io_poll_task_func, io_req_rw_complete,
1304-
req, ts);
1305-
ret++;
1306-
node = next;
1307-
}
1325+
ret = __io_run_local_work_loop(&node, ts, ret);
1326+
ctx->retry_llist.first = node;
13081327
loops++;
13091328

1329+
ret = limit - ret;
13101330
if (io_run_local_work_continue(ctx, ret, min_events))
13111331
goto again;
1332+
retry_done:
13121333
io_submit_flush_completions(ctx);
13131334
if (io_run_local_work_continue(ctx, ret, min_events))
13141335
goto again;

io_uring/io_uring.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ static inline int io_run_task_work(void)
349349

350350
static inline bool io_local_work_pending(struct io_ring_ctx *ctx)
351351
{
352-
return !llist_empty(&ctx->work_llist);
352+
return !llist_empty(&ctx->work_llist) || !llist_empty(&ctx->retry_llist);
353353
}
354354

355355
static inline bool io_task_work_pending(struct io_ring_ctx *ctx)

0 commit comments

Comments
 (0)