[PATCH 0/6] qemu: add poll-weight support for iothreads
This series adds support for the QEMU iothread poll-weight property, which controls the weight of the most recent event interval in the adaptive polling duration calculation. The valid range is [0, 63]; a value of 0 lets QEMU use its default weight. The series is split by layer: 1) conf/schema support 2) qemu capability detection 3) qemu backend support + public API constants + xmlconf tests 4) virsh support + test driver + virshtest 5) docs: fix pre-existing typos in iothread poll element description 6) docs: formatdomain documentation for poll-weight The series was validated with: meson test -C build virschematest meson test -C build qemucapabilitiestest meson test -C build qemuxmlconftest meson test -C build virshtest meson test -C build genericxml2xmltest QEMU commits: 9fea80ddf0 qapi/iothread: introduce poll-weight parameter for aio-poll 9563d0b5e2 aio-poll: refine iothread polling using weighted handler intervals ed21d9d65c aio-poll: avoid unnecessary polling time computation Jaehoon Kim (6): conf: add iothread poll-weight XML support qemu: capabilities: add capability for iothread poll-weight qemu: support iothread poll-weight virsh: add support for iothread poll-weight docs: fix typos in iothread poll element description docs: formatdomain: document iothread poll-weight docs/formatdomain.rst | 14 +++-- docs/manpages/virsh.rst | 18 ++++-- include/libvirt/libvirt-domain.h | 26 +++++++++ src/conf/domain_conf.c | 14 ++++- src/conf/domain_conf.h | 2 + src/conf/schemas/domaincommon.rng | 7 +++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 18 +++++- src/qemu/qemu_driver.c | 38 ++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 18 ++++++ src/qemu/qemu_validate.c | 10 +++- src/test/test_driver.c | 12 ++++ tests/genericxml2xmlindata/iothreadids.xml | 2 +- .../caps_11.1.0_aarch64.xml | 1 + .../caps_11.1.0_x86_64.xml | 1 + ...othreads-ids-poll-weight.x86_64-11.0.0.err | 1 + ...threads-ids-poll-weight.x86_64-latest.args | 40 +++++++++++++ ...othreads-ids-poll-weight.x86_64-latest.xml | 58 +++++++++++++++++++ .../iothreads-ids-poll-weight.xml | 58 +++++++++++++++++++ tests/qemuxmlconftest.c | 2 + tests/virshtestdata/iothreads.in | 2 + tests/virshtestdata/iothreads.out | 18 ++++++ tools/virsh-domain.c | 18 ++++++ 25 files changed, 367 insertions(+), 16 deletions(-) create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-11.0.0.err create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.xml -- 2.54.0
Add support for the iothread poll-weight XML attribute. Store the value in the internal iothread definition, parse it from the <poll/> element, and format it back into domain XML. Also extend the schema to accept the new attribute and validate the accepted range of [0, 63]. Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- src/conf/domain_conf.c | 14 +++++++++++++- src/conf/domain_conf.h | 2 ++ src/conf/schemas/domaincommon.rng | 7 +++++++ tests/genericxml2xmlindata/iothreadids.xml | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 17c4a57cd8..f69317c36f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16984,7 +16984,9 @@ virDomainDefParseBootXML(xmlXPathContextPtr ctxt, * * <iothreads>4</iothreads> * <iothreadids> - * <iothread id='1' thread_pool_min="0" thread_pool_max="60"/> + * <iothread id='1' thread_pool_min="0" thread_pool_max="60"> + * <poll max='32000' grow='2' shrink='2' weight='3'/> + * </iothread> * <iothread id='3'/> * <iothread id='5'/> * <iothread id='7'/> @@ -17032,6 +17034,12 @@ virDomainIOThreadIDDefParseXML(xmlNodePtr node) return NULL; iothrid->set_poll_shrink = rc == 1; + + if ((rc = virXMLPropUInt(pollNode, "weight", 10, VIR_XML_PROP_NONE, + &iothrid->poll_weight)) < 0) + return NULL; + + iothrid->set_poll_weight = rc == 1; } return g_steal_pointer(&iothrid); @@ -29011,6 +29019,7 @@ virDomainDefIothreadShouldFormat(const virDomainDef *def) def->iothreadids[i]->set_poll_max_ns || def->iothreadids[i]->set_poll_grow || def->iothreadids[i]->set_poll_shrink || + def->iothreadids[i]->set_poll_weight || def->iothreadids[i]->thread_pool_min >= 0 || def->iothreadids[i]->thread_pool_max >= 0) return true; @@ -29084,6 +29093,9 @@ virDomainDefIOThreadsFormat(virBuffer *buf, if (iothread->set_poll_shrink) virBufferAsprintf(&pollAttrBuf, " shrink='%llu'", iothread->poll_shrink); + if (iothread->set_poll_weight) + virBufferAsprintf(&pollAttrBuf, " weight='%u'", iothread->poll_weight); + virXMLFormatElement(&iothreadChildBuf, "poll", &pollAttrBuf, NULL); virXMLFormatElement(&childrenBuf, "iothread", &attrBuf, &iothreadChildBuf); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 0c6c79c413..eebe55a093 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2902,6 +2902,8 @@ struct _virDomainIOThreadIDDef { bool set_poll_grow; unsigned long long poll_shrink; bool set_poll_shrink; + unsigned int poll_weight; + bool set_poll_weight; int thread_pool_min; int thread_pool_max; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 121e4e06a6..36743f81e4 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -990,6 +990,13 @@ <ref name="unsignedLong"/> </attribute> </optional> + <optional> + <attribute name="weight"> + <data type="unsignedInt"> + <param name="maxInclusive">63</param> + </data> + </attribute> + </optional> </element> </optional> </element> diff --git a/tests/genericxml2xmlindata/iothreadids.xml b/tests/genericxml2xmlindata/iothreadids.xml index 671a467295..e9814854eb 100644 --- a/tests/genericxml2xmlindata/iothreadids.xml +++ b/tests/genericxml2xmlindata/iothreadids.xml @@ -7,7 +7,7 @@ <iothreads>1</iothreads> <iothreadids> <iothread id='8' thread_pool_min='2147483647' thread_pool_max='2147483647'> - <poll max='9223372036854775807' grow='456' shrink='789'/> + <poll max='9223372036854775807' grow='456' shrink='789' weight='3'/> </iothread> </iothreadids> <os> -- 2.54.0
Add a capability flag for the iothread poll-weight property. Detect support for the property from the QMP schema so that libvirt can conditionally expose and use poll-weight only with QEMU binaries that support it. Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_11.1.0_aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_11.1.0_x86_64.xml | 1 + 4 files changed, 5 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ebea050453..971663badc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -768,6 +768,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 495 */ "blockdev-mirror.target-is-zero", /* QEMU_CAPS_BLOCKDEV_MIRROR_TARGET_IS_ZERO */ "object-monitor-qmp", /* QEMU_CAPS_OBJECT_MONITOR_QMP */ + "iothread.poll-weight", /* QEMU_CAPS_IOTHREAD_POLL_WEIGHT */ ); @@ -1671,6 +1672,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "netdev_add/arg-type/+stream/reconnect-ms", QEMU_CAPS_NETDEV_STREAM_RECONNECT_MILISECONDS }, { "object-add/arg-type/+sev-guest/kernel-hashes", QEMU_CAPS_SEV_GUEST_KERNEL_HASHES }, { "object-add/arg-type/+iothread/thread-pool-max", QEMU_CAPS_IOTHREAD_THREAD_POOL_MAX }, + { "object-add/arg-type/+iothread/poll-weight", QEMU_CAPS_IOTHREAD_POLL_WEIGHT }, { "query-block/arg-type/flat", QEMU_CAPS_QUERY_BLOCK_FLAT }, { "query-display-options/ret-type/+egl-headless/rendernode", QEMU_CAPS_EGL_HEADLESS_RENDERNODE }, { "query-display-options/ret-type/+sdl", QEMU_CAPS_SDL }, diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index daec874a59..8f83eb8acd 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -742,6 +742,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 495 */ QEMU_CAPS_BLOCKDEV_MIRROR_TARGET_IS_ZERO, /* 'blockdev-mirror' supports 'target-is-zero' */ QEMU_CAPS_OBJECT_MONITOR_QMP, /* 'monitor-qmp' -object */ + QEMU_CAPS_IOTHREAD_POLL_WEIGHT, /* -object iothread.poll-weight */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_11.1.0_aarch64.xml b/tests/qemucapabilitiesdata/caps_11.1.0_aarch64.xml index b45dd83889..6c5c1770ad 100644 --- a/tests/qemucapabilitiesdata/caps_11.1.0_aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_11.1.0_aarch64.xml @@ -189,6 +189,7 @@ <flag name='query-block-flat'/> <flag name='blockdev-mirror.target-is-zero'/> <flag name='object-monitor-qmp'/> + <flag name='iothread.poll-weight'/> <version>11000090</version> <microcodeVersion>61700287</microcodeVersion> <package>v11.1.0-rc0</package> diff --git a/tests/qemucapabilitiesdata/caps_11.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_11.1.0_x86_64.xml index 7a4396c82b..98a6a7e083 100644 --- a/tests/qemucapabilitiesdata/caps_11.1.0_x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_11.1.0_x86_64.xml @@ -223,6 +223,7 @@ <flag name='amd-iommu.xtsup'/> <flag name='blockdev-mirror.target-is-zero'/> <flag name='object-monitor-qmp'/> + <flag name='iothread.poll-weight'/> <version>11000090</version> <microcodeVersion>43100287</microcodeVersion> <package>v11.1.0-rc0</package> -- 2.54.0
Use the configured iothread poll-weight value when interacting with QEMU. This wires the new setting into command line generation, monitor data parsing, driver-side parameter handling, and capability-based validation. Remove the break from the iothread validation loop because the loop now also checks poll-weight on every iothread. Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- include/libvirt/libvirt-domain.h | 26 +++++++++ src/qemu/qemu_command.c | 18 +++++- src/qemu/qemu_driver.c | 38 ++++++++++++ src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 18 ++++++ src/qemu/qemu_validate.c | 10 +++- ...othreads-ids-poll-weight.x86_64-11.0.0.err | 1 + ...threads-ids-poll-weight.x86_64-latest.args | 40 +++++++++++++ ...othreads-ids-poll-weight.x86_64-latest.xml | 58 +++++++++++++++++++ .../iothreads-ids-poll-weight.xml | 58 +++++++++++++++++++ tests/qemuxmlconftest.c | 2 + 11 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-11.0.0.err create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.args create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.xml create mode 100644 tests/qemuxmlconfdata/iothreads-ids-poll-weight.xml diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 5b67f8f897..f49aa1c136 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2748,6 +2748,22 @@ int virDomainDelIOThread(virDomainPtr domain, */ # define VIR_DOMAIN_IOTHREAD_POLL_SHRINK "poll_shrink" +/** + * VIR_DOMAIN_IOTHREAD_POLL_WEIGHT: + * + * This provides a shift value for the adaptive polling algorithm to control + * how much the most recent event interval affects the next polling duration + * calculation. Larger values decrease the weight of the current interval, + * enabling more gradual adjustments. Valid range is [0, 63]. A value of 0 + * lets the hypervisor select a default weight (typically 3, meaning the + * current interval contributes approximately 1/8 to the weighted average). + * + * Accepted type is VIR_TYPED_PARAM_UINT. + * + * Since: 12.6.0 + */ +# define VIR_DOMAIN_IOTHREAD_POLL_WEIGHT "poll_weight" + /** * VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN: * @@ -4330,6 +4346,16 @@ struct _virDomainStatsRecord { */ # define VIR_DOMAIN_STATS_IOTHREAD_SUFFIX_POLL_SHRINK ".poll-shrink" +/** + * VIR_DOMAIN_STATS_IOTHREAD_SUFFIX_POLL_WEIGHT: + * + * Polling weight factor as an unsigned int. This shift value controls how + * much the most recent event interval affects adaptive polling calculations. + * A 0 (zero) indicates the hypervisor's default weight is used. + * + * Since: 12.6.0 + */ +# define VIR_DOMAIN_STATS_IOTHREAD_SUFFIX_POLL_WEIGHT ".poll-weight" /** * VIR_DOMAIN_STATS_MEMORY_BANDWIDTH_MONITOR_COUNT: diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 95e2ea9a6b..b351059fc1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7659,7 +7659,8 @@ qemuBuildMemCommandLine(virCommand *cmd, static int qemuBuildIOThreadCommandLine(virCommand *cmd, - const virDomainDef *def) + const virDomainDef *def, + virQEMUCaps *qemuCaps) { size_t i; @@ -7694,6 +7695,19 @@ qemuBuildIOThreadCommandLine(virCommand *cmd, NULL) < 0) return -1; + if (iothread->set_poll_weight) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_IOTHREAD_POLL_WEIGHT)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("poll-weight is not supported by this QEMU binary")); + return -1; + } + + if (virJSONValueObjectAdd(&props, + "u:poll-weight", iothread->poll_weight, + NULL) < 0) + return -1; + } + if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0) return -1; } @@ -10903,7 +10917,7 @@ qemuBuildCommandLine(virDomainObj *vm, if (qemuBuildSmpCommandLine(cmd, def, qemuCaps) < 0) return NULL; - if (qemuBuildIOThreadCommandLine(cmd, def) < 0) + if (qemuBuildIOThreadCommandLine(cmd, def, qemuCaps) < 0) return NULL; if (qemuBuildThrottleGroupCommandLine(cmd, def) < 0) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index bdc0cff66a..1afd6e83ba 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5261,6 +5261,11 @@ qemuDomainHotplugModIOThreadIDDef(virDomainIOThreadIDDef *def, def->set_poll_shrink = true; } + if (mondef.set_poll_weight) { + def->poll_weight = mondef.poll_weight; + def->set_poll_weight = true; + } + if (mondef.set_thread_pool_min) def->thread_pool_min = mondef.thread_pool_min; @@ -5353,6 +5358,11 @@ qemuDomainHotplugDelIOThread(virDomainObj *vm, * necessary. If a 0 (zero) value is provided, QEMU resets the polling * interval to 0 (zero) allowing the poll-grow to manipulate the time. * + * - "poll-weight" - weight shift value used by the adaptive polling algorithm + * to determine how much the most recent event interval influences the + * next interval calculation. Accepted range is [0, 63]. If a 0 (zero) + * value is provided, QEMU uses its default weight. + * * QEMU keeps track of the polling time elapsed and may grow or shrink the * its polling interval based upon its heuristic algorithm. It is possible * that calculations determine that it has found a "sweet spot" and no @@ -5388,6 +5398,20 @@ qemuDomainIOThreadParseParams(virTypedParameterPtr params, if (rc == 1) iothread->set_poll_shrink = true; + if ((rc = virTypedParamsGetUInt(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, + &iothread->poll_weight)) < 0) + return -1; + if (rc == 1) { + if (iothread->poll_weight > 63) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("poll-weight value %1$u is out of range [0, 63]"), + iothread->poll_weight); + return -1; + } + iothread->set_poll_weight = true; + } + if ((rc = virTypedParamsGetInt(params, nparams, VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, &iothread->thread_pool_min)) < 0) @@ -5586,6 +5610,13 @@ qemuDomainChgIOThread(virQEMUDriver *driver, if (qemuDomainIOThreadValidate(iothreaddef, iothread, true) < 0) goto endjob; + if (iothread.set_poll_weight && + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_IOTHREAD_POLL_WEIGHT)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("poll-weight is not supported by this QEMU binary")); + goto endjob; + } + if (qemuDomainHotplugModIOThread(vm, iothread) < 0) goto endjob; @@ -5716,6 +5747,8 @@ qemuDomainSetIOThreadParams(virDomainPtr dom, VIR_TYPED_PARAM_UNSIGNED, VIR_DOMAIN_IOTHREAD_POLL_SHRINK, VIR_TYPED_PARAM_UNSIGNED, + VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, + VIR_TYPED_PARAM_UINT, VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, VIR_TYPED_PARAM_INT, VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, @@ -18380,6 +18413,11 @@ qemuDomainGetStatsIOThread(virQEMUDriver *driver G_GNUC_UNUSED, VIR_DOMAIN_STATS_IOTHREAD_PREFIX "%u" VIR_DOMAIN_STATS_IOTHREAD_SUFFIX_POLL_SHRINK, iothreads[i]->iothread_id); } + if (iothreads[i]->set_poll_weight) { + virTypedParamListAddUInt(params, iothreads[i]->poll_weight, + VIR_DOMAIN_STATS_IOTHREAD_PREFIX "%u" VIR_DOMAIN_STATS_IOTHREAD_SUFFIX_POLL_WEIGHT, + iothreads[i]->iothread_id); + } } for (i = 0; i < niothreads; i++) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2afb580e4..e73be4e263 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1583,11 +1583,13 @@ struct _qemuMonitorIOThreadInfo { unsigned long long poll_max_ns; unsigned long long poll_grow; unsigned long long poll_shrink; + unsigned int poll_weight; int thread_pool_min; int thread_pool_max; bool set_poll_max_ns; bool set_poll_grow; bool set_poll_shrink; + bool set_poll_weight; bool set_thread_pool_min; bool set_thread_pool_max; }; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 21f4d613b7..c88f74c10b 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7202,6 +7202,11 @@ qemuMonitorJSONGetIOThreads(qemuMonitor *mon, virJSONValueObjectGetNumberUlong(child, "poll-shrink", &info->poll_shrink) == 0) info->poll_valid = true; + + /* poll-weight is optional, only present on newer QEMU */ + if (virJSONValueObjectGetNumberUint(child, "poll-weight", + &info->poll_weight) == 0) + info->set_poll_weight = true; } *niothreads = n; @@ -7243,6 +7248,19 @@ qemuMonitorJSONSetIOThread(qemuMonitor *mon, #undef VIR_IOTHREAD_SET_PROP_UL +#define VIR_IOTHREAD_SET_PROP_UINT(propName, propVal) \ + if (iothreadInfo->set_##propVal) { \ + memset(&prop, 0, sizeof(prop)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_UINT; \ + prop.val.ui = iothreadInfo->propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + return -1; \ + } + + VIR_IOTHREAD_SET_PROP_UINT("poll-weight", poll_weight); + +#undef VIR_IOTHREAD_SET_PROP_UINT + if (iothreadInfo->set_thread_pool_min && iothreadInfo->set_thread_pool_max) { int curr_max = -1; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 439d4b1916..5a770a800f 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -500,9 +500,15 @@ qemuValidateDomainDefIOThreads(const virDomainDef *def, for (i = 0; i < def->niothreadids; i++) { virDomainIOThreadIDDef *iothread = def->iothreadids[i]; - if (iothread->thread_pool_min != -1 || iothread->thread_pool_max != -1) { + if (iothread->thread_pool_min != -1 || iothread->thread_pool_max != -1) needsThreadPoolCap = true; - break; + + /* poll-weight requires QEMU_CAPS_IOTHREAD_POLL_WEIGHT */ + if (iothread->set_poll_weight && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_IOTHREAD_POLL_WEIGHT)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("poll-weight is not supported by this QEMU binary")); + return -1; } } diff --git a/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-11.0.0.err b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-11.0.0.err new file mode 100644 index 0000000000..1cc4109f27 --- /dev/null +++ b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-11.0.0.err @@ -0,0 +1 @@ +unsupported configuration: poll-weight is not supported by this QEMU binary diff --git a/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.args b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.args new file mode 100644 index 0000000000..d73060ad46 --- /dev/null +++ b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.args @@ -0,0 +1,40 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine q35,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m size=219136k \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \ +-overcommit mem-lock=off \ +-smp 4,sockets=4,cores=1,threads=1 \ +-object '{"qom-type":"iothread","id":"iothread1","poll-max-ns":123000,"poll-grow":456,"poll-shrink":789,"poll-weight":3}' \ +-object '{"qom-type":"iothread","id":"iothread2","poll-weight":0}' \ +-object '{"qom-type":"iothread","id":"iothread3","poll-max-ns":32000,"poll-weight":63}' \ +-object '{"qom-type":"iothread","id":"iothread4","poll-max-ns":32000,"poll-grow":2,"poll-shrink":2}' \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=@mon-fd@,server=on,wait=off \ +-object '{"qom-type":"monitor-qmp","id":"monitor","chardev":"charmonitor"}' \ +-rtc base=utc \ +-no-shutdown \ +-boot strict=on \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \ +-device '{"driver":"qemu-xhci","id":"usb","bus":"pci.1","addr":"0x0"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-global ICH9-LPC.noreboot=off \ +-watchdog-action reset \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.xml b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.xml new file mode 100644 index 0000000000..1134d9ffdd --- /dev/null +++ b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.x86_64-latest.xml @@ -0,0 +1,58 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>4</vcpu> + <iothreads>4</iothreads> + <iothreadids> + <iothread id='1'> + <poll max='123000' grow='456' shrink='789' weight='3'/> + </iothread> + <iothread id='2'> + <poll weight='0'/> + </iothread> + <iothread id='3'> + <poll max='32000' weight='63'/> + </iothread> + <iothread id='4'> + <poll max='32000' grow='2' shrink='2'/> + </iothread> + </iothreadids> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='usb' index='0' model='qemu-xhci'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/iothreads-ids-poll-weight.xml b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.xml new file mode 100644 index 0000000000..1134d9ffdd --- /dev/null +++ b/tests/qemuxmlconfdata/iothreads-ids-poll-weight.xml @@ -0,0 +1,58 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>4</vcpu> + <iothreads>4</iothreads> + <iothreadids> + <iothread id='1'> + <poll max='123000' grow='456' shrink='789' weight='3'/> + </iothread> + <iothread id='2'> + <poll weight='0'/> + </iothread> + <iothread id='3'> + <poll max='32000' weight='63'/> + </iothread> + <iothread id='4'> + <poll max='32000' grow='2' shrink='2'/> + </iothread> + </iothreadids> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='usb' index='0' model='qemu-xhci'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <watchdog model='itco' action='reset'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index df0b257cbe..682aaad74f 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -2333,6 +2333,8 @@ mymain(void) DO_TEST_CAPS_LATEST("iothreads-ids"); DO_TEST_CAPS_LATEST("iothreads-ids-partial"); DO_TEST_CAPS_LATEST("iothreads-ids-pool-sizes"); + DO_TEST_CAPS_LATEST("iothreads-ids-poll-weight"); + DO_TEST_CAPS_VER_PARSE_ERROR("iothreads-ids-poll-weight", "11.0.0"); DO_TEST_CAPS_LATEST("iothreads-disk"); DO_TEST_CAPS_LATEST("iothreads-virtio-scsi-pci"); DO_TEST_CAPS_LATEST("iothreads-virtio-scsi-mapping"); -- 2.54.0
Add virsh support for configuring and reporting iothread poll-weight. Document poll-weight in the virsh manpage and extend iothreadset so that poll-weight can be configured from the command line. Also add poll-weight support to the test driver and extend virshtest accordingly. Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- docs/manpages/virsh.rst | 18 ++++++++++++------ src/test/test_driver.c | 12 ++++++++++++ tests/virshtestdata/iothreads.in | 2 ++ tests/virshtestdata/iothreads.out | 18 ++++++++++++++++++ tools/virsh-domain.c | 18 ++++++++++++++++++ 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index a10d29e0ea..24052d0cdb 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -2905,6 +2905,8 @@ not available for statistical purposes. growth is managed by the hypervisor. * ``iothread.<id>.poll-shrink`` - polling time shrink value. A value of (zero) indicates shrink is managed by hypervisor. +* ``iothread.<id>.poll-weight`` - polling weight shift value. A value of 0 + (zero) indicates the hypervisor's default weight is used. *--memory* returns: @@ -3498,8 +3500,8 @@ iothreadset :: iothreadset domain iothread_id [[--poll-max-ns ns] [--poll-grow factor] - [--poll-shrink divisor] [--thread-pool-min value] - [--thread-pool-max value]] + [--poll-shrink divisor] [--poll-weight factor] + [--thread-pool-min value] [--thread-pool-max value]] [[--config] [--live] | [--current]] Modifies an existing iothread of the domain using the specified @@ -3511,10 +3513,14 @@ reach the maximum polling time. If a 0 (zero) is provided, then the default factor will be used. The *--poll-shrink* is the quotient by which the current polling time will be reduced in order to get below the maximum polling interval. If a 0 (zero) is provided, then -the default quotient will be used. The polling values are purely dynamic -for a running guest. Saving, destroying, stopping, etc. the guest will -result in the polling values returning to hypervisor defaults at the -next start, restore, etc. +the default quotient will be used. The *--poll-weight* sets the weight +shift value for adaptive polling, determining how much the most recent +event interval affects the next polling duration calculation. Larger +values reduce the weight of recent events. Valid range is [0, 63]. +If omitted or set to 0, the hypervisor selects a default. +The polling values are purely dynamic for a running guest. Saving, +destroying, stopping, etc. the guest will result in the polling values +returning to hypervisor defaults at the next start, restore, etc. The *--thread-pool-min* and *--thread-pool-max* options then set lower and upper bound, respectively of number of threads in worker pool of given diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 536e291861..8546c3e251 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -189,6 +189,7 @@ struct _testIOThreadInfo { unsigned long long poll_max_ns; unsigned int poll_grow; unsigned int poll_shrink; + unsigned int poll_weight; }; static void @@ -749,6 +750,7 @@ testDomainGenerateIOThreadInfos(virDomainObj *obj) iothread.poll_max_ns = 32768; iothread.poll_grow = 0; iothread.poll_shrink = 0; + iothread.poll_weight = 0; g_array_append_val(priv->iothreads, iothread); } } @@ -9681,6 +9683,7 @@ testDomainAddIOThread(virDomainPtr dom, iothread.poll_max_ns = 32768; iothread.poll_grow = 0; iothread.poll_shrink = 0; + iothread.poll_weight = 0; g_array_append_val(priv->iothreads, iothread); @@ -9795,6 +9798,8 @@ testDomainIOThreadParseParams(virTypedParameterPtr params, VIR_TYPED_PARAM_UINT, VIR_DOMAIN_IOTHREAD_POLL_SHRINK, VIR_TYPED_PARAM_UINT, + VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, + VIR_TYPED_PARAM_UINT, NULL) < 0) return -1; @@ -9813,6 +9818,11 @@ testDomainIOThreadParseParams(virTypedParameterPtr params, &iothread->poll_shrink) < 0) return -1; + if (virTypedParamsGetUInt(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, + &iothread->poll_weight) < 0) + return -1; + return 0; } @@ -9899,6 +9909,8 @@ testDomainGetStatsIOThread(virDomainObj *dom, "iothread.%u.poll-grow", iothread.iothread_id); virTypedParamListAddUInt(params, iothread.poll_shrink, "iothread.%u.poll-shrink", iothread.iothread_id); + virTypedParamListAddUInt(params, iothread.poll_weight, + "iothread.%u.poll-weight", iothread.iothread_id); } return 0; diff --git a/tests/virshtestdata/iothreads.in b/tests/virshtestdata/iothreads.in index 25ebcb5cda..b5aed83bba 100644 --- a/tests/virshtestdata/iothreads.in +++ b/tests/virshtestdata/iothreads.in @@ -7,6 +7,8 @@ iothreadinfo --domain fc4 domstats --domain fc4 iothreadset --domain fc4 --id 6 --poll-max-ns 100 --poll-shrink 10 --poll-grow 10 domstats --domain fc4 +iothreadset --domain fc4 --id 6 --poll-weight 3 +domstats --domain fc4 iothreadadd --domain fc5 --id 2 iothreadinfo --domain fc5 diff --git a/tests/virshtestdata/iothreads.out b/tests/virshtestdata/iothreads.out index 1e38733bcf..a51593d765 100644 --- a/tests/virshtestdata/iothreads.out +++ b/tests/virshtestdata/iothreads.out @@ -23,9 +23,11 @@ Domain: 'fc4' iothread.4.poll-max-ns=32768 iothread.4.poll-grow=0 iothread.4.poll-shrink=0 + iothread.4.poll-weight=0 iothread.6.poll-max-ns=32768 iothread.6.poll-grow=0 iothread.6.poll-shrink=0 + iothread.6.poll-weight=0 Domain: 'fc4' @@ -35,9 +37,25 @@ Domain: 'fc4' iothread.4.poll-max-ns=32768 iothread.4.poll-grow=0 iothread.4.poll-shrink=0 + iothread.4.poll-weight=0 iothread.6.poll-max-ns=100 iothread.6.poll-grow=10 iothread.6.poll-shrink=10 + iothread.6.poll-weight=0 + + +Domain: 'fc4' + state.state=1 + state.reason=0 + iothread.count=2 + iothread.4.poll-max-ns=32768 + iothread.4.poll-grow=0 + iothread.4.poll-shrink=0 + iothread.4.poll-weight=0 + iothread.6.poll-max-ns=100 + iothread.6.poll-grow=10 + iothread.6.poll-shrink=10 + iothread.6.poll-weight=3 IOThread ID CPU Affinity diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index aa4f2a7a48..2e4923283b 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -8270,6 +8270,11 @@ static const vshCmdOptDef opts_iothreadset[] = { .unwanted_positional = true, .help = N_("set the value for reduction of the IOThread polling time") }, + {.name = "poll-weight", + .type = VSH_OT_INT, + .unwanted_positional = true, + .help = N_("set the adaptive polling weight factor") + }, {.name = "thread-pool-min", .type = VSH_OT_INT, .unwanted_positional = true, @@ -8299,6 +8304,7 @@ cmdIOThreadSet(vshControl *ctl, const vshCmd *cmd) virTypedParameterPtr par; size_t npar = 0; unsigned long long poll_val; + unsigned int poll_weight; int thread_val; int rc; @@ -8335,6 +8341,18 @@ cmdIOThreadSet(vshControl *ctl, const vshCmd *cmd) if (rc > 0) virTypedParamListAddUnsigned(params, poll_val, VIR_DOMAIN_IOTHREAD_POLL_SHRINK); + if ((rc = vshCommandOptUInt(ctl, cmd, "poll-weight", &poll_weight)) < 0) + return false; + if (rc > 0) { + if (poll_weight > 63) { + vshError(ctl, _("poll-weight value %1$u is out of range [0, 63]"), + poll_weight); + return false; + } + + virTypedParamListAddUInt(params, poll_weight, VIR_DOMAIN_IOTHREAD_POLL_WEIGHT); + } + if ((rc = vshCommandOptInt(ctl, cmd, "thread-pool-min", &thread_val)) < 0) return false; if (rc > 0) -- 2.54.0
Fix three pre-existing typos in the iothread poll sub-element description: - Remove spurious 'with' in 'poll with can be used to' - Add missing closing ')' after the poll-grow/shrink '0' note - Fix typo 'extensive' -> 'excessive' Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- docs/formatdomain.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index a861f9f177..3ba981422f 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -842,13 +842,13 @@ 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` - :since:`Since 9.4.0` an optional sub-element ``poll`` with can be used to + :since:`Since 9.4.0` an optional sub-element ``poll`` can be used to override the hypervisor-default interval of polling for the iothread before it switches back to events. The optional attribute ``max`` sets the maximum time polling should be used in nanoseconds. Setting ``max`` to ``0`` disables polling. Attributes ``grow`` and ``shrink`` override (or disable when set to - ``0`` the default steps for increasing/decreasing the polling interval if - the set interval is deemed insufficient or extensive. + ``0``) the default steps for increasing/decreasing the polling interval if + the set interval is deemed insufficient or excessive. ``defaultiothread`` This element represents the default event loop within hypervisor, where I/O requests from devices not assigned to a specific IOThread are processed. -- 2.54.0
Document the iothread poll-weight XML attribute in formatdomain. Extend the description of iothread polling controls to cover the new poll-weight attribute and how it relates to the existing poll-max, poll-grow, and poll-shrink settings. Also document the accepted range and the meaning of zero as a request for the hypervisor default. Signed-off-by: Jaehoon Kim <jhkim@linux.ibm.com> --- docs/formatdomain.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 3ba981422f..b173fc897b 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -815,7 +815,7 @@ host/guest with many LUNs. :since:`Since 1.2.8 (QEMU only)` <iothread id="4"/> <iothread id="6"/> <iothread id="8" thread_pool_min="2" thread_pool_max="32"> - <poll max='123' grow='456' shrink='789'/> + <poll max='123' grow='456' shrink='789' weight='3'/> </iothread> </iothreadids> <defaultiothread thread_pool_min="8" thread_pool_max="16"/> @@ -849,6 +849,12 @@ host/guest with many LUNs. :since:`Since 1.2.8 (QEMU only)` polling. Attributes ``grow`` and ``shrink`` override (or disable when set to ``0``) the default steps for increasing/decreasing the polling interval if the set interval is deemed insufficient or excessive. + :since:`Since 12.6.0` the optional attribute ``weight`` sets the shift value + for the adaptive polling algorithm, controlling how much the most recent + event interval affects the next polling duration calculation. Larger values + decrease the weight of recent events, producing more gradual adjustments. + Valid range is ``[0, 63]``. Setting ``weight`` to ``0`` lets the hypervisor + select its default value. ``defaultiothread`` This element represents the default event loop within hypervisor, where I/O requests from devices not assigned to a specific IOThread are processed. -- 2.54.0
participants (1)
-
Jaehoon Kim