<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>
``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
virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
+ g_free(def->defaultIOThread);
+
virBitmapFree(def->cputune.emulatorpin);
g_free(def->cputune.emulatorsched);
* <iothread id='5'/>
* <iothread id='7'/>
* </iothreadids>
+ * <defaultiothread thread_pool_min="8" thread_pool_max="8"/>
*/
static virDomainIOThreadIDDef *
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)
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;
}
+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)
}
virXMLFormatElement(buf, "iothreadids", NULL, &childrenBuf);
+
+ virDomainDefaultIOThreadDefFormat(buf, 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;
size_t niothreadids;
virDomainIOThreadIDDef **iothreadids;
+ virDomainDefaultIOThreadDef *defaultIOThread;
+
virDomainCputune cputune;
virDomainResctrlDef **resctrls;
}
+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)
{
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;
}
</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>
typedef struct _virDomainIOThreadIDDef virDomainIOThreadIDDef;
+typedef struct _virDomainDefaultIOThreadDef virDomainDefaultIOThreadDef;
+
typedef struct _virDomainIdMapDef virDomainIdMapDef;
typedef struct _virDomainIdMapEntry virDomainIdMapEntry;
<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'/>