* [PATCH 1/3] io_uring: partially inline io_iopoll_getevents()
2020-07-07 13:36 [RFC 0/3] reduce CPU usage on exit for IOPOLL Pavel Begunkov
@ 2020-07-07 13:36 ` Pavel Begunkov
2020-07-07 13:36 ` [PATCH 2/3] io_uring: remove nr_events arg from iopoll_check() Pavel Begunkov
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2020-07-07 13:36 UTC (permalink / raw)
To: Jens Axboe, io-uring
io_iopoll_reap_events() doesn't care about returned valued of
io_iopoll_getevents() and does the same checks for list emptiness
and need_resched(). Just use io_do_iopoll().
io_sq_thread() doesn't check return value as well. It also passes min=0,
so there never be the second iteration inside io_poll_getevents().
Inline it there too.
Signed-off-by: Pavel Begunkov <[email protected]>
---
fs/io_uring.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 54756ae94bcd..db8dd2cdd2cb 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -2057,7 +2057,7 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
while (!list_empty(&ctx->poll_list)) {
unsigned int nr_events = 0;
- io_iopoll_getevents(ctx, &nr_events, 1);
+ io_do_iopoll(ctx, &nr_events, 1);
/*
* Ensure we allow local-to-the-cpu processing to take place,
@@ -6311,8 +6311,8 @@ static int io_sq_thread(void *data)
unsigned nr_events = 0;
mutex_lock(&ctx->uring_lock);
- if (!list_empty(&ctx->poll_list))
- io_iopoll_getevents(ctx, &nr_events, 0);
+ if (!list_empty(&ctx->poll_list) && !need_resched())
+ io_do_iopoll(ctx, &nr_events, 0);
else
timeout = jiffies + ctx->sq_thread_idle;
mutex_unlock(&ctx->uring_lock);
--
2.24.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] io_uring: remove nr_events arg from iopoll_check()
2020-07-07 13:36 [RFC 0/3] reduce CPU usage on exit for IOPOLL Pavel Begunkov
2020-07-07 13:36 ` [PATCH 1/3] io_uring: partially inline io_iopoll_getevents() Pavel Begunkov
@ 2020-07-07 13:36 ` Pavel Begunkov
2020-07-07 13:36 ` [PATCH 3/3] io_uring: don't burn CPU for iopoll on exit Pavel Begunkov
2020-07-07 19:00 ` [RFC 0/3] reduce CPU usage on exit for IOPOLL Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2020-07-07 13:36 UTC (permalink / raw)
To: Jens Axboe, io-uring
Nobody checks io_iopoll_check()'s output parameter @nr_events.
Remove the parameter and declare it further down the stack.
Signed-off-by: Pavel Begunkov <[email protected]>
---
fs/io_uring.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index db8dd2cdd2cb..9c3f9ccb850d 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -2073,9 +2073,9 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
mutex_unlock(&ctx->uring_lock);
}
-static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
- long min)
+static int io_iopoll_check(struct io_ring_ctx *ctx, long min)
{
+ unsigned int nr_events = 0;
int iters = 0, ret = 0;
/*
@@ -2109,11 +2109,11 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned *nr_events,
mutex_lock(&ctx->uring_lock);
}
- ret = io_iopoll_getevents(ctx, nr_events, min);
+ ret = io_iopoll_getevents(ctx, &nr_events, min);
if (ret <= 0)
break;
ret = 0;
- } while (min && !*nr_events && !need_resched());
+ } while (min && !nr_events && !need_resched());
mutex_unlock(&ctx->uring_lock);
return ret;
@@ -7963,8 +7963,6 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
goto out;
}
if (flags & IORING_ENTER_GETEVENTS) {
- unsigned nr_events = 0;
-
min_complete = min(min_complete, ctx->cq_entries);
/*
@@ -7975,7 +7973,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
*/
if (ctx->flags & IORING_SETUP_IOPOLL &&
!(ctx->flags & IORING_SETUP_SQPOLL)) {
- ret = io_iopoll_check(ctx, &nr_events, min_complete);
+ ret = io_iopoll_check(ctx, min_complete);
} else {
ret = io_cqring_wait(ctx, min_complete, sig, sigsz);
}
--
2.24.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] io_uring: don't burn CPU for iopoll on exit
2020-07-07 13:36 [RFC 0/3] reduce CPU usage on exit for IOPOLL Pavel Begunkov
2020-07-07 13:36 ` [PATCH 1/3] io_uring: partially inline io_iopoll_getevents() Pavel Begunkov
2020-07-07 13:36 ` [PATCH 2/3] io_uring: remove nr_events arg from iopoll_check() Pavel Begunkov
@ 2020-07-07 13:36 ` Pavel Begunkov
2020-07-07 19:00 ` [RFC 0/3] reduce CPU usage on exit for IOPOLL Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2020-07-07 13:36 UTC (permalink / raw)
To: Jens Axboe, io-uring
First of all don't spin in io_ring_ctx_wait_and_kill() on iopoll.
Requests won't complete faster because of that, but only lengthen
io_uring_release().
The same goes for offloaded cleanup in io_ring_exit_work() -- it
already has waiting loop, don't do blocking active spinning.
For that, pass min=0 into io_iopoll_[try_]reap_events(), so it won't
actively spin. Leave the function if io_do_iopoll() there can't
complete a request to sleep in io_ring_exit_work().
Signed-off-by: Pavel Begunkov <[email protected]>
---
fs/io_uring.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 9c3f9ccb850d..bcf6bf799a61 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -2048,7 +2048,7 @@ static int io_iopoll_getevents(struct io_ring_ctx *ctx, unsigned int *nr_events,
* We can't just wait for polled events to come to us, we have to actively
* find and complete them.
*/
-static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
+static void io_iopoll_try_reap_events(struct io_ring_ctx *ctx)
{
if (!(ctx->flags & IORING_SETUP_IOPOLL))
return;
@@ -2057,8 +2057,11 @@ static void io_iopoll_reap_events(struct io_ring_ctx *ctx)
while (!list_empty(&ctx->poll_list)) {
unsigned int nr_events = 0;
- io_do_iopoll(ctx, &nr_events, 1);
+ io_do_iopoll(ctx, &nr_events, 0);
+ /* let it sleep and repeat later if can't complete a request */
+ if (nr_events == 0)
+ break;
/*
* Ensure we allow local-to-the-cpu processing to take place,
* in this case we need to ensure that we reap all events.
@@ -7634,7 +7637,6 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
ctx->sqo_mm = NULL;
}
- io_iopoll_reap_events(ctx);
io_sqe_buffer_unregister(ctx);
io_sqe_files_unregister(ctx);
io_eventfd_unregister(ctx);
@@ -7701,11 +7703,8 @@ static int io_remove_personalities(int id, void *p, void *data)
static void io_ring_exit_work(struct work_struct *work)
{
- struct io_ring_ctx *ctx;
-
- ctx = container_of(work, struct io_ring_ctx, exit_work);
- if (ctx->rings)
- io_cqring_overflow_flush(ctx, true);
+ struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx,
+ exit_work);
/*
* If we're doing polled IO and end up having requests being
@@ -7713,11 +7712,11 @@ static void io_ring_exit_work(struct work_struct *work)
* we're waiting for refs to drop. We need to reap these manually,
* as nobody else will be looking for them.
*/
- while (!wait_for_completion_timeout(&ctx->ref_comp, HZ/20)) {
- io_iopoll_reap_events(ctx);
+ do {
if (ctx->rings)
io_cqring_overflow_flush(ctx, true);
- }
+ io_iopoll_try_reap_events(ctx);
+ } while (!wait_for_completion_timeout(&ctx->ref_comp, HZ/20));
io_ring_ctx_free(ctx);
}
@@ -7733,10 +7732,10 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
if (ctx->io_wq)
io_wq_cancel_all(ctx->io_wq);
- io_iopoll_reap_events(ctx);
/* if we failed setting up the ctx, we might not have any rings */
if (ctx->rings)
io_cqring_overflow_flush(ctx, true);
+ io_iopoll_try_reap_events(ctx);
idr_for_each(&ctx->personality_idr, io_remove_personalities, ctx);
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
queue_work(system_wq, &ctx->exit_work);
--
2.24.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC 0/3] reduce CPU usage on exit for IOPOLL
2020-07-07 13:36 [RFC 0/3] reduce CPU usage on exit for IOPOLL Pavel Begunkov
` (2 preceding siblings ...)
2020-07-07 13:36 ` [PATCH 3/3] io_uring: don't burn CPU for iopoll on exit Pavel Begunkov
@ 2020-07-07 19:00 ` Jens Axboe
3 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2020-07-07 19:00 UTC (permalink / raw)
To: Pavel Begunkov, io-uring
On 7/7/20 7:36 AM, Pavel Begunkov wrote:
> [1,2] are small preps for the future that should change
> nothing functionally.
>
> [3] helps to reduce CPU usage on exit. We don't care about latency
> and CQEs when io_uring is going away, so checking it every HZ/20
> should be enough
> Please, check the assumptions, because I hope that nobody expects
> ->iopoll() to do real work but not just completing.
I think it's fine to do it in 1/20th second intervals, if you exit
with pending poll requests.
Hence it looks good to me, I've applied it.
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread