a83cc2
From d8682ef60e3a658d776473fee2299015dd5105d7 Mon Sep 17 00:00:00 2001
a83cc2
From: Stefano Garzarella <sgarzare@redhat.com>
a83cc2
Date: Thu, 29 Jul 2021 07:42:31 -0400
a83cc2
Subject: [PATCH 18/39] iothread: add aio-max-batch parameter
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-MergeRequest: 32: Synchronize with RHEL-AV 8.5 release 27 to RHEL 9
a83cc2
RH-Commit: [10/15] d033b3c8ddd71bae799103832039d6daa6dfad52 (mrezanin/centos-src-qemu-kvm)
a83cc2
RH-Bugzilla: 1957194
a83cc2
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
a83cc2
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
a83cc2
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
a83cc2
RH-Acked-by: Andrew Jones <drjones@redhat.com>
a83cc2
a83cc2
The `aio-max-batch` parameter will be propagated to AIO engines
a83cc2
and it will be used to control the maximum number of queued requests.
a83cc2
a83cc2
When there are in queue a number of requests equal to `aio-max-batch`,
a83cc2
the engine invokes the system call to forward the requests to the kernel.
a83cc2
a83cc2
This parameter allows us to control the maximum batch size to reduce
a83cc2
the latency that requests might accumulate while queued in the AIO
a83cc2
engine queue.
a83cc2
a83cc2
If `aio-max-batch` is equal to 0 (default value), the AIO engine will
a83cc2
use its default maximum batch size value.
a83cc2
a83cc2
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
a83cc2
Message-id: 20210721094211.69853-3-sgarzare@redhat.com
a83cc2
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
a83cc2
(cherry picked from commit 1793ad0247cad35db1ebbc04fbea0446c30a27ca)
a83cc2
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 include/block/aio.h       | 12 +++++++++
a83cc2
 include/sysemu/iothread.h |  3 +++
a83cc2
 iothread.c                | 55 +++++++++++++++++++++++++++++++++++----
a83cc2
 monitor/hmp-cmds.c        |  2 ++
a83cc2
 qapi/misc.json            |  6 ++++-
a83cc2
 qapi/qom.json             |  7 ++++-
a83cc2
 qemu-options.hx           |  8 ++++--
a83cc2
 util/aio-posix.c          | 12 +++++++++
a83cc2
 util/aio-win32.c          |  5 ++++
a83cc2
 util/async.c              |  2 ++
a83cc2
 10 files changed, 103 insertions(+), 9 deletions(-)
a83cc2
a83cc2
diff --git a/include/block/aio.h b/include/block/aio.h
a83cc2
index 5f342267d5..ea68a139c8 100644
a83cc2
--- a/include/block/aio.h
a83cc2
+++ b/include/block/aio.h
a83cc2
@@ -232,6 +232,9 @@ struct AioContext {
a83cc2
     int64_t poll_grow;      /* polling time growth factor */
a83cc2
     int64_t poll_shrink;    /* polling time shrink factor */
a83cc2
 
a83cc2
+    /* AIO engine parameters */
a83cc2
+    int64_t aio_max_batch;  /* maximum number of requests in a batch */
a83cc2
+
a83cc2
     /*
a83cc2
      * List of handlers participating in userspace polling.  Protected by
a83cc2
      * ctx->list_lock.  Iterated and modified mostly by the event loop thread
a83cc2
@@ -727,4 +730,13 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
a83cc2
                                  int64_t grow, int64_t shrink,
a83cc2
                                  Error **errp);
a83cc2
 
a83cc2
+/**
a83cc2
+ * aio_context_set_aio_params:
a83cc2
+ * @ctx: the aio context
a83cc2
+ * @max_batch: maximum number of requests in a batch, 0 means that the
a83cc2
+ *             engine will use its default
a83cc2
+ */
a83cc2
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
a83cc2
+                                Error **errp);
a83cc2
+
a83cc2
 #endif
a83cc2
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
a83cc2
index f177142f16..7f714bd136 100644
a83cc2
--- a/include/sysemu/iothread.h
a83cc2
+++ b/include/sysemu/iothread.h
a83cc2
@@ -37,6 +37,9 @@ struct IOThread {
a83cc2
     int64_t poll_max_ns;
a83cc2
     int64_t poll_grow;
a83cc2
     int64_t poll_shrink;
a83cc2
+
a83cc2
+    /* AioContext AIO engine parameters */
a83cc2
+    int64_t aio_max_batch;
a83cc2
 };
a83cc2
 typedef struct IOThread IOThread;
a83cc2
 
a83cc2
diff --git a/iothread.c b/iothread.c
a83cc2
index a12de6e455..272be5e146 100644
a83cc2
--- a/iothread.c
a83cc2
+++ b/iothread.c
a83cc2
@@ -159,6 +159,24 @@ static void iothread_init_gcontext(IOThread *iothread)
a83cc2
     iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
a83cc2
 }
a83cc2
 
a83cc2
+static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
a83cc2
+{
a83cc2
+    ERRP_GUARD();
a83cc2
+
a83cc2
+    aio_context_set_poll_params(iothread->ctx,
a83cc2
+                                iothread->poll_max_ns,
a83cc2
+                                iothread->poll_grow,
a83cc2
+                                iothread->poll_shrink,
a83cc2
+                                errp);
a83cc2
+    if (*errp) {
a83cc2
+        return;
a83cc2
+    }
a83cc2
+
a83cc2
+    aio_context_set_aio_params(iothread->ctx,
a83cc2
+                               iothread->aio_max_batch,
a83cc2
+                               errp);
a83cc2
+}
a83cc2
+
a83cc2
 static void iothread_complete(UserCreatable *obj, Error **errp)
a83cc2
 {
a83cc2
     Error *local_error = NULL;
a83cc2
@@ -178,11 +196,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp)
a83cc2
      */
a83cc2
     iothread_init_gcontext(iothread);
a83cc2
 
a83cc2
-    aio_context_set_poll_params(iothread->ctx,
a83cc2
-                                iothread->poll_max_ns,
a83cc2
-                                iothread->poll_grow,
a83cc2
-                                iothread->poll_shrink,
a83cc2
-                                &local_error);
a83cc2
+    iothread_set_aio_context_params(iothread, &local_error);
a83cc2
     if (local_error) {
a83cc2
         error_propagate(errp, local_error);
a83cc2
         aio_context_unref(iothread->ctx);
a83cc2
@@ -219,6 +233,9 @@ static PollParamInfo poll_grow_info = {
a83cc2
 static PollParamInfo poll_shrink_info = {
a83cc2
     "poll-shrink", offsetof(IOThread, poll_shrink),
a83cc2
 };
a83cc2
+static PollParamInfo aio_max_batch_info = {
a83cc2
+    "aio-max-batch", offsetof(IOThread, aio_max_batch),
a83cc2
+};
a83cc2
 
a83cc2
 static void iothread_get_param(Object *obj, Visitor *v,
a83cc2
         const char *name, void *opaque, Error **errp)
a83cc2
@@ -278,6 +295,29 @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
a83cc2
     }
a83cc2
 }
a83cc2
 
a83cc2
+static void iothread_get_aio_param(Object *obj, Visitor *v,
a83cc2
+        const char *name, void *opaque, Error **errp)
a83cc2
+{
a83cc2
+
a83cc2
+    iothread_get_param(obj, v, name, opaque, errp);
a83cc2
+}
a83cc2
+
a83cc2
+static void iothread_set_aio_param(Object *obj, Visitor *v,
a83cc2
+        const char *name, void *opaque, Error **errp)
a83cc2
+{
a83cc2
+    IOThread *iothread = IOTHREAD(obj);
a83cc2
+
a83cc2
+    if (!iothread_set_param(obj, v, name, opaque, errp)) {
a83cc2
+        return;
a83cc2
+    }
a83cc2
+
a83cc2
+    if (iothread->ctx) {
a83cc2
+        aio_context_set_aio_params(iothread->ctx,
a83cc2
+                                   iothread->aio_max_batch,
a83cc2
+                                   errp);
a83cc2
+    }
a83cc2
+}
a83cc2
+
a83cc2
 static void iothread_class_init(ObjectClass *klass, void *class_data)
a83cc2
 {
a83cc2
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
a83cc2
@@ -295,6 +335,10 @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
a83cc2
                               iothread_get_poll_param,
a83cc2
                               iothread_set_poll_param,
a83cc2
                               NULL, &poll_shrink_info);
a83cc2
+    object_class_property_add(klass, "aio-max-batch", "int",
a83cc2
+                              iothread_get_aio_param,
a83cc2
+                              iothread_set_aio_param,
a83cc2
+                              NULL, &aio_max_batch_info);
a83cc2
 }
a83cc2
 
a83cc2
 static const TypeInfo iothread_info = {
a83cc2
@@ -344,6 +388,7 @@ static int query_one_iothread(Object *object, void *opaque)
a83cc2
     info->poll_max_ns = iothread->poll_max_ns;
a83cc2
     info->poll_grow = iothread->poll_grow;
a83cc2
     info->poll_shrink = iothread->poll_shrink;
a83cc2
+    info->aio_max_batch = iothread->aio_max_batch;
a83cc2
 
a83cc2
     QAPI_LIST_APPEND(*tail, info);
a83cc2
     return 0;
a83cc2
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
a83cc2
index cc15d9b6ee..2905bc1594 100644
a83cc2
--- a/monitor/hmp-cmds.c
a83cc2
+++ b/monitor/hmp-cmds.c
a83cc2
@@ -1889,6 +1889,8 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
a83cc2
         monitor_printf(mon, "  poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
a83cc2
         monitor_printf(mon, "  poll-grow=%" PRId64 "\n", value->poll_grow);
a83cc2
         monitor_printf(mon, "  poll-shrink=%" PRId64 "\n", value->poll_shrink);
a83cc2
+        monitor_printf(mon, "  aio-max-batch=%" PRId64 "\n",
a83cc2
+                       value->aio_max_batch);
a83cc2
     }
a83cc2
 
a83cc2
     qapi_free_IOThreadInfoList(info_list);
a83cc2
diff --git a/qapi/misc.json b/qapi/misc.json
a83cc2
index 156f98203e..5c2ca3b556 100644
a83cc2
--- a/qapi/misc.json
a83cc2
+++ b/qapi/misc.json
a83cc2
@@ -86,6 +86,9 @@
a83cc2
 # @poll-shrink: how many ns will be removed from polling time, 0 means that
a83cc2
 #               it's not configured (since 2.9)
a83cc2
 #
a83cc2
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
a83cc2
+#                 0 means that the engine will use its default (since 6.1)
a83cc2
+#
a83cc2
 # Since: 2.0
a83cc2
 ##
a83cc2
 { 'struct': 'IOThreadInfo',
a83cc2
@@ -93,7 +96,8 @@
a83cc2
            'thread-id': 'int',
a83cc2
            'poll-max-ns': 'int',
a83cc2
            'poll-grow': 'int',
a83cc2
-           'poll-shrink': 'int' } }
a83cc2
+           'poll-shrink': 'int',
a83cc2
+           'aio-max-batch': 'int' } }
a83cc2
 
a83cc2
 ##
a83cc2
 # @query-iothreads:
a83cc2
diff --git a/qapi/qom.json b/qapi/qom.json
a83cc2
index cd0e76d564..f361157903 100644
a83cc2
--- a/qapi/qom.json
a83cc2
+++ b/qapi/qom.json
a83cc2
@@ -516,12 +516,17 @@
a83cc2
 #               algorithm detects it is spending too long polling without
a83cc2
 #               encountering events. 0 selects a default behaviour (default: 0)
a83cc2
 #
a83cc2
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
a83cc2
+#                 0 means that the engine will use its default
a83cc2
+#                 (default:0, since 6.1)
a83cc2
+#
a83cc2
 # Since: 2.0
a83cc2
 ##
a83cc2
 { 'struct': 'IothreadProperties',
a83cc2
   'data': { '*poll-max-ns': 'int',
a83cc2
             '*poll-grow': 'int',
a83cc2
-            '*poll-shrink': 'int' } }
a83cc2
+            '*poll-shrink': 'int',
a83cc2
+            '*aio-max-batch': 'int' } }
a83cc2
 
a83cc2
 ##
a83cc2
 # @MemoryBackendProperties:
a83cc2
diff --git a/qemu-options.hx b/qemu-options.hx
a83cc2
index 79ca09feac..d5f1ec27c5 100644
a83cc2
--- a/qemu-options.hx
a83cc2
+++ b/qemu-options.hx
a83cc2
@@ -5185,7 +5185,7 @@ SRST
a83cc2
 
a83cc2
             CN=laptop.example.com,O=Example Home,L=London,ST=London,C=GB
a83cc2
 
a83cc2
-    ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink``
a83cc2
+    ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink,aio-max-batch=aio-max-batch``
a83cc2
         Creates a dedicated event loop thread that devices can be
a83cc2
         assigned to. This is known as an IOThread. By default device
a83cc2
         emulation happens in vCPU threads or the main event loop thread.
a83cc2
@@ -5221,7 +5221,11 @@ SRST
a83cc2
         the polling time when the algorithm detects it is spending too
a83cc2
         long polling without encountering events.
a83cc2
 
a83cc2
-        The polling parameters can be modified at run-time using the
a83cc2
+        The ``aio-max-batch`` parameter is the maximum number of requests
a83cc2
+        in a batch for the AIO engine, 0 means that the engine will use
a83cc2
+        its default.
a83cc2
+
a83cc2
+        The IOThread parameters can be modified at run-time using the
a83cc2
         ``qom-set`` command (where ``iothread1`` is the IOThread's
a83cc2
         ``id``):
a83cc2
 
a83cc2
diff --git a/util/aio-posix.c b/util/aio-posix.c
a83cc2
index 30f5354b1e..2b86777e91 100644
a83cc2
--- a/util/aio-posix.c
a83cc2
+++ b/util/aio-posix.c
a83cc2
@@ -716,3 +716,15 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
a83cc2
 
a83cc2
     aio_notify(ctx);
a83cc2
 }
a83cc2
+
a83cc2
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
a83cc2
+                                Error **errp)
a83cc2
+{
a83cc2
+    /*
a83cc2
+     * No thread synchronization here, it doesn't matter if an incorrect value
a83cc2
+     * is used once.
a83cc2
+     */
a83cc2
+    ctx->aio_max_batch = max_batch;
a83cc2
+
a83cc2
+    aio_notify(ctx);
a83cc2
+}
a83cc2
diff --git a/util/aio-win32.c b/util/aio-win32.c
a83cc2
index 168717b51b..d5b09a1193 100644
a83cc2
--- a/util/aio-win32.c
a83cc2
+++ b/util/aio-win32.c
a83cc2
@@ -440,3 +440,8 @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
a83cc2
         error_setg(errp, "AioContext polling is not implemented on Windows");
a83cc2
     }
a83cc2
 }
a83cc2
+
a83cc2
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
a83cc2
+                                Error **errp)
a83cc2
+{
a83cc2
+}
a83cc2
diff --git a/util/async.c b/util/async.c
a83cc2
index 674dbefb7c..6a9588d86b 100644
a83cc2
--- a/util/async.c
a83cc2
+++ b/util/async.c
a83cc2
@@ -537,6 +537,8 @@ AioContext *aio_context_new(Error **errp)
a83cc2
     ctx->poll_grow = 0;
a83cc2
     ctx->poll_shrink = 0;
a83cc2
 
a83cc2
+    ctx->aio_max_batch = 0;
a83cc2
+
a83cc2
     return ctx;
a83cc2
 fail:
a83cc2
     g_source_destroy(&ctx->source);
a83cc2
-- 
a83cc2
2.27.0
a83cc2