As of v7.0.0-877-g70ac26b9e5 QEMU exposes its main event loop 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 <mainloop/> element. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- docs/formatdomain.rst | 9 +++ src/conf/domain_conf.c | 63 +++++++++++++++++++ src/conf/domain_conf.h | 8 +++ src/conf/schemas/domaincommon.rng | 15 +++++ src/conf/virconftypes.h | 2 + .../iothreads-ids-pool-sizes.xml | 1 + 6 files changed, 98 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 2aa39b2f63..22eb540ba3 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> @@ -699,6 +700,14 @@ host/guest with many LUNs. :since:`Since 1.2.8 (QEMU only)` The element has two optional attributes ``thread_pool_min`` and ``hread_pool_max`` which allow setting lower and upper boundary for number of worker threads for given IOThread. :since:`Since 8.5.0` +``defaultiothread`` + 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 for the emulator. 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 8891289866..b1e7c2ef22 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3824,6 +3824,8 @@ void virDomainDefFree(virDomainDef *def) virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids); + g_free(def->defaultIOThread); + virBitmapFree(def->cputune.emulatorpin); g_free(def->cputune.emulatorsched); @@ -17016,6 +17018,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) @@ -17041,6 +17044,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) @@ -17058,6 +17093,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; @@ -27603,6 +27641,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) @@ -27640,6 +27701,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 2a5001f15c..98b8ce703c 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/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 7e6310832b..e64900d0cf 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="unsignedLong"/> + </attribute> + </optional> + <optional> + <attribute name="thread_pool_max"> + <ref name="unsignedLong"/> + </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