Extend the 'IOThreadInfo' structure to include attachment metrics.
This allows users to monitor the associated devices by identify them
by their QOM paths.

New fields added to IOThreadInfo:
 @holders: IOThreadHolder of the devices currently associated with
     this iothread.  Users can pre-allocate multiple iothread objects
     to serve as a persistent thread pool.  When a device is hot-unplugged,
     it is detached from its iothread, but the iothread remains available,
     allowing future hot-plugged devices to attach to it.  (Since 11.1)

These fields are also exposed via the Human Monitor Interface (HMP)
command 'info iothreads' to assist with manual debugging and
performance tuning.

Signed-off-by: Zhang Chen <[email protected]>
---
 iothread.c         | 22 ++++++++++++++++++++++
 monitor/hmp-cmds.c | 26 ++++++++++++++++++++++++++
 qapi/misc.json     | 11 +++++++++++
 3 files changed, 59 insertions(+)

diff --git a/iothread.c b/iothread.c
index a85e960e45..5949785b32 100644
--- a/iothread.c
+++ b/iothread.c
@@ -24,6 +24,8 @@
 #include "qemu/error-report.h"
 #include "qemu/rcu.h"
 #include "qemu/main-loop.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-misc.h"
 
 /*
  * iothread_ref:
@@ -119,6 +121,25 @@ static void iothread_unref(IOThread *iothread, const 
IOThreadHolder *holder)
     object_unref(OBJECT(iothread));
 }
 
+static IOThreadHolderList *iothread_get_holders_list(IOThread *iothread)
+{
+    IOThreadHolderList *head = NULL;
+    IOThreadHolderList **prev = &head;
+    GList *l;
+
+    for (l = iothread->holders; l; l = l->next) {
+        IOThreadHolder *src = l->data;
+        IOThreadHolderList *entry = g_new0(IOThreadHolderList, 1);
+
+        entry->value = QAPI_CLONE(IOThreadHolder, src);
+
+        *prev = entry;
+        prev = &entry->next;
+    }
+
+    return head;
+}
+
 static void *iothread_run(void *opaque)
 {
     IOThread *iothread = opaque;
@@ -488,6 +509,7 @@ static int query_one_iothread(Object *object, void *opaque)
     info = g_new0(IOThreadInfo, 1);
     info->id = iothread_get_id(iothread);
     info->thread_id = iothread->thread_id;
+    info->holders = iothread_get_holders_list(iothread);
     info->poll_max_ns = iothread->poll_max_ns;
     info->poll_grow = iothread->poll_grow;
     info->poll_shrink = iothread->poll_shrink;
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 443b8c785d..1b5883147b 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -237,11 +237,37 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
     IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
     IOThreadInfoList *info;
     IOThreadInfo *value;
+    IOThreadHolderList *h;
 
     for (info = info_list; info; info = info->next) {
         value = info->value;
         monitor_printf(mon, "%s:\n", value->id);
         monitor_printf(mon, "  thread_id=%" PRId64 "\n", value->thread_id);
+        monitor_printf(mon, "  holders=");
+        if (value->holders) {
+            for (h = value->holders; h; h = h->next) {
+                IOThreadHolder *holder = h->value;
+
+                switch (holder->type) {
+                case IO_THREAD_HOLDER_KIND_BLOCK_NODE:
+                    monitor_printf(mon, "[block-node: %s]",
+                                   holder->u.block_node.node_name);
+                    break;
+                case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
+                    monitor_printf(mon, "[qom-path: %s]",
+                                   holder->u.qom_object.qom_path);
+                    break;
+                case IO_THREAD_HOLDER_KIND_MONITOR_NAME:
+                    monitor_printf(mon, "[monitor-name: %s]",
+                                   holder->u.monitor_name.monitor_name);
+                    break;
+                default:
+                    monitor_printf(mon, "[unknown]");
+                    break;
+                }
+            }
+            monitor_printf(mon, "\n");
+        }
         monitor_printf(mon, "  poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
         monitor_printf(mon, "  poll-grow=%" PRId64 "\n", value->poll_grow);
         monitor_printf(mon, "  poll-shrink=%" PRId64 "\n", value->poll_shrink);
diff --git a/qapi/misc.json b/qapi/misc.json
index d9f82f0922..4c16be3fd4 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -137,6 +137,13 @@
 #
 # @thread-id: ID of the underlying host thread
 #
+# @holders: IOThreadHolder of the devices currently associated with
+#     this iothread.  Users can pre-allocate multiple iothread objects
+#     to serve as a persistent thread pool.  When a device is
+#     hot-unplugged, it is detached from its iothread, but the
+#     iothread remains available, allowing future hot-plugged devices
+#     to attach to it.  (Since 11.1)
+#
 # @poll-max-ns: maximum polling time in ns, 0 means polling is
 #     disabled (since 2.9)
 #
@@ -159,6 +166,7 @@
 { 'struct': 'IOThreadInfo',
   'data': {'id': 'str',
            'thread-id': 'int',
+           'holders': ['IOThreadHolder'],
            'poll-max-ns': 'int',
            'poll-grow': 'int',
            'poll-shrink': 'int',
@@ -185,6 +193,8 @@
 #              {
 #                 "id":"iothread0",
 #                 "thread-id":3134,
+#                 "holders":[{"qom-path": 
"/machine/peripheral/blk1/virtio-backend", "type": "qom-object"},
+#                            {"qom-path": 
"/machine/peripheral/blk0/virtio-backend", "type": "qom-object"}],
 #                 "poll-max-ns":32768,
 #                 "poll-grow":0,
 #                 "poll-shrink":0,
@@ -193,6 +203,7 @@
 #              {
 #                 "id":"iothread1",
 #                 "thread-id":3135,
+#                 "holders":[{"qom-path": 
"/machine/peripheral/blk2/virtio-backend", "type": "qom-object"}],
 #                 "poll-max-ns":32768,
 #                 "poll-grow":0,
 #                 "poll-shrink":0,
-- 
2.49.0


Reply via email to