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 (QOM path or block node name) 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 | 22 ++++++++++++++++++++++
qapi/misc.json | 11 +++++++++++
3 files changed, 55 insertions(+)
diff --git a/iothread.c b/iothread.c
index 5d6f46d286..a78744284b 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"
/*
* Add the @holder path to the iothread's tracking list.
@@ -93,6 +95,25 @@ static void iothread_unref(IOThread *iothread, const char
*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;
@@ -465,6 +486,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 db92d6cb86..be799766d6 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -237,11 +237,33 @@ 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.data);
+ break;
+ case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
+ monitor_printf(mon, "[qom: %s]",
+ holder->u.qom_object.data);
+ 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 5fb7dcfcad..39ec19362c 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -124,6 +124,13 @@
#
# @thread-id: ID of the underlying host thread
#
+# @holders: IoThreadHolder (QOM path or block node name) 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)
#
@@ -146,6 +153,7 @@
{ 'struct': 'IOThreadInfo',
'data': {'id': 'str',
'thread-id': 'int',
+ 'holders': ['IoThreadHolder'],
'poll-max-ns': 'int',
'poll-grow': 'int',
'poll-shrink': 'int',
@@ -172,6 +180,8 @@
# {
# "id":"iothread0",
# "thread-id":3134,
+# "holders":["/machine/peripheral/blk1/virtio-backend",
+# "/machine/peripheral/blk0/virtio-backend"],
# "poll-max-ns":32768,
# "poll-grow":0,
# "poll-shrink":0,
@@ -180,6 +190,7 @@
# {
# "id":"iothread1",
# "thread-id":3135,
+# "holders":["/machine/peripheral/blk2/virtio-backend"],
# "poll-max-ns":32768,
# "poll-grow":0,
# "poll-shrink":0,
--
2.49.0