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 <[email protected]> --- 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
