* [Qemu-devel] [PATCH 0/3] aio-posix: polling mode bug fixes
@ 2018-09-12 17:10 Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt Paolo Bonzini
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Paolo Bonzini @ 2018-09-12 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, famz, kwolf, stefanha
Patch 1 fixes a too-strict assertion that could fire when aio_poll
is called in parallel with aio_set_fd_handler.
Patch 2 and 3 reinstate the performance benefits of polling, which were
essentially disabled by commit 70232b5253 ("aio-posix: Don't count
ctx->notifier as progress when polling", 2018-08-15).
Please review carefully! :)
Thanks,
Paolo
Paolo Bonzini (3):
aio-posix: fix concurrent access to poll_disable_cnt
aio-posix: compute timeout before polling
aio-posix: do skip system call if ctx->notifier polling succeeds
util/aio-posix.c | 88 +++++++++++++++++++++++++++--------------------
util/trace-events | 4 +--
2 files changed, 53 insertions(+), 39 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
2018-09-12 17:10 [Qemu-devel] [PATCH 0/3] aio-posix: polling mode bug fixes Paolo Bonzini
@ 2018-09-12 17:10 ` Paolo Bonzini
2018-09-13 6:56 ` Fam Zheng
2018-09-12 17:10 ` [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds Paolo Bonzini
2 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2018-09-12 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, famz, kwolf, stefanha
It is valid for an aio_set_fd_handler to happen concurrently with
aio_poll. In that case, poll_disable_cnt can change under the heels
of aio_poll, and the assertion on poll_disable_cnt can fail in
run_poll_handlers.
Therefore, this patch simply checks the counter on every polling
iteration. There are no particular needs for ordering, since the
polling loop is terminated anyway by aio_notify at the end of
aio_set_fd_handler.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
util/aio-posix.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 131ba6b4a8..5c29380575 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -211,6 +211,7 @@ void aio_set_fd_handler(AioContext *ctx,
AioHandler *node;
bool is_new = false;
bool deleted = false;
+ int poll_disable_change;
qemu_lockcnt_lock(&ctx->list_lock);
@@ -244,11 +245,9 @@ void aio_set_fd_handler(AioContext *ctx,
QLIST_REMOVE(node, node);
deleted = true;
}
-
- if (!node->io_poll) {
- ctx->poll_disable_cnt--;
- }
+ poll_disable_change = -!node->io_poll;
} else {
+ poll_disable_change = !io_poll - (node && !node->io_poll);
if (node == NULL) {
/* Alloc and insert if it's not already there */
node = g_new0(AioHandler, 1);
@@ -257,10 +256,6 @@ void aio_set_fd_handler(AioContext *ctx,
g_source_add_poll(&ctx->source, &node->pfd);
is_new = true;
-
- ctx->poll_disable_cnt += !io_poll;
- } else {
- ctx->poll_disable_cnt += !io_poll - !node->io_poll;
}
/* Update handler with latest information */
@@ -274,6 +269,15 @@ void aio_set_fd_handler(AioContext *ctx,
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
}
+ /* No need to order poll_disable_cnt writes against other updates;
+ * the counter is only used to avoid wasting time and latency on
+ * iterated polling when the system call will be ultimately necessary.
+ * Changing handlers is a rare event, and a little wasted polling until
+ * the aio_notify below is not an issue.
+ */
+ atomic_set(&ctx->poll_disable_cnt,
+ atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
+
aio_epoll_update(ctx, node, is_new);
qemu_lockcnt_unlock(&ctx->list_lock);
aio_notify(ctx);
@@ -525,7 +529,6 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
assert(ctx->notify_me);
assert(qemu_lockcnt_count(&ctx->list_lock) > 0);
- assert(ctx->poll_disable_cnt == 0);
trace_run_poll_handlers_begin(ctx, max_ns);
@@ -533,7 +536,8 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
do {
progress = run_poll_handlers_once(ctx);
- } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);
+ } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time
+ && !atomic_read(&ctx->poll_disable_cnt));
trace_run_poll_handlers_end(ctx, progress);
@@ -552,7 +556,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
*/
static bool try_poll_mode(AioContext *ctx, bool blocking)
{
- if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) {
+ if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
/* See qemu_soonest_timeout() uint64_t hack */
int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
(uint64_t)ctx->poll_ns);
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling
2018-09-12 17:10 [Qemu-devel] [PATCH 0/3] aio-posix: polling mode bug fixes Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt Paolo Bonzini
@ 2018-09-12 17:10 ` Paolo Bonzini
2018-09-13 7:16 ` Fam Zheng
2018-09-12 17:10 ` [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds Paolo Bonzini
2 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2018-09-12 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, famz, kwolf, stefanha
This is a preparation for the next patch, and also a very small
optimization. Compute the timeout only once, before invoking
try_poll_mode, and adjust it in run_poll_handlers. The adjustment
is the polling time when polling fails, or zero (non-blocking) if
polling succeeds.
Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
util/aio-posix.c | 59 +++++++++++++++++++++++++++--------------------
util/trace-events | 4 ++--
2 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 5c29380575..21d8987179 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -490,7 +490,7 @@ static void add_pollfd(AioHandler *node)
npfd++;
}
-static bool run_poll_handlers_once(AioContext *ctx)
+static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout)
{
bool progress = false;
AioHandler *node;
@@ -500,6 +500,7 @@ static bool run_poll_handlers_once(AioContext *ctx)
aio_node_check(ctx, node->is_external) &&
node->io_poll(node->opaque) &&
node->opaque != &ctx->notifier) {
+ *timeout = 0;
progress = true;
}
@@ -522,31 +523,38 @@ static bool run_poll_handlers_once(AioContext *ctx)
*
* Returns: true if progress was made, false otherwise
*/
-static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
+static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
{
bool progress;
- int64_t end_time;
+ int64_t start_time, elapsed_time;
assert(ctx->notify_me);
assert(qemu_lockcnt_count(&ctx->list_lock) > 0);
- trace_run_poll_handlers_begin(ctx, max_ns);
-
- end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns;
+ trace_run_poll_handlers_begin(ctx, max_ns, *timeout);
+ start_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
do {
- progress = run_poll_handlers_once(ctx);
- } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time
+ progress = run_poll_handlers_once(ctx, timeout);
+ elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time;
+ } while (!progress && elapsed_time < max_ns
&& !atomic_read(&ctx->poll_disable_cnt));
- trace_run_poll_handlers_end(ctx, progress);
+ /* If time has passed with no successful polling, adjust *timeout to
+ * keep the same ending time.
+ */
+ if (*timeout != -1) {
+ *timeout -= MIN(*timeout, elapsed_time);
+ }
+ trace_run_poll_handlers_end(ctx, progress, *timeout);
return progress;
}
/* try_poll_mode:
* @ctx: the AioContext
- * @blocking: busy polling is only attempted when blocking is true
+ * @timeout: timeout for blocking wait, computed by the caller and updated if
+ * polling succeeds.
*
* ctx->notify_me must be non-zero so this function can detect aio_notify().
*
@@ -554,19 +562,16 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
*
* Returns: true if progress was made, false otherwise
*/
-static bool try_poll_mode(AioContext *ctx, bool blocking)
+static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
{
- if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
- /* See qemu_soonest_timeout() uint64_t hack */
- int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
- (uint64_t)ctx->poll_ns);
+ /* See qemu_soonest_timeout() uint64_t hack */
+ int64_t max_ns = MIN((uint64_t)*timeout, (uint64_t)ctx->poll_ns);
- if (max_ns) {
- poll_set_started(ctx, true);
+ if (max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
+ poll_set_started(ctx, true);
- if (run_poll_handlers(ctx, max_ns)) {
- return true;
- }
+ if (run_poll_handlers(ctx, max_ns, timeout)) {
+ return true;
}
}
@@ -575,7 +580,7 @@ static bool try_poll_mode(AioContext *ctx, bool blocking)
/* Even if we don't run busy polling, try polling once in case it can make
* progress and the caller will be able to avoid ppoll(2)/epoll_wait(2).
*/
- return run_poll_handlers_once(ctx);
+ return run_poll_handlers_once(ctx, timeout);
}
bool aio_poll(AioContext *ctx, bool blocking)
@@ -605,8 +610,14 @@ bool aio_poll(AioContext *ctx, bool blocking)
start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
}
- progress = try_poll_mode(ctx, blocking);
- if (!progress) {
+ timeout = blocking ? aio_compute_timeout(ctx) : 0;
+ progress = try_poll_mode(ctx, &timeout);
+ assert(!(timeout && progress));
+
+ /* If polling is allowed, non-blocking aio_poll does not need the
+ * system call---a single round of run_poll_handlers_once suffices.
+ */
+ if (timeout || atomic_read(&ctx->poll_disable_cnt)) {
assert(npfd == 0);
/* fill pollfds */
@@ -620,8 +631,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
}
}
- timeout = blocking ? aio_compute_timeout(ctx) : 0;
-
/* wait until next event */
if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) {
AioHandler epoll_handler;
diff --git a/util/trace-events b/util/trace-events
index 4822434c89..79569b7fdf 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -1,8 +1,8 @@
# See docs/devel/tracing.txt for syntax documentation.
# util/aio-posix.c
-run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64
-run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d"
+run_poll_handlers_begin(void *ctx, int64_t max_ns, int64_t timeout) "ctx %p max_ns %"PRId64 " timeout %"PRId64
+run_poll_handlers_end(void *ctx, bool progress, int64_t timeout) "ctx %p progress %d new timeout %"PRId64
poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds
2018-09-12 17:10 [Qemu-devel] [PATCH 0/3] aio-posix: polling mode bug fixes Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling Paolo Bonzini
@ 2018-09-12 17:10 ` Paolo Bonzini
2018-09-13 7:19 ` Fam Zheng
2 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2018-09-12 17:10 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, famz, kwolf, stefanha
Commit 70232b5253 ("aio-posix: Don't count ctx->notifier as progress when
2018-08-15), by not reporting progress, causes aio_poll to execute the
system call when polling succeeds because of ctx->notifier. This introduces
latency before the call to aio_bh_poll() and negates the advantages of
polling, unfortunately.
The fix builds on the previous patch, separating the effect of polling on
the timeout from the progress reported to aio_poll(). ctx->notifier
does zero the timeout, causing the caller to skip the system call,
but it does not report progress, so that the bug fix of commit 70232b5253
still stands.
Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
util/aio-posix.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 21d8987179..efa79b9e62 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -498,10 +498,11 @@ static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout)
QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
if (!node->deleted && node->io_poll &&
aio_node_check(ctx, node->is_external) &&
- node->io_poll(node->opaque) &&
- node->opaque != &ctx->notifier) {
+ node->io_poll(node->opaque)) {
*timeout = 0;
- progress = true;
+ if (node->opaque != &ctx->notifier) {
+ progress = true;
+ }
}
/* Caller handles freeing deleted nodes. Don't do it here. */
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
2018-09-12 17:10 ` [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt Paolo Bonzini
@ 2018-09-13 6:56 ` Fam Zheng
2018-09-13 8:29 ` [Qemu-devel] [Qemu-block] " Paolo Bonzini
0 siblings, 1 reply; 9+ messages in thread
From: Fam Zheng @ 2018-09-13 6:56 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel, qemu-block, kwolf, stefanha
On Wed, 09/12 19:10, Paolo Bonzini wrote:
> It is valid for an aio_set_fd_handler to happen concurrently with
> aio_poll. In that case, poll_disable_cnt can change under the heels
> of aio_poll, and the assertion on poll_disable_cnt can fail in
> run_poll_handlers.
>
> Therefore, this patch simply checks the counter on every polling
> iteration. There are no particular needs for ordering, since the
> polling loop is terminated anyway by aio_notify at the end of
> aio_set_fd_handler.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> util/aio-posix.c | 26 +++++++++++++++-----------
> 1 file changed, 15 insertions(+), 11 deletions(-)
>
> diff --git a/util/aio-posix.c b/util/aio-posix.c
> index 131ba6b4a8..5c29380575 100644
> --- a/util/aio-posix.c
> +++ b/util/aio-posix.c
> @@ -211,6 +211,7 @@ void aio_set_fd_handler(AioContext *ctx,
> AioHandler *node;
> bool is_new = false;
> bool deleted = false;
> + int poll_disable_change;
>
> qemu_lockcnt_lock(&ctx->list_lock);
>
> @@ -244,11 +245,9 @@ void aio_set_fd_handler(AioContext *ctx,
> QLIST_REMOVE(node, node);
> deleted = true;
> }
> -
> - if (!node->io_poll) {
> - ctx->poll_disable_cnt--;
> - }
> + poll_disable_change = -!node->io_poll;
> } else {
> + poll_disable_change = !io_poll - (node && !node->io_poll);
> if (node == NULL) {
> /* Alloc and insert if it's not already there */
> node = g_new0(AioHandler, 1);
> @@ -257,10 +256,6 @@ void aio_set_fd_handler(AioContext *ctx,
>
> g_source_add_poll(&ctx->source, &node->pfd);
> is_new = true;
> -
> - ctx->poll_disable_cnt += !io_poll;
> - } else {
> - ctx->poll_disable_cnt += !io_poll - !node->io_poll;
> }
>
> /* Update handler with latest information */
> @@ -274,6 +269,15 @@ void aio_set_fd_handler(AioContext *ctx,
> node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
> }
>
> + /* No need to order poll_disable_cnt writes against other updates;
> + * the counter is only used to avoid wasting time and latency on
> + * iterated polling when the system call will be ultimately necessary.
> + * Changing handlers is a rare event, and a little wasted polling until
> + * the aio_notify below is not an issue.
> + */
> + atomic_set(&ctx->poll_disable_cnt,
> + atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
Why not atomic_add?
> +
> aio_epoll_update(ctx, node, is_new);
> qemu_lockcnt_unlock(&ctx->list_lock);
> aio_notify(ctx);
> @@ -525,7 +529,6 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
>
> assert(ctx->notify_me);
> assert(qemu_lockcnt_count(&ctx->list_lock) > 0);
> - assert(ctx->poll_disable_cnt == 0);
>
> trace_run_poll_handlers_begin(ctx, max_ns);
>
> @@ -533,7 +536,8 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
>
> do {
> progress = run_poll_handlers_once(ctx);
> - } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);
> + } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time
> + && !atomic_read(&ctx->poll_disable_cnt));
>
> trace_run_poll_handlers_end(ctx, progress);
>
> @@ -552,7 +556,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
> */
> static bool try_poll_mode(AioContext *ctx, bool blocking)
> {
> - if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) {
> + if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
> /* See qemu_soonest_timeout() uint64_t hack */
> int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
> (uint64_t)ctx->poll_ns);
> --
> 2.17.1
>
>
Reviewed-by: Fam Zheng <famz@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling
2018-09-12 17:10 ` [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling Paolo Bonzini
@ 2018-09-13 7:16 ` Fam Zheng
0 siblings, 0 replies; 9+ messages in thread
From: Fam Zheng @ 2018-09-13 7:16 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel, qemu-block, kwolf, stefanha
On Wed, 09/12 19:10, Paolo Bonzini wrote:
> This is a preparation for the next patch, and also a very small
> optimization. Compute the timeout only once, before invoking
> try_poll_mode, and adjust it in run_poll_handlers. The adjustment
> is the polling time when polling fails, or zero (non-blocking) if
> polling succeeds.
>
> Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> util/aio-posix.c | 59 +++++++++++++++++++++++++++--------------------
> util/trace-events | 4 ++--
> 2 files changed, 36 insertions(+), 27 deletions(-)
>
> diff --git a/util/aio-posix.c b/util/aio-posix.c
> index 5c29380575..21d8987179 100644
> --- a/util/aio-posix.c
> +++ b/util/aio-posix.c
> @@ -490,7 +490,7 @@ static void add_pollfd(AioHandler *node)
> npfd++;
> }
>
> -static bool run_poll_handlers_once(AioContext *ctx)
> +static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout)
> {
> bool progress = false;
> AioHandler *node;
> @@ -500,6 +500,7 @@ static bool run_poll_handlers_once(AioContext *ctx)
> aio_node_check(ctx, node->is_external) &&
> node->io_poll(node->opaque) &&
> node->opaque != &ctx->notifier) {
> + *timeout = 0;
> progress = true;
> }
>
> @@ -522,31 +523,38 @@ static bool run_poll_handlers_once(AioContext *ctx)
> *
> * Returns: true if progress was made, false otherwise
> */
> -static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
> +static bool run_poll_handlers(AioContext *ctx, int64_t max_ns, int64_t *timeout)
> {
> bool progress;
> - int64_t end_time;
> + int64_t start_time, elapsed_time;
>
> assert(ctx->notify_me);
> assert(qemu_lockcnt_count(&ctx->list_lock) > 0);
>
> - trace_run_poll_handlers_begin(ctx, max_ns);
> -
> - end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns;
> + trace_run_poll_handlers_begin(ctx, max_ns, *timeout);
>
> + start_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
> do {
> - progress = run_poll_handlers_once(ctx);
> - } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time
> + progress = run_poll_handlers_once(ctx, timeout);
> + elapsed_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start_time;
> + } while (!progress && elapsed_time < max_ns
> && !atomic_read(&ctx->poll_disable_cnt));
>
> - trace_run_poll_handlers_end(ctx, progress);
> + /* If time has passed with no successful polling, adjust *timeout to
> + * keep the same ending time.
> + */
> + if (*timeout != -1) {
> + *timeout -= MIN(*timeout, elapsed_time);
> + }
>
> + trace_run_poll_handlers_end(ctx, progress, *timeout);
> return progress;
> }
>
> /* try_poll_mode:
> * @ctx: the AioContext
> - * @blocking: busy polling is only attempted when blocking is true
> + * @timeout: timeout for blocking wait, computed by the caller and updated if
> + * polling succeeds.
> *
> * ctx->notify_me must be non-zero so this function can detect aio_notify().
> *
> @@ -554,19 +562,16 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
> *
> * Returns: true if progress was made, false otherwise
> */
> -static bool try_poll_mode(AioContext *ctx, bool blocking)
> +static bool try_poll_mode(AioContext *ctx, int64_t *timeout)
> {
> - if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
> - /* See qemu_soonest_timeout() uint64_t hack */
> - int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
> - (uint64_t)ctx->poll_ns);
> + /* See qemu_soonest_timeout() uint64_t hack */
> + int64_t max_ns = MIN((uint64_t)*timeout, (uint64_t)ctx->poll_ns);
>
> - if (max_ns) {
> - poll_set_started(ctx, true);
> + if (max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
> + poll_set_started(ctx, true);
>
> - if (run_poll_handlers(ctx, max_ns)) {
> - return true;
> - }
> + if (run_poll_handlers(ctx, max_ns, timeout)) {
> + return true;
> }
> }
>
> @@ -575,7 +580,7 @@ static bool try_poll_mode(AioContext *ctx, bool blocking)
> /* Even if we don't run busy polling, try polling once in case it can make
> * progress and the caller will be able to avoid ppoll(2)/epoll_wait(2).
> */
> - return run_poll_handlers_once(ctx);
> + return run_poll_handlers_once(ctx, timeout);
> }
>
> bool aio_poll(AioContext *ctx, bool blocking)
> @@ -605,8 +610,14 @@ bool aio_poll(AioContext *ctx, bool blocking)
> start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
> }
>
> - progress = try_poll_mode(ctx, blocking);
> - if (!progress) {
> + timeout = blocking ? aio_compute_timeout(ctx) : 0;
> + progress = try_poll_mode(ctx, &timeout);
> + assert(!(timeout && progress));
> +
> + /* If polling is allowed, non-blocking aio_poll does not need the
> + * system call---a single round of run_poll_handlers_once suffices.
> + */
> + if (timeout || atomic_read(&ctx->poll_disable_cnt)) {
> assert(npfd == 0);
>
> /* fill pollfds */
> @@ -620,8 +631,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
> }
> }
>
> - timeout = blocking ? aio_compute_timeout(ctx) : 0;
> -
> /* wait until next event */
> if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) {
> AioHandler epoll_handler;
> diff --git a/util/trace-events b/util/trace-events
> index 4822434c89..79569b7fdf 100644
> --- a/util/trace-events
> +++ b/util/trace-events
> @@ -1,8 +1,8 @@
> # See docs/devel/tracing.txt for syntax documentation.
>
> # util/aio-posix.c
> -run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64
> -run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d"
> +run_poll_handlers_begin(void *ctx, int64_t max_ns, int64_t timeout) "ctx %p max_ns %"PRId64 " timeout %"PRId64
> +run_poll_handlers_end(void *ctx, bool progress, int64_t timeout) "ctx %p progress %d new timeout %"PRId64
> poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
> poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
>
> --
> 2.17.1
>
>
Reviewed-by: Fam Zheng <famz@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds
2018-09-12 17:10 ` [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds Paolo Bonzini
@ 2018-09-13 7:19 ` Fam Zheng
0 siblings, 0 replies; 9+ messages in thread
From: Fam Zheng @ 2018-09-13 7:19 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel, qemu-block, kwolf, stefanha
On Wed, 09/12 19:10, Paolo Bonzini wrote:
> Commit 70232b5253 ("aio-posix: Don't count ctx->notifier as progress when
> 2018-08-15), by not reporting progress, causes aio_poll to execute the
> system call when polling succeeds because of ctx->notifier. This introduces
> latency before the call to aio_bh_poll() and negates the advantages of
> polling, unfortunately.
>
> The fix builds on the previous patch, separating the effect of polling on
> the timeout from the progress reported to aio_poll(). ctx->notifier
> does zero the timeout, causing the caller to skip the system call,
> but it does not report progress, so that the bug fix of commit 70232b5253
> still stands.
>
> Fixes: 70232b5253a3c4e03ed1ac47ef9246a8ac66c6fa
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> util/aio-posix.c | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/util/aio-posix.c b/util/aio-posix.c
> index 21d8987179..efa79b9e62 100644
> --- a/util/aio-posix.c
> +++ b/util/aio-posix.c
> @@ -498,10 +498,11 @@ static bool run_poll_handlers_once(AioContext *ctx, int64_t *timeout)
> QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {
> if (!node->deleted && node->io_poll &&
> aio_node_check(ctx, node->is_external) &&
> - node->io_poll(node->opaque) &&
> - node->opaque != &ctx->notifier) {
> + node->io_poll(node->opaque)) {
> *timeout = 0;
> - progress = true;
> + if (node->opaque != &ctx->notifier) {
> + progress = true;
> + }
> }
>
> /* Caller handles freeing deleted nodes. Don't do it here. */
> --
> 2.17.1
>
Reviewed-by: Fam Zheng <famz@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [Qemu-block] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
2018-09-13 6:56 ` Fam Zheng
@ 2018-09-13 8:29 ` Paolo Bonzini
2018-09-13 8:34 ` Fam Zheng
0 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2018-09-13 8:29 UTC (permalink / raw)
To: Fam Zheng; +Cc: kwolf, stefanha, qemu-devel, qemu-block
On 13/09/2018 08:56, Fam Zheng wrote:
>> + /* No need to order poll_disable_cnt writes against other updates;
>> + * the counter is only used to avoid wasting time and latency on
>> + * iterated polling when the system call will be ultimately necessary.
>> + * Changing handlers is a rare event, and a little wasted polling until
>> + * the aio_notify below is not an issue.
>> + */
>> + atomic_set(&ctx->poll_disable_cnt,
>> + atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
>
> Why not atomic_add?
This is not lockless, it's protected by list_lock, so there's no race
condition involved. I'm just mimicking what is done for other similar
cases, for example involving seqlocks.
The alternative would be to add a full set of
atomic_{add,sub,...}_relaxed atomics.
Paolo
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [Qemu-block] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
2018-09-13 8:29 ` [Qemu-devel] [Qemu-block] " Paolo Bonzini
@ 2018-09-13 8:34 ` Fam Zheng
0 siblings, 0 replies; 9+ messages in thread
From: Fam Zheng @ 2018-09-13 8:34 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kwolf, stefanha, qemu-devel, qemu-block
On Thu, 09/13 10:29, Paolo Bonzini wrote:
> On 13/09/2018 08:56, Fam Zheng wrote:
> >> + /* No need to order poll_disable_cnt writes against other updates;
> >> + * the counter is only used to avoid wasting time and latency on
> >> + * iterated polling when the system call will be ultimately necessary.
> >> + * Changing handlers is a rare event, and a little wasted polling until
> >> + * the aio_notify below is not an issue.
> >> + */
> >> + atomic_set(&ctx->poll_disable_cnt,
> >> + atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
> >
> > Why not atomic_add?
>
> This is not lockless, it's protected by list_lock, so there's no race
> condition involved. I'm just mimicking what is done for other similar
> cases, for example involving seqlocks.
Yeah, no doubt about the correctness. Just curious about the preference since
atomic_add is less typing and one less atomic_* op.
Fam
>
> The alternative would be to add a full set of
> atomic_{add,sub,...}_relaxed atomics.
>
> Paolo
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2018-09-13 8:34 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-12 17:10 [Qemu-devel] [PATCH 0/3] aio-posix: polling mode bug fixes Paolo Bonzini
2018-09-12 17:10 ` [Qemu-devel] [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt Paolo Bonzini
2018-09-13 6:56 ` Fam Zheng
2018-09-13 8:29 ` [Qemu-devel] [Qemu-block] " Paolo Bonzini
2018-09-13 8:34 ` Fam Zheng
2018-09-12 17:10 ` [Qemu-devel] [PATCH 2/3] aio-posix: compute timeout before polling Paolo Bonzini
2018-09-13 7:16 ` Fam Zheng
2018-09-12 17:10 ` [Qemu-devel] [PATCH 3/3] aio-posix: do skip system call if ctx->notifier polling succeeds Paolo Bonzini
2018-09-13 7:19 ` Fam Zheng
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.