[PATCH v3 13/15] conf: Introduce <defaultiothread/>

Michal Privoznik mprivozn at redhat.com
Wed Jun 8 13:43:07 UTC 2022


As of v7.0.0-877-g70ac26b9e5 QEMU exposes its default event loop
for devices with no IOThread assigned as an QMP object. In the
very next commit (v7.0.0-878-g71ad4713cc) it was extended for
thread-pool-min and thread-pool-max attributes. Expose them under
new <defaultiothread/> element.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
Reviewed-by: Peter Krempa <pkrempa at redhat.com>
---
 docs/formatdomain.rst                         | 11 ++++
 src/conf/domain_conf.c                        | 63 +++++++++++++++++++
 src/conf/domain_conf.h                        |  8 +++
 src/conf/domain_validate.c                    | 37 ++++++++---
 src/conf/schemas/domaincommon.rng             | 15 +++++
 src/conf/virconftypes.h                       |  2 +
 .../iothreads-ids-pool-sizes.xml              |  1 +
 7 files changed, 127 insertions(+), 10 deletions(-)

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 07837220ed..7da625380c 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -677,6 +677,7 @@ host/guest with many LUNs. :since:`Since 1.2.8 (QEMU only)`
        <iothread id="6"/>
        <iothread id="8" thread_pool_min="2" thread_pool_max="32"/>
      </iothreadids>
+     <defaultiothread thread_pool_min="8" thread_pool_max="16">
      ...
    </domain>
 
@@ -700,6 +701,16 @@ host/guest with many LUNs. :since:`Since 1.2.8 (QEMU only)`
    ``thread_pool_max`` which allow setting lower and upper boundary for number
    of worker threads for given IOThread. While the former can be value of zero,
    the latter can't. :since:`Since 8.5.0`
+``defaultiothread``
+   This element represents the default event loop within hypervisor, where I/O
+   requests from devices not assigned to a specific IOThread are processed.
+   The element then can have ``thread_pool_min`` and/or ``thread_pool_max``
+   attributes, which control the lower and upper boundary for number of worker
+   threads of the default event loop. Emulator might be multithreaded and spawn
+   so called worker threads on demand. In general neither of these attributes
+   should be set (leaving the emulator use its own default values), unless the
+   emulator runs in a real time workload and thus can't afford unpredictability
+   of time it takes to spawn new worker threads. :since:`Since 8.5.0`
 
 
 CPU Tuning
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index ea8061dc3d..761c3f4d87 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3825,6 +3825,8 @@ void virDomainDefFree(virDomainDef *def)
 
     virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
 
+    g_free(def->defaultIOThread);
+
     virBitmapFree(def->cputune.emulatorpin);
     g_free(def->cputune.emulatorsched);
 
@@ -17017,6 +17019,7 @@ virDomainIdmapDefParseXML(xmlXPathContextPtr ctxt,
  *       <iothread id='5'/>
  *       <iothread id='7'/>
  *     </iothreadids>
+ *     <defaultiothread thread_pool_min="8" thread_pool_max="8"/>
  */
 static virDomainIOThreadIDDef *
 virDomainIOThreadIDDefParseXML(xmlNodePtr node)
@@ -17042,6 +17045,38 @@ virDomainIOThreadIDDefParseXML(xmlNodePtr node)
 }
 
 
+static int
+virDomainDefaultIOThreadDefParse(virDomainDef *def,
+                                 xmlXPathContextPtr ctxt)
+{
+    xmlNodePtr node = NULL;
+    g_autofree virDomainDefaultIOThreadDef *thrd = NULL;
+
+    node = virXPathNode("./defaultiothread", ctxt);
+    if (!node)
+        return 0;
+
+    thrd = g_new0(virDomainDefaultIOThreadDef, 1);
+
+    if (virXMLPropInt(node, "thread_pool_min", 10,
+                      VIR_XML_PROP_NONNEGATIVE,
+                      &thrd->thread_pool_min, -1) < 0)
+        return -1;
+
+    if (virXMLPropInt(node, "thread_pool_max", 10,
+                      VIR_XML_PROP_NONNEGATIVE,
+                      &thrd->thread_pool_max, -1) < 0)
+        return -1;
+
+    if (thrd->thread_pool_min == -1 &&
+        thrd->thread_pool_max == -1)
+        return 0;
+
+    def->defaultIOThread = g_steal_pointer(&thrd);
+    return 0;
+}
+
+
 static int
 virDomainDefParseIOThreads(virDomainDef *def,
                            xmlXPathContextPtr ctxt)
@@ -17059,6 +17094,9 @@ virDomainDefParseIOThreads(virDomainDef *def,
         return -1;
     }
 
+    if (virDomainDefaultIOThreadDefParse(def, ctxt) < 0)
+        return -1;
+
     /* Extract any iothread id's defined */
     if ((n = virXPathNodeSet("./iothreadids/iothread", ctxt, &nodes)) < 0)
         return -1;
@@ -27604,6 +27642,29 @@ virDomainDefIothreadShouldFormat(const virDomainDef *def)
 }
 
 
+static void
+virDomainDefaultIOThreadDefFormat(virBuffer *buf,
+                                  const virDomainDef *def)
+{
+    virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
+
+    if (!def->defaultIOThread)
+        return;
+
+    if (def->defaultIOThread->thread_pool_min >= 0) {
+        virBufferAsprintf(&attrBuf, " thread_pool_min='%d'",
+                          def->defaultIOThread->thread_pool_min);
+    }
+
+    if (def->defaultIOThread->thread_pool_max >= 0) {
+        virBufferAsprintf(&attrBuf, " thread_pool_max='%d'",
+                          def->defaultIOThread->thread_pool_max);
+    }
+
+    virXMLFormatElement(buf, "defaultiothread", &attrBuf, NULL);
+}
+
+
 static void
 virDomainDefIOThreadsFormat(virBuffer *buf,
                             const virDomainDef *def)
@@ -27641,6 +27702,8 @@ virDomainDefIOThreadsFormat(virBuffer *buf,
     }
 
     virXMLFormatElement(buf, "iothreadids", NULL, &childrenBuf);
+
+    virDomainDefaultIOThreadDefFormat(buf, def);
 }
 
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 035edc0710..da9e281214 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2655,6 +2655,12 @@ void virDomainIOThreadIDDefFree(virDomainIOThreadIDDef *def);
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainIOThreadIDDef, virDomainIOThreadIDDefFree);
 
 
+struct _virDomainDefaultIOThreadDef {
+    int thread_pool_min;
+    int thread_pool_max;
+};
+
+
 struct _virDomainCputune {
     unsigned long long shares;
     bool sharesSpecified;
@@ -2863,6 +2869,8 @@ struct _virDomainDef {
     size_t niothreadids;
     virDomainIOThreadIDDef **iothreadids;
 
+    virDomainDefaultIOThreadDef *defaultIOThread;
+
     virDomainCputune cputune;
 
     virDomainResctrlDef **resctrls;
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 3ada739ea7..1e18826bc1 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1716,6 +1716,26 @@ virDomainDefFSValidate(const virDomainDef *def)
 }
 
 
+static int
+virDomainDefValidateIOThreadsThreadPool(int thread_pool_min,
+                                        int thread_pool_max)
+{
+    if (thread_pool_max == 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("thread_pool_max must be a positive integer"));
+        return -1;
+    }
+
+    if (thread_pool_min > thread_pool_max) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("thread_pool_min must be smaller or equal to thread_pool_max"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 virDomainDefValidateIOThreads(const virDomainDef *def)
 {
@@ -1724,19 +1744,16 @@ virDomainDefValidateIOThreads(const virDomainDef *def)
     for (i = 0; i < def->niothreadids; i++) {
         virDomainIOThreadIDDef *iothread = def->iothreadids[i];
 
-        if (iothread->thread_pool_max == 0) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("thread_pool_max must be a positive integer"));
+        if (virDomainDefValidateIOThreadsThreadPool(iothread->thread_pool_min,
+                                                    iothread->thread_pool_max) < 0)
             return -1;
-        }
-
-        if (iothread->thread_pool_min > iothread->thread_pool_max) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                           _("thread_pool_min must be smaller or equal to thread_pool_max"));
-            return -1;
-        }
     }
 
+    if (def->defaultIOThread &&
+        virDomainDefValidateIOThreadsThreadPool(def->defaultIOThread->thread_pool_min,
+                                                def->defaultIOThread->thread_pool_max) < 0)
+        return -1;
+
     return 0;
 }
 
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index fad70d3857..efd49cfa01 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -844,6 +844,21 @@
         </element>
       </optional>
 
+      <optional>
+        <element name="defaultiothread">
+          <optional>
+            <attribute name="thread_pool_min">
+              <ref name="unsignedInt"/>
+            </attribute>
+          </optional>
+          <optional>
+            <attribute name="thread_pool_max">
+              <ref name="unsignedInt"/>
+            </attribute>
+          </optional>
+        </element>
+      </optional>
+
       <optional>
         <ref name="blkiotune"/>
       </optional>
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index 21420ba8ea..c3f1c5fa01 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -142,6 +142,8 @@ typedef struct _virDomainIOMMUDef virDomainIOMMUDef;
 
 typedef struct _virDomainIOThreadIDDef virDomainIOThreadIDDef;
 
+typedef struct _virDomainDefaultIOThreadDef virDomainDefaultIOThreadDef;
+
 typedef struct _virDomainIdMapDef virDomainIdMapDef;
 
 typedef struct _virDomainIdMapEntry virDomainIdMapEntry;
diff --git a/tests/qemuxml2argvdata/iothreads-ids-pool-sizes.xml b/tests/qemuxml2argvdata/iothreads-ids-pool-sizes.xml
index 0f93d14f12..4cebdfada9 100644
--- a/tests/qemuxml2argvdata/iothreads-ids-pool-sizes.xml
+++ b/tests/qemuxml2argvdata/iothreads-ids-pool-sizes.xml
@@ -12,6 +12,7 @@
     <iothread id='3'/>
     <iothread id='5'/>
   </iothreadids>
+  <defaultiothread thread_pool_min='8' thread_pool_max='16'/>
   <os>
     <type arch='x86_64' machine='q35'>hvm</type>
     <boot dev='hd'/>
-- 
2.35.1



More information about the libvir-list mailing list