[libvirt] [PATCH 00/11] Allow modification of IOThread polling values (redux)

This series attempts to resurrect the concept of being able to modify the IOThread polling parameters; however, in a slightly different manner than the previous series posted by posted by Pavel Hrdina <phrdina@redhat.com>: https://www.redhat.com/archives/libvir-list/2017-February/msg01047.html The work is prompted by continued pleas found in the bz: https://bugzilla.redhat.com/show_bug.cgi?id=1545732 to provide some way to modify the paremters without needing to supply QEMU command line pass through values. It's accepted that the values being changed are fairly or extremely low level type knobs; however, it's also shown that by being able to turn the knob it is possible for certain, specific appliances to be able to gain a performance benefit for the thread at the expense of other competing threads. Unlike the previous series, this series does not attempt to save the polling values in the guest XML. Rather, it only modifies the live guest's IOThread with new values. It also doesn't provide the polling values in a virsh iothread* command, rather it uses the domstats in order to fetch and display the values. The theory being this leaves the onus on the higher level appliance/application to provide the "proper guidance" and "concerns" related to changing the values to the consumer. Not saving the values means whatever values that are chosen do not "live" in perpetuity. Once the guest is shut down or the IOThread removed from guest, the hypervisor default values take over again. Perhaps not a perfect situation in terms of what the bz requests; however, storage of default values that could cause performance issues is not an optimal situation. So this I figured is a "comprimise" of sorts. If it's still felt that no we don't want to do this, then fine, but please in doing so own the bz, state your case, and close it. I'm 50/50 on it, but figured at least I'd present this option and see what the concensus was. John Ferlan (11): qemu: Check for and return IOThread polling values if available qemu: Split qemuDomainGetIOThreadsLive qemu: Implement the ability to return IOThread stats virsh: Add ability to display IOThread stats lib: Introduce virDomainSetIOThreadParams qemu: Add monitor functions to set IOThread params qemu: Alter qemuDomainChgIOThread to take enum instead of bool qemu: Alter qemuDomainChgIOThread to take qemuMonitorIOThreadInfo qemu: Detect whether iothread polling is supported qemu: Introduce qemuDomainSetIOThreadParams tools: Add virsh iothreadset command include/libvirt/libvirt-domain.h | 45 ++ src/driver-hypervisor.h | 8 + src/libvirt-domain.c | 109 +++++ src/libvirt_public.syms | 5 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_driver.c | 393 ++++++++++++++++-- src/qemu/qemu_monitor.c | 19 + src/qemu/qemu_monitor.h | 6 + src/qemu/qemu_monitor_json.c | 48 +++ src/qemu/qemu_monitor_json.h | 4 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 +- src/remote_protocol-structs | 10 + .../caps_2.10.0.aarch64.xml | 1 + .../caps_2.10.0.ppc64.xml | 1 + .../caps_2.10.0.s390x.xml | 1 + .../caps_2.10.0.x86_64.xml | 1 + .../caps_2.11.0.s390x.xml | 1 + .../caps_2.11.0.x86_64.xml | 1 + .../caps_2.12.0.aarch64.xml | 1 + .../caps_2.12.0.ppc64.xml | 1 + .../caps_2.12.0.s390x.xml | 1 + .../caps_2.12.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + .../caps_2.9.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.ppc64.xml | 1 + .../caps_3.0.0.riscv32.xml | 1 + .../caps_3.0.0.riscv64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + .../caps_3.0.0.x86_64.xml | 1 + tools/virsh-domain-monitor.c | 7 + tools/virsh-domain.c | 110 +++++ tools/virsh.pod | 47 ++- 35 files changed, 810 insertions(+), 44 deletions(-) -- 2.17.1

If there are IOThread polling values in the query-iothreads return buffer, then fill them in and set a bool indicating their presence. This will allow for displaying in a domain stats output eventually. Note that the QEMU values are managed a bit differently (as int's stored in int64_t's) than we will manage them (as unsigned long and int values). This is intentional to allow for value validation checking when it comes time to provide the values to QEMU. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.h | 4 ++++ src/qemu/qemu_monitor_json.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 48b142a4f4..c2991e2b16 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1116,6 +1116,10 @@ typedef qemuMonitorIOThreadInfo *qemuMonitorIOThreadInfoPtr; struct _qemuMonitorIOThreadInfo { unsigned int iothread_id; int thread_id; + bool poll_valid; + unsigned long long poll_max_ns; + unsigned int poll_grow; + unsigned int poll_shrink; }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 3de298c9e2..2e92984b44 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7441,6 +7441,21 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, "'thread-id' data")); goto cleanup; } + + /* Fetch poll values (since QEMU 2.9 ) if available. QEMU + * stores these values as int64_t's; however, the qapi type + * is an int. The qapi/misc.json also mis-describes the grow + * and shrink values as pure add/remove values. The source + * util/aio-posix.c function aio_poll uses them as a factor + * or divisor in it's calculation. We will fetch and store + * them as defined in our structures. */ + if (virJSONValueObjectGetNumberUlong(child, "poll-max-ns", + &info->poll_max_ns) == 0 && + virJSONValueObjectGetNumberUint(child, "poll-grow", + &info->poll_grow) == 0 && + virJSONValueObjectGetNumberUint(child, "poll-shrink", + &info->poll_shrink) == 0) + info->poll_valid = true; } ret = n; -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
If there are IOThread polling values in the query-iothreads return buffer, then fill them in and set a bool indicating their presence. This will allow for displaying in a domain stats output eventually.
Note that the QEMU values are managed a bit differently (as int's stored in int64_t's) than we will manage them (as unsigned long and int values). This is intentional to allow for value validation checking when it comes time to provide the values to QEMU.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.h | 4 ++++ src/qemu/qemu_monitor_json.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+)
ACK Michal

Separate out the fetch of the IOThread monitor call into a separate helper so that a subsequent domain statistics change can fetch the raw IOThread data and parse it as it sees fit. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 59 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ef87a6ef05..e0edb43557 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5486,20 +5486,18 @@ qemuDomainGetMaxVcpus(virDomainPtr dom) VIR_DOMAIN_VCPU_MAXIMUM)); } + static int -qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainIOThreadInfoPtr **info) +qemuDomainGetIOThreadsMon(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuMonitorIOThreadInfoPtr **iothreads) { qemuDomainObjPrivatePtr priv; - qemuMonitorIOThreadInfoPtr *iothreads = NULL; - virDomainIOThreadInfoPtr *info_ret = NULL; int niothreads = 0; - size_t i; int ret = -1; if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) - goto cleanup; + return -1; if (!virDomainObjIsActive(vm)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", @@ -5515,46 +5513,57 @@ qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, } qemuDomainObjEnterMonitor(driver, vm); - niothreads = qemuMonitorGetIOThreads(priv->mon, &iothreads); - if (qemuDomainObjExitMonitor(driver, vm) < 0) - goto endjob; - if (niothreads < 0) + niothreads = qemuMonitorGetIOThreads(priv->mon, iothreads); + if (qemuDomainObjExitMonitor(driver, vm) < 0 || niothreads < 0) goto endjob; - /* Nothing to do */ - if (niothreads == 0) { - ret = 0; - goto endjob; - } + ret = niothreads; + + endjob: + qemuDomainObjEndJob(driver, vm); + + return ret; +} + + +static int +qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainIOThreadInfoPtr **info) +{ + qemuMonitorIOThreadInfoPtr *iothreads = NULL; + virDomainIOThreadInfoPtr *info_ret = NULL; + int niothreads; + size_t i; + int ret = -1; + + if ((niothreads = qemuDomainGetIOThreadsMon(driver, vm, &iothreads)) <= 0) + return niothreads; if (VIR_ALLOC_N(info_ret, niothreads) < 0) - goto endjob; + goto cleanup; for (i = 0; i < niothreads; i++) { virBitmapPtr map = NULL; if (VIR_ALLOC(info_ret[i]) < 0) - goto endjob; + goto cleanup; info_ret[i]->iothread_id = iothreads[i]->iothread_id; if (!(map = virProcessGetAffinity(iothreads[i]->thread_id))) - goto endjob; + goto cleanup; if (virBitmapToData(map, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen) < 0) { virBitmapFree(map); - goto endjob; + goto cleanup; } virBitmapFree(map); } - *info = info_ret; - info_ret = NULL; + VIR_STEAL_PTR(*info, info_ret); ret = niothreads; - endjob: - qemuDomainObjEndJob(driver, vm); - cleanup: if (info_ret) { for (i = 0; i < niothreads; i++) -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Separate out the fetch of the IOThread monitor call into a separate helper so that a subsequent domain statistics change can fetch the raw IOThread data and parse it as it sees fit.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 59 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 25 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ef87a6ef05..e0edb43557 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5486,20 +5486,18 @@ qemuDomainGetMaxVcpus(virDomainPtr dom) VIR_DOMAIN_VCPU_MAXIMUM)); }
+ static int -qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainIOThreadInfoPtr **info) +qemuDomainGetIOThreadsMon(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuMonitorIOThreadInfoPtr **iothreads) { qemuDomainObjPrivatePtr priv; - qemuMonitorIOThreadInfoPtr *iothreads = NULL; - virDomainIOThreadInfoPtr *info_ret = NULL; int niothreads = 0; - size_t i; int ret = -1;
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) - goto cleanup; + return -1;
if (!virDomainObjIsActive(vm)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", @@ -5515,46 +5513,57 @@ qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, }
qemuDomainObjEnterMonitor(driver, vm); - niothreads = qemuMonitorGetIOThreads(priv->mon, &iothreads); - if (qemuDomainObjExitMonitor(driver, vm) < 0) - goto endjob; - if (niothreads < 0) + niothreads = qemuMonitorGetIOThreads(priv->mon, iothreads); + if (qemuDomainObjExitMonitor(driver, vm) < 0 || niothreads < 0) goto endjob;
- /* Nothing to do */ - if (niothreads == 0) { - ret = 0; - goto endjob; - } + ret = niothreads; + + endjob: + qemuDomainObjEndJob(driver, vm); + + return ret; +} + + +static int +qemuDomainGetIOThreadsLive(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainIOThreadInfoPtr **info) +{ + qemuMonitorIOThreadInfoPtr *iothreads = NULL; + virDomainIOThreadInfoPtr *info_ret = NULL; + int niothreads; + size_t i; + int ret = -1; + + if ((niothreads = qemuDomainGetIOThreadsMon(driver, vm, &iothreads)) <= 0) + return niothreads;
if (VIR_ALLOC_N(info_ret, niothreads) < 0) - goto endjob; + goto cleanup;
for (i = 0; i < niothreads; i++) { virBitmapPtr map = NULL;
if (VIR_ALLOC(info_ret[i]) < 0) - goto endjob; + goto cleanup; info_ret[i]->iothread_id = iothreads[i]->iothread_id;
if (!(map = virProcessGetAffinity(iothreads[i]->thread_id))) - goto endjob; + goto cleanup;
I don't think this is a good idea. GetAffinity should be inside job too. SetAffinity call inside PinIOThread is inside one. Probably doesn't hurt us right now since the domain object is locked here, but regardless I think it should be inside a job. The split into two functions looks okay.
if (virBitmapToData(map, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen) < 0) { virBitmapFree(map); - goto endjob; + goto cleanup; } virBitmapFree(map); }
- *info = info_ret; - info_ret = NULL; + VIR_STEAL_PTR(*info, info_ret); ret = niothreads;
- endjob: - qemuDomainObjEndJob(driver, vm); - cleanup: if (info_ret) { for (i = 0; i < niothreads; i++)
Michal

[...]
if (VIR_ALLOC_N(info_ret, niothreads) < 0) - goto endjob; + goto cleanup;
for (i = 0; i < niothreads; i++) { virBitmapPtr map = NULL;
if (VIR_ALLOC(info_ret[i]) < 0) - goto endjob; + goto cleanup; info_ret[i]->iothread_id = iothreads[i]->iothread_id;
if (!(map = virProcessGetAffinity(iothreads[i]->thread_id))) - goto endjob; + goto cleanup;
I don't think this is a good idea. GetAffinity should be inside job too. SetAffinity call inside PinIOThread is inside one. Probably doesn't hurt us right now since the domain object is locked here, but regardless I think it should be inside a job.
The split into two functions looks okay.
OK - I'll move the job logic back inside here and just have the Mon logic do the magic fetch. I was attempting to use a mix of the Block and Interface logic and missed the detail regarding it being run in a job 0-). Thanks! John
if (virBitmapToData(map, &info_ret[i]->cpumap, &info_ret[i]->cpumaplen) < 0) { virBitmapFree(map); - goto endjob; + goto cleanup; } virBitmapFree(map); }
- *info = info_ret; - info_ret = NULL; + VIR_STEAL_PTR(*info, info_ret); ret = niothreads;
- endjob: - qemuDomainObjEndJob(driver, vm); - cleanup: if (info_ret) { for (i = 0; i < niothreads; i++)
Michal

Process the IOThreads polling stats if available. Generate the output params record to be returned to the caller with the three values - poll-max-ns, poll-grow, and poll-shrink. Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 38 ++++++++++++++++ src/qemu/qemu_driver.c | 78 ++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index fdd2d6b8ea..58fd4bc10c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2048,6 +2048,7 @@ typedef enum { VIR_DOMAIN_STATS_INTERFACE = (1 << 4), /* return domain interfaces info */ VIR_DOMAIN_STATS_BLOCK = (1 << 5), /* return domain block info */ VIR_DOMAIN_STATS_PERF = (1 << 6), /* return domain perf event info */ + VIR_DOMAIN_STATS_IOTHREAD = (1 << 7), /* return iothread poll info */ } virDomainStatsTypes; typedef enum { diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 7690339521..9fda56d660 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11499,6 +11499,44 @@ virConnectGetDomainCapabilities(virConnectPtr conn, * long long. It is produced by the * emulation_faults perf event * + * VIR_DOMAIN_STATS_IOTHREAD: + * Return IOThread statistics if available. IOThread polling is a + * timing mechanism that allows the hypervisor to generate a longer + * period of time in which the guest will perform operations on the + * CPU being used by the IOThread. The higher the value for poll-max-ns + * the longer the guest will keep the CPU. This may affect other host + * threads using the CPU. The poll-grow and poll-shrink values allow + * the hypervisor to generate a mechanism to add or remove polling time + * within the confines of 0 and poll-max-ns. For QEMU, the poll-grow is + * multiplied by the polling interval, while poll-shrink is used as a + * divisor. When not provided, QEMU may double the polling time until + * poll-max-ns is reached. When poll-shrink is 0 (zero) QEMU may reset + * the polling interval to 0 until it finds its "sweet spot". Setting + * poll-grow too large may cause frequent fluctution of the time; however, + * this can be tempered by a high poll-shrink to reduce the polling + * interval. For example, a poll-grow of 3 will triple the polling time + * which could quickly exceed poll-max-ns; however, a poll-shrink of + * 10 would cut that polling time more gradually. + * + * The typed parameter keys are in this format: + * + * "iothread.cnt" - maximum number of IOThreads in the subsequent list + * as unsigned int. Each IOThread in the list will + * will use it's iothread_id value as the <id>. There + * may be fewer <id> entries than the iothread.cnt + * value if the polling values are not supported. + * "iothread.<id>.poll-max-ns" - maximum polling time in ns as an unsigned + * long long. A 0 (zero) means polling is + * disabled. + * "iothread.<id>.poll-grow" - polling time factor as an unsigned int. + * A 0 (zero) indicates to allow the underlying + * hypervisor to choose how to grow the + * polling time. + * "iothread.<id>.poll-shrink" - polling time divisor as an unsigned int. + * A 0 (zero) indicates to allow the underlying + * hypervisor to choose how to shrink the + * polling time. + * * Note that entire stats groups or individual stat fields may be missing from * the output in case they are not supported by the given hypervisor, are not * applicable for the current state of the guest domain, or their retrieval diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e0edb43557..ff87865fe6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20431,6 +20431,83 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver, #undef QEMU_ADD_NAME_PARAM +#define QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, id, name, value) \ + do { \ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ + "block.%u.%s", id, name); \ + if (virTypedParamsAddUInt(&(record)->params, \ + &(record)->nparams, \ + maxparams, \ + param_name, \ + value) < 0) \ + goto cleanup; \ + } while (0) + +#define QEMU_ADD_IOTHREAD_PARAM_ULL(record, maxparams, id, name, value) \ +do { \ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ + "iothread.%u.%s", id, name); \ + if (virTypedParamsAddULLong(&(record)->params, \ + &(record)->nparams, \ + maxparams, \ + param_name, \ + value) < 0) \ + goto cleanup; \ +} while (0) + +static int +qemuDomainGetStatsIOThread(virQEMUDriverPtr driver, + virDomainObjPtr dom, + virDomainStatsRecordPtr record, + int *maxparams, + unsigned int privflags ATTRIBUTE_UNUSED) +{ + size_t i; + qemuMonitorIOThreadInfoPtr *iothreads = NULL; + int niothreads; + int ret = -1; + + if ((niothreads = qemuDomainGetIOThreadsMon(driver, dom, &iothreads)) < 0) + return -1; + + if (niothreads == 0) + return 0; + + QEMU_ADD_COUNT_PARAM(record, maxparams, "iothread", niothreads); + + for (i = 0; i < niothreads; i++) { + if (iothreads[i]->poll_valid) { + QEMU_ADD_IOTHREAD_PARAM_ULL(record, maxparams, + iothreads[i]->iothread_id, + "poll-max-ns", + iothreads[i]->poll_max_ns); + QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, + iothreads[i]->iothread_id, + "poll-grow", + iothreads[i]->poll_grow); + QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, + iothreads[i]->iothread_id, + "poll-shrink", + iothreads[i]->poll_shrink); + } + } + + ret = 0; + + cleanup: + for (i = 0; i < niothreads; i++) + VIR_FREE(iothreads[i]); + VIR_FREE(iothreads); + + return ret; +} + +#undef QEMU_ADD_IOTHREAD_PARAM_UI + +#undef QEMU_ADD_IOTHREAD_PARAM_ULL + #undef QEMU_ADD_COUNT_PARAM static int @@ -20505,6 +20582,7 @@ static struct qemuDomainGetStatsWorker qemuDomainGetStatsWorkers[] = { { qemuDomainGetStatsInterface, VIR_DOMAIN_STATS_INTERFACE, false }, { qemuDomainGetStatsBlock, VIR_DOMAIN_STATS_BLOCK, true }, { qemuDomainGetStatsPerf, VIR_DOMAIN_STATS_PERF, false }, + { qemuDomainGetStatsIOThread, VIR_DOMAIN_STATS_IOTHREAD, false }, { NULL, 0, false } }; -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Process the IOThreads polling stats if available. Generate the output params record to be returned to the caller with the three values - poll-max-ns, poll-grow, and poll-shrink.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 38 ++++++++++++++++ src/qemu/qemu_driver.c | 78 ++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index fdd2d6b8ea..58fd4bc10c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2048,6 +2048,7 @@ typedef enum { VIR_DOMAIN_STATS_INTERFACE = (1 << 4), /* return domain interfaces info */ VIR_DOMAIN_STATS_BLOCK = (1 << 5), /* return domain block info */ VIR_DOMAIN_STATS_PERF = (1 << 6), /* return domain perf event info */ + VIR_DOMAIN_STATS_IOTHREAD = (1 << 7), /* return iothread poll info */ } virDomainStatsTypes;
typedef enum { diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 7690339521..9fda56d660 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11499,6 +11499,44 @@ virConnectGetDomainCapabilities(virConnectPtr conn, * long long. It is produced by the * emulation_faults perf event * + * VIR_DOMAIN_STATS_IOTHREAD: + * Return IOThread statistics if available. IOThread polling is a + * timing mechanism that allows the hypervisor to generate a longer + * period of time in which the guest will perform operations on the + * CPU being used by the IOThread. The higher the value for poll-max-ns + * the longer the guest will keep the CPU. This may affect other host + * threads using the CPU. The poll-grow and poll-shrink values allow + * the hypervisor to generate a mechanism to add or remove polling time + * within the confines of 0 and poll-max-ns. For QEMU, the poll-grow is + * multiplied by the polling interval, while poll-shrink is used as a + * divisor. When not provided, QEMU may double the polling time until + * poll-max-ns is reached. When poll-shrink is 0 (zero) QEMU may reset + * the polling interval to 0 until it finds its "sweet spot". Setting + * poll-grow too large may cause frequent fluctution of the time; however, + * this can be tempered by a high poll-shrink to reduce the polling + * interval. For example, a poll-grow of 3 will triple the polling time + * which could quickly exceed poll-max-ns; however, a poll-shrink of + * 10 would cut that polling time more gradually. + * + * The typed parameter keys are in this format: + * + * "iothread.cnt" - maximum number of IOThreads in the subsequent list + * as unsigned int. Each IOThread in the list will + * will use it's iothread_id value as the <id>. There + * may be fewer <id> entries than the iothread.cnt + * value if the polling values are not supported. + * "iothread.<id>.poll-max-ns" - maximum polling time in ns as an unsigned + * long long. A 0 (zero) means polling is + * disabled. + * "iothread.<id>.poll-grow" - polling time factor as an unsigned int. + * A 0 (zero) indicates to allow the underlying + * hypervisor to choose how to grow the + * polling time. + * "iothread.<id>.poll-shrink" - polling time divisor as an unsigned int. + * A 0 (zero) indicates to allow the underlying + * hypervisor to choose how to shrink the + * polling time. + * * Note that entire stats groups or individual stat fields may be missing from * the output in case they are not supported by the given hypervisor, are not * applicable for the current state of the guest domain, or their retrieval diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e0edb43557..ff87865fe6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20431,6 +20431,83 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
#undef QEMU_ADD_NAME_PARAM
+#define QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, id, name, value) \ + do { \ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ + "block.%u.%s", id, name); \
s/block/iothread/
+ if (virTypedParamsAddUInt(&(record)->params, \ + &(record)->nparams, \ + maxparams, \ + param_name, \ + value) < 0) \ + goto cleanup; \ + } while (0) + +#define QEMU_ADD_IOTHREAD_PARAM_ULL(record, maxparams, id, name, value) \ +do { \ + char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \ + snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \ + "iothread.%u.%s", id, name); \ + if (virTypedParamsAddULLong(&(record)->params, \ + &(record)->nparams, \ + maxparams, \ + param_name, \ + value) < 0) \ + goto cleanup; \ +} while (0) + +static int +qemuDomainGetStatsIOThread(virQEMUDriverPtr driver, + virDomainObjPtr dom, + virDomainStatsRecordPtr record, + int *maxparams, + unsigned int privflags ATTRIBUTE_UNUSED) +{ + size_t i; + qemuMonitorIOThreadInfoPtr *iothreads = NULL; + int niothreads; + int ret = -1;
This MUST have the check for job - it is talking to a monitor and therefore @dom is locked and unlocked meanwhile. You can take a look at qemuDomainGetStatsBlock() what the check should look like.
+ + if ((niothreads = qemuDomainGetIOThreadsMon(driver, dom, &iothreads)) < 0) + return -1;
Worse, since you moved acquiring the job here, this will fail miserably when running all stats for a domain. Because the code works like this: 1) it calls qemuDomainGetStatsNeedMonitor() to figure out if monitor is needed and if it is a job is started, 2) it iterate over all stats callbacks, 3) this function is reached which tries to set the job again.
+ + if (niothreads == 0) + return 0; + + QEMU_ADD_COUNT_PARAM(record, maxparams, "iothread", niothreads); + + for (i = 0; i < niothreads; i++) { + if (iothreads[i]->poll_valid) { + QEMU_ADD_IOTHREAD_PARAM_ULL(record, maxparams, + iothreads[i]->iothread_id, + "poll-max-ns", + iothreads[i]->poll_max_ns); + QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, + iothreads[i]->iothread_id, + "poll-grow", + iothreads[i]->poll_grow); + QEMU_ADD_IOTHREAD_PARAM_UI(record, maxparams, + iothreads[i]->iothread_id, + "poll-shrink", + iothreads[i]->poll_shrink); + } + } + + ret = 0; + + cleanup: + for (i = 0; i < niothreads; i++) + VIR_FREE(iothreads[i]); + VIR_FREE(iothreads); + + return ret; +} + +#undef QEMU_ADD_IOTHREAD_PARAM_UI + +#undef QEMU_ADD_IOTHREAD_PARAM_ULL + #undef QEMU_ADD_COUNT_PARAM
static int @@ -20505,6 +20582,7 @@ static struct qemuDomainGetStatsWorker qemuDomainGetStatsWorkers[] = { { qemuDomainGetStatsInterface, VIR_DOMAIN_STATS_INTERFACE, false }, { qemuDomainGetStatsBlock, VIR_DOMAIN_STATS_BLOCK, true }, { qemuDomainGetStatsPerf, VIR_DOMAIN_STATS_PERF, false }, + { qemuDomainGetStatsIOThread, VIR_DOMAIN_STATS_IOTHREAD, false },
s/false/true/ The function you're calling does require access to the monitor.
{ NULL, 0, false } };
Michal

Add an --iothread qualifier to domstats and an explanation in the man page. Describe the values in as generic terms as possible allowing each hypervisor to provide a specific algorithm to utilize the values as it sees fit. Signed-off-by: John Ferlan <jferlan@redhat.com> --- tools/virsh-domain-monitor.c | 7 +++++++ tools/virsh.pod | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 3a2636377d..5187c1e248 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -2066,6 +2066,10 @@ static const vshCmdOptDef opts_domstats[] = { .type = VSH_OT_BOOL, .help = N_("report domain perf event statistics"), }, + {.name = "iothread", + .type = VSH_OT_BOOL, + .help = N_("report domain IOThread information"), + }, {.name = "list-active", .type = VSH_OT_BOOL, .help = N_("list only active domains"), @@ -2179,6 +2183,9 @@ cmdDomstats(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "perf")) stats |= VIR_DOMAIN_STATS_PERF; + if (vshCommandOptBool(cmd, "iothread")) + stats |= VIR_DOMAIN_STATS_IOTHREAD; + if (vshCommandOptBool(cmd, "list-active")) flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE; diff --git a/tools/virsh.pod b/tools/virsh.pod index 86c041d575..90f3c1ef5c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -975,7 +975,8 @@ or unique source names printed by this command. =item B<domstats> [I<--raw>] [I<--enforce>] [I<--backing>] [I<--nowait>] [I<--state>] [I<--cpu-total>] [I<--balloon>] [I<--vcpu>] [I<--interface>] -[I<--block>] [I<--perf>] [[I<--list-active>] [I<--list-inactive>] +[I<--block>] [I<--perf>] [I<--iothread>] +[[I<--list-active>] [I<--list-inactive>] [I<--list-persistent>] [I<--list-transient>] [I<--list-running>] [I<--list-paused>] [I<--list-shutoff>] [I<--list-other>]] | [I<domain> ...] @@ -993,7 +994,7 @@ behavior use the I<--raw> flag. The individual statistics groups are selectable via specific flags. By default all supported statistics groups are returned. Supported statistics groups flags are: I<--state>, I<--cpu-total>, I<--balloon>, -I<--vcpu>, I<--interface>, I<--block>, I<--perf>. +I<--vcpu>, I<--interface>, I<--block>, I<--perf>, I<--iothread>. Note that - depending on the hypervisor type and version or the domain state - not all of the following statistics may be returned. @@ -1126,6 +1127,27 @@ Information listed includes: VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD event See domblkthreshold. +I<--iothread> returns information about IOThreads on the running guest +if supported by the hypervisor. + +The "poll-max-ns" for each thread is the maximum nanoseconds to allow +each polling interval to occur. A polling interval is a period of time +allowed for a thread to process data before being the guest gives up +its CPU quantum back to the host. A value set too small will not allow +the IOThread to run long enough on a CPU to process data. A value set +too high will consume too much CPU time per IOThread failing to allow +other threads running on the CPU to get time. The polling interval is +not available for statistical purposes. + + "iothread.<id>.poll-max-ns" - maximum polling time in nanoseconds used + by the <id> IOThread. A value of 0 (zero) + indicates polling is disabled. + "iothread.<id>.poll-grow" - polling time grow value. A value of 0 (zero) + indicates growth is managed by the hypervisor. + "iothread.<id>.poll-shrink" - polling time shrink value. A value of + 0 (zero) indicates shrink is managed by + the hypervisor. + Selecting a specific statistics groups doesn't guarantee that the daemon supports the selected group of stats. Flag I<--enforce> forces the command to fail if the daemon doesn't support the -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Add an --iothread qualifier to domstats and an explanation in the man page. Describe the values in as generic terms as possible allowing each hypervisor to provide a specific algorithm to utilize the values as it sees fit.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- tools/virsh-domain-monitor.c | 7 +++++++ tools/virsh.pod | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-)
ACK Michal

Create a new API that will allow an adjustment of IOThread polling parameters for the specified IOThread. These parameters will not be saved in the guest XML. Currently the only parameters supported will allow the hypervisor to adjust the parameters used to limit and alter the scope of the polling interval. The polling interval allows the IOThread to spend more or less time processing in the guest. Based on code originally posted by Pavel Hrdina <phrdina@redhat.com> to add virDomainAddIOThreadParams and virDomainModIOThreadParams. Modification of those changes to use virDomainSetIOThreadParams instead and remove concepts related to saving the data in guest XML as well as the way to specifically enable the polling parameters. Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 44 ++++++++++++++++++++ src/driver-hypervisor.h | 8 ++++ src/libvirt-domain.c | 71 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 +++++++++- src/remote_protocol-structs | 10 +++++ 7 files changed, 159 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 58fd4bc10c..bf89d0149f 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1911,6 +1911,50 @@ int virDomainDelIOThread(virDomainPtr domain, unsigned int iothread_id, unsigned int flags); +/* IOThread set parameters */ + +/** + * VIR_DOMAIN_IOTHREAD_POLL_MAX_NS: + * + * The maximum polling time that can be used by polling algorithm in ns. + * The polling time starts at 0 (zero) and is the time spent by the guest + * to process IOThread data before returning the CPU to the host. The + * polling time will be dynamically modified over time based on the + * poll_grow and poll_shrink parameters provided. A value set too large + * will cause more CPU time to be allocated the guest. A value set too + * small will not provide enough cycles for the guest to process data. + * The polling interval is not available for statistical purposes. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_MAX_NS "poll_max_ns" + +/** + * VIR_DOMAIN_IOTHREAD_POLL_GROW: + * + * This provides a value for the dynamic polling adjustment algorithm to + * use to grow its polling interval up to the poll_max_ns value. A value + * of 0 (zero) allows the hypervisor to choose its own value. The algorithm + * to use for adjustment is hypervisor specific. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_GROW "poll_grow" + +/** + * VIR_DOMAIN_IOTHREAD_POLL_SHRINK: + * + * This provides a value for the dynamic polling adjustment algorithm to + * use to shrink its polling interval when the polling interval exceeds + * the poll_max_ns value. A value of 0 (zero) allows the hypervisor to + * choose its own value. The algorithm to use for adjustment is hypervisor + * specific. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_SHRINK "poll_shrink" + +int virDomainSetIOThreadParams(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + + /** * VIR_USE_CPU: * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index eef31eb1f0..6be3e175ce 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -406,6 +406,13 @@ typedef int unsigned int iothread_id, unsigned int flags); +typedef int +(*virDrvDomainSetIOThreadParams)(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + typedef int (*virDrvDomainGetSecurityLabel)(virDomainPtr domain, virSecurityLabelPtr seclabel); @@ -1407,6 +1414,7 @@ struct _virHypervisorDriver { virDrvDomainPinIOThread domainPinIOThread; virDrvDomainAddIOThread domainAddIOThread; virDrvDomainDelIOThread domainDelIOThread; + virDrvDomainSetIOThreadParams domainSetIOThreadParams; virDrvDomainGetSecurityLabel domainGetSecurityLabel; virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 9fda56d660..ce5de4b208 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -7812,6 +7812,77 @@ virDomainDelIOThread(virDomainPtr domain, } +/** + * virDomainSetIOThreadParams: + * @domain: a domain object + * @iothread_id: the specific IOThread ID value to add + * @params: pointer to IOThread parameter objects + * @nparams: number of IOThread parameters + * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags + * + * Dynamically set IOThread parameters to the domain. It is left up to + * the underlying virtual hypervisor to determine the valid range for an + * @iothread_id, determining whether the @iothread_id already exists, and + * determining the validity of the provided param values. + * + * See VIR_DOMAIN_IOTHREAD_* for detailed description of accepted IOThread + * parameters. + * + * Since the purpose of this API is to dynamically modify the IOThread + * @flags should only include the VIR_DOMAIN_AFFECT_CURRENT and/or + * VIR_DOMAIN_AFFECT_LIVE virDomainMemoryModFlags. Setting other flags + * may cause errors from the hypervisor. + * + * Note that this call can fail if the underlying virtualization hypervisor + * does not support it or does not support setting the provided values. + * + * This function requires privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virDomainSetIOThreadParams(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "iothread_id=%u, params=%p, nparams=%d, flags=0x%x", + iothread_id, params, nparams, flags); + VIR_TYPED_PARAMS_DEBUG(params, nparams); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNegativeArgGoto(nparams, error); + if (nparams) + virCheckNonNullArgGoto(params, error); + + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->domainSetIOThreadParams) { + int ret; + ret = conn->driver->domainSetIOThreadParams(domain, iothread_id, + params, nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(domain->conn); + return -1; +} + + /** * virDomainGetSecurityLabel: * @domain: a domain object diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index d4cdbd8b32..0a17f6eb90 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -809,4 +809,9 @@ LIBVIRT_4.5.0 { virNWFilterBindingGetFilterName; } LIBVIRT_4.4.0; +LIBVIRT_4.9.0 { + global: + virDomainSetIOThreadParams; +} LIBVIRT_4.5.0; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 3b43e219e5..d045501d86 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8371,6 +8371,7 @@ static virHypervisorDriver hypervisor_driver = { .domainPinIOThread = remoteDomainPinIOThread, /* 1.2.14 */ .domainAddIOThread = remoteDomainAddIOThread, /* 1.2.15 */ .domainDelIOThread = remoteDomainDelIOThread, /* 1.2.15 */ + .domainSetIOThreadParams = remoteDomainSetIOThreadParams, /* 4.9.0 */ .domainGetSecurityLabel = remoteDomainGetSecurityLabel, /* 0.6.1 */ .domainGetSecurityLabelList = remoteDomainGetSecurityLabelList, /* 0.10.0 */ .nodeGetSecurityModel = remoteNodeGetSecurityModel, /* 0.6.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 28c8febabd..7630b2ed15 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -256,6 +256,9 @@ const REMOTE_DOMAIN_IP_ADDR_MAX = 2048; /* Upper limit on number of guest vcpu information entries */ const REMOTE_DOMAIN_GUEST_VCPU_PARAMS_MAX = 64; +/* Upper limit on number of IOThread parameter set entries */ +const REMOTE_DOMAIN_IOTHREAD_PARAMS_MAX = 64; + /* Upper limit on number of SEV parameters */ const REMOTE_NODE_SEV_INFO_MAX = 64; @@ -1249,6 +1252,13 @@ struct remote_domain_del_iothread_args { unsigned int flags; }; +struct remote_domain_set_iothread_params_args { + remote_nonnull_domain dom; + unsigned int iothread_id; + remote_typed_param params<REMOTE_DOMAIN_IOTHREAD_PARAMS_MAX>; + unsigned int flags; +}; + struct remote_domain_get_security_label_args { remote_nonnull_domain dom; }; @@ -6312,5 +6322,14 @@ enum remote_procedure { * @acl: connect:search_nwfilter_bindings * @aclfilter: nwfilter_binding:getattr */ - REMOTE_PROC_CONNECT_LIST_ALL_NWFILTER_BINDINGS = 401 + REMOTE_PROC_CONNECT_LIST_ALL_NWFILTER_BINDINGS = 401, + + /** + * @generate: both + * @acl: domain:write + * @acl: domain:save:!VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE + * @acl: domain:save:VIR_DOMAIN_AFFECT_CONFIG + */ + REMOTE_PROC_DOMAIN_SET_IOTHREAD_PARAMS = 402 + }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 6343e14638..7c27c63542 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -866,6 +866,15 @@ struct remote_domain_del_iothread_args { u_int iothread_id; u_int flags; }; +struct remote_domain_set_iothread_params_args { + remote_nonnull_domain dom; + u_int iothread_id; + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; struct remote_domain_get_security_label_args { remote_nonnull_domain dom; }; @@ -3368,4 +3377,5 @@ enum remote_procedure { REMOTE_PROC_NWFILTER_BINDING_CREATE_XML = 399, REMOTE_PROC_NWFILTER_BINDING_DELETE = 400, REMOTE_PROC_CONNECT_LIST_ALL_NWFILTER_BINDINGS = 401, + REMOTE_PROC_DOMAIN_SET_IOTHREAD_PARAMS = 402, }; -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Create a new API that will allow an adjustment of IOThread polling parameters for the specified IOThread. These parameters will not be saved in the guest XML. Currently the only parameters supported will allow the hypervisor to adjust the parameters used to limit and alter the scope of the polling interval. The polling interval allows the IOThread to spend more or less time processing in the guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com> to add virDomainAddIOThreadParams and virDomainModIOThreadParams. Modification of those changes to use virDomainSetIOThreadParams instead and remove concepts related to saving the data in guest XML as well as the way to specifically enable the polling parameters.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 44 ++++++++++++++++++++ src/driver-hypervisor.h | 8 ++++ src/libvirt-domain.c | 71 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 +++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 +++++++++- src/remote_protocol-structs | 10 +++++ 7 files changed, 159 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 58fd4bc10c..bf89d0149f 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1911,6 +1911,50 @@ int virDomainDelIOThread(virDomainPtr domain, unsigned int iothread_id, unsigned int flags);
+/* IOThread set parameters */ + +/** + * VIR_DOMAIN_IOTHREAD_POLL_MAX_NS: + * + * The maximum polling time that can be used by polling algorithm in ns. + * The polling time starts at 0 (zero) and is the time spent by the guest + * to process IOThread data before returning the CPU to the host. The + * polling time will be dynamically modified over time based on the + * poll_grow and poll_shrink parameters provided. A value set too large + * will cause more CPU time to be allocated the guest. A value set too + * small will not provide enough cycles for the guest to process data. + * The polling interval is not available for statistical purposes. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_MAX_NS "poll_max_ns" + +/** + * VIR_DOMAIN_IOTHREAD_POLL_GROW: + * + * This provides a value for the dynamic polling adjustment algorithm to + * use to grow its polling interval up to the poll_max_ns value. A value + * of 0 (zero) allows the hypervisor to choose its own value. The algorithm + * to use for adjustment is hypervisor specific. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_GROW "poll_grow" + +/** + * VIR_DOMAIN_IOTHREAD_POLL_SHRINK: + * + * This provides a value for the dynamic polling adjustment algorithm to + * use to shrink its polling interval when the polling interval exceeds + * the poll_max_ns value. A value of 0 (zero) allows the hypervisor to + * choose its own value. The algorithm to use for adjustment is hypervisor + * specific. + */ +# define VIR_DOMAIN_IOTHREAD_POLL_SHRINK "poll_shrink" + +int virDomainSetIOThreadParams(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + + /** * VIR_USE_CPU: * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index eef31eb1f0..6be3e175ce 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -406,6 +406,13 @@ typedef int unsigned int iothread_id, unsigned int flags);
+typedef int +(*virDrvDomainSetIOThreadParams)(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + typedef int (*virDrvDomainGetSecurityLabel)(virDomainPtr domain, virSecurityLabelPtr seclabel); @@ -1407,6 +1414,7 @@ struct _virHypervisorDriver { virDrvDomainPinIOThread domainPinIOThread; virDrvDomainAddIOThread domainAddIOThread; virDrvDomainDelIOThread domainDelIOThread; + virDrvDomainSetIOThreadParams domainSetIOThreadParams; virDrvDomainGetSecurityLabel domainGetSecurityLabel; virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 9fda56d660..ce5de4b208 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -7812,6 +7812,77 @@ virDomainDelIOThread(virDomainPtr domain, }
+/** + * virDomainSetIOThreadParams: + * @domain: a domain object + * @iothread_id: the specific IOThread ID value to add + * @params: pointer to IOThread parameter objects + * @nparams: number of IOThread parameters + * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags + * + * Dynamically set IOThread parameters to the domain. It is left up to + * the underlying virtual hypervisor to determine the valid range for an + * @iothread_id, determining whether the @iothread_id already exists, and + * determining the validity of the provided param values. + * + * See VIR_DOMAIN_IOTHREAD_* for detailed description of accepted IOThread + * parameters. + * + * Since the purpose of this API is to dynamically modify the IOThread + * @flags should only include the VIR_DOMAIN_AFFECT_CURRENT and/or + * VIR_DOMAIN_AFFECT_LIVE virDomainMemoryModFlags. Setting other flags + * may cause errors from the hypervisor. + * + * Note that this call can fail if the underlying virtualization hypervisor + * does not support it or does not support setting the provided values. + * + * This function requires privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virDomainSetIOThreadParams(virDomainPtr domain, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "iothread_id=%u, params=%p, nparams=%d, flags=0x%x", + iothread_id, params, nparams, flags); + VIR_TYPED_PARAMS_DEBUG(params, nparams); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + virCheckNonNegativeArgGoto(nparams, error); + if (nparams) + virCheckNonNullArgGoto(params, error);
So this allows call like this: virDomainSetIOThreadParams(.params = NULL, .nparams = 0); (yeah, weird mixture of C and C++ call, but you get the idea) I don't think it makes sense to allow it. The checks should be as follows IMO: virCheckPositiveArgGoto(); virCheckNonNullArgGoto();
+ + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->domainSetIOThreadParams) { + int ret; + ret = conn->driver->domainSetIOThreadParams(domain, iothread_id, + params, nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(domain->conn); + return -1; +}
ACK Michal

Add functions to set the IOThreadInfo param data for the live guest. Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, } +/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo); typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, } +int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink) + +#undef VIR_IOTHREAD_SET_PROP + + ret = 0; + + cleanup: + VIR_FREE(path); + return ret; +} + + int qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitorPtr mon, virHashTablePtr info) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index da267b15b0..c3abd0ddf0 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -502,6 +502,10 @@ int qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads) ATTRIBUTE_NONNULL(2); +int qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitorPtr mon, virHashTablePtr info) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Add functions to set the IOThreadInfo param data for the live guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, }
+/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo);
typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, }
+int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink)
So this is all or nothing approach. All values are set - even though user might request through public API to change just one. I don't think it is a good design. Either we need a monitor API that changes just one value and call it for every typed parameter that user sends to us, or public API implementation must copy the old values into this struct (even though it would be ugly). Michal

On 10/19/18 7:06 AM, Michal Privoznik wrote:
On 10/07/2018 03:00 PM, John Ferlan wrote:
Add functions to set the IOThreadInfo param data for the live guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, }
+/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo);
typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, }
+int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink)
So this is all or nothing approach. All values are set - even though user might request through public API to change just one. I don't think it is a good design. Either we need a monitor API that changes just one value and call it for every typed parameter that user sends to us, or public API implementation must copy the old values into this struct (even though it would be ugly).
Michal
Fair complaint - I tried to reuse as much as possible from the initial series so that I didn't "waste" time implementing something that in the long run wasn't desired. Originally there were lots of checks about what was or wasn't set - I just took the path of least resistance. It should be simple to add flag for each to determine which was set before setting them in the object path. IOW: #define VIR_IOTHREAD_SET_PROP(propName, propVal) \ if (iothreadInfo->set_##propVal) { \ memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ prop.val.iv = iothreadInfo->propVal; \ if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ goto cleanup; \ } VIR_IOTHREAD_SET_PROP("poll-max-ns", poll_max_ns); VIR_IOTHREAD_SET_PROP("poll-grow", poll_grow); VIR_IOTHREAD_SET_PROP("poll-shrink", poll_shrink); That just then gets utilized in patch10 as well. Tks - John

On 10/19/2018 03:09 PM, John Ferlan wrote:
On 10/19/18 7:06 AM, Michal Privoznik wrote:
On 10/07/2018 03:00 PM, John Ferlan wrote:
Add functions to set the IOThreadInfo param data for the live guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, }
+/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo);
typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, }
+int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink)
So this is all or nothing approach. All values are set - even though user might request through public API to change just one. I don't think it is a good design. Either we need a monitor API that changes just one value and call it for every typed parameter that user sends to us, or public API implementation must copy the old values into this struct (even though it would be ugly).
Michal
Fair complaint - I tried to reuse as much as possible from the initial series so that I didn't "waste" time implementing something that in the long run wasn't desired. Originally there were lots of checks about what was or wasn't set - I just took the path of least resistance.
It should be simple to add flag for each to determine which was set before setting them in the object path.
IOW:
#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ if (iothreadInfo->set_##propVal) { \
This will fly iff zero value can't be set on the monitor. I have no idea whether it can or can not. If it can be set, then we have to go with something more clever. Michal

On 10/22/18 5:16 AM, Michal Prívozník wrote:
On 10/19/2018 03:09 PM, John Ferlan wrote:
On 10/19/18 7:06 AM, Michal Privoznik wrote:
On 10/07/2018 03:00 PM, John Ferlan wrote:
Add functions to set the IOThreadInfo param data for the live guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, }
+/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo);
typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, }
+int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink)
So this is all or nothing approach. All values are set - even though user might request through public API to change just one. I don't think it is a good design. Either we need a monitor API that changes just one value and call it for every typed parameter that user sends to us, or public API implementation must copy the old values into this struct (even though it would be ugly).
Michal
Fair complaint - I tried to reuse as much as possible from the initial series so that I didn't "waste" time implementing something that in the long run wasn't desired. Originally there were lots of checks about what was or wasn't set - I just took the path of least resistance.
It should be simple to add flag for each to determine which was set before setting them in the object path.
IOW:
#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ if (iothreadInfo->set_##propVal) { \
This will fly iff zero value can't be set on the monitor. I have no idea whether it can or can not. If it can be set, then we have to go with something more clever.
Michal
Not 100% sure what you meant... The point of the bools is to indicate when the value was set, doesn't matter if it's zero. From: $QEMU.GIT/qapi/misc.json: # @poll-max-ns: maximum polling time in ns, 0 means polling is disabled # (since 2.9) # # @poll-grow: how many ns will be added to polling time, 0 means that it's not # configured (since 2.9) # # @poll-shrink: how many ns will be removed from polling time, 0 means that # it's not configured (since 2.9) # John FWIW: Examples "in action" # virsh domstats f18iothr --iothread Domain: 'f18iothr' iothread.count=6 iothread.1.poll-max-ns=32768 iothread.1.poll-grow=0 iothread.1.poll-shrink=0 iothread.3.poll-max-ns=32768 iothread.3.poll-grow=0 iothread.3.poll-shrink=0 iothread.4.poll-max-ns=32768 iothread.4.poll-grow=0 iothread.4.poll-shrink=0 iothread.5.poll-max-ns=32768 iothread.5.poll-grow=0 iothread.5.poll-shrink=0 iothread.6.poll-max-ns=32768 iothread.6.poll-grow=0 iothread.6.poll-shrink=0 iothread.2.poll-max-ns=32768 iothread.2.poll-grow=0 iothread.2.poll-shrink=0 # virsh iothreadset f18iothr 3 --poll-grow 2 irsh domstats f18iothr --iothread Domain: 'f18iothr' iothread.count=6 iothread.1.poll-max-ns=32768 iothread.1.poll-grow=0 iothread.1.poll-shrink=0 iothread.3.poll-max-ns=32768 iothread.3.poll-grow=2 iothread.3.poll-shrink=0 ... # virsh iothreadset f18iothr 3 --poll-max-ns 100000 2 # virsh domstats f18iothr --iothread Domain: 'f18iothr' iothread.count=6 iothread.1.poll-max-ns=32768 iothread.1.poll-grow=0 iothread.1.poll-shrink=0 iothread.3.poll-max-ns=100000 iothread.3.poll-grow=2 iothread.3.poll-shrink=0 ... # virsh iothreadset f18iothr 3 --poll-max-ns 500000 2 --poll-shrink 4 # virsh domstats f18iothr --iothread Domain: 'f18iothr' iothread.count=6 iothread.1.poll-max-ns=32768 iothread.1.poll-grow=0 iothread.1.poll-shrink=0 iothread.3.poll-max-ns=500000 iothread.3.poll-grow=2 iothread.3.poll-shrink=4 ...

On 10/22/2018 11:00 PM, John Ferlan wrote:
On 10/22/18 5:16 AM, Michal Prívozník wrote:
On 10/19/2018 03:09 PM, John Ferlan wrote:
On 10/19/18 7:06 AM, Michal Privoznik wrote:
On 10/07/2018 03:00 PM, John Ferlan wrote:
Add functions to set the IOThreadInfo param data for the live guest.
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but extracted into a separate patch. Note that qapi expects to receive integer parameters rather than unsigned long long or unsigned int's. QEMU does save the value in larger signed 64 bit values eventually.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_monitor.c | 19 +++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 4 files changed, 58 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..a65d638ab8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4135,6 +4135,25 @@ qemuMonitorGetIOThreads(qemuMonitorPtr mon, }
+/** + * qemuMonitorSetIOThread: + * @mon: Pointer to the monitor + * @iothreadInfo: filled IOThread info with data + * + * Alter the specified IOThread's IOThreadInfo values. + */ +int +qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + VIR_DEBUG("iothread=%p", iothreadInfo); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetIOThread(mon, iothreadInfo); +} + + /** * qemuMonitorGetMemoryDeviceInfo: * @mon: pointer to the monitor diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2991e2b16..ef71fc6448 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1123,6 +1123,8 @@ struct _qemuMonitorIOThreadInfo { }; int qemuMonitorGetIOThreads(qemuMonitorPtr mon, qemuMonitorIOThreadInfoPtr **iothreads); +int qemuMonitorSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo);
typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo; typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2e92984b44..bb1d62b844 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7474,6 +7474,39 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, }
+int +qemuMonitorJSONSetIOThread(qemuMonitorPtr mon, + qemuMonitorIOThreadInfoPtr iothreadInfo) +{ + int ret = -1; + char *path = NULL; + qemuMonitorJSONObjectProperty prop; + + if (virAsprintf(&path, "/objects/iothread%u", + iothreadInfo->iothread_id) < 0) + goto cleanup; + +#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); \ + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT; \ + prop.val.iv = propVal; \ + if (qemuMonitorJSONSetObjectProperty(mon, path, propName, &prop) < 0) \ + goto cleanup; + + VIR_IOTHREAD_SET_PROP("poll-max-ns", iothreadInfo->poll_max_ns) + VIR_IOTHREAD_SET_PROP("poll-grow", iothreadInfo->poll_grow) + VIR_IOTHREAD_SET_PROP("poll-shrink", iothreadInfo->poll_shrink)
So this is all or nothing approach. All values are set - even though user might request through public API to change just one. I don't think it is a good design. Either we need a monitor API that changes just one value and call it for every typed parameter that user sends to us, or public API implementation must copy the old values into this struct (even though it would be ugly).
Michal
Fair complaint - I tried to reuse as much as possible from the initial series so that I didn't "waste" time implementing something that in the long run wasn't desired. Originally there were lots of checks about what was or wasn't set - I just took the path of least resistance.
It should be simple to add flag for each to determine which was set before setting them in the object path.
IOW:
#define VIR_IOTHREAD_SET_PROP(propName, propVal) \ if (iothreadInfo->set_##propVal) { \
This will fly iff zero value can't be set on the monitor. I have no idea whether it can or can not. If it can be set, then we have to go with something more clever.
Michal
Not 100% sure what you meant... The point of the bools is to indicate when the value was set, doesn't matter if it's zero.
Ah sorry, I've misunderstood then. set_##propVal is a boolean not integer holding the value we want to set. So you'd have two variables, int A and bool set_A. Okay, this will work well. However, at this point I wonder if having monitor API that would take attribute name and a value would be simpler. Something like: qemuMonitorSetIOThreadAttr(qemuMonitorPtr mon, unsigned int thread_id, const char *attrName, int attrVal); Then this function would be called like this: static int qemuDomainSetIOThreadParams(virDomainPtr dom, unsigned int iothread_id, virTypedParameterPtr params, int nparams, unsigned int flags) { ... for (i = 0; i < nparams; i++) { qemuMonitorSetIOThreadAttr(mon, thread_id, param[i].str, param[i].val); } ... } Anyway, I'll leave it up to you. Michal

[...]
Not 100% sure what you meant... The point of the bools is to indicate when the value was set, doesn't matter if it's zero.
Ah sorry, I've misunderstood then. set_##propVal is a boolean not integer holding the value we want to set. So you'd have two variables, int A and bool set_A. Okay, this will work well. However, at this point I wonder if having monitor API that would take attribute name and a value would be simpler. Something like:
qemuMonitorSetIOThreadAttr(qemuMonitorPtr mon, unsigned int thread_id, const char *attrName, int attrVal);
Then this function would be called like this:
static int qemuDomainSetIOThreadParams(virDomainPtr dom, unsigned int iothread_id, virTypedParameterPtr params, int nparams, unsigned int flags) { ...
for (i = 0; i < nparams; i++) { qemuMonitorSetIOThreadAttr(mon, thread_id, param[i].str, param[i].val); } ... }
Anyway, I'll leave it up to you.
Michal
I kept a lot of what Pavel already had for simplicity and leaving the setting deeper in the _json code for all values rather than 'n' calls to essentially do the same thing. Those patches were posted before this discussion. I'm not against rewriting to conform to some other mechanism, just let me know. John

On 10/23/2018 03:42 PM, John Ferlan wrote:
[...]
Not 100% sure what you meant... The point of the bools is to indicate when the value was set, doesn't matter if it's zero.
Ah sorry, I've misunderstood then. set_##propVal is a boolean not integer holding the value we want to set. So you'd have two variables, int A and bool set_A. Okay, this will work well. However, at this point I wonder if having monitor API that would take attribute name and a value would be simpler. Something like:
qemuMonitorSetIOThreadAttr(qemuMonitorPtr mon, unsigned int thread_id, const char *attrName, int attrVal);
Then this function would be called like this:
static int qemuDomainSetIOThreadParams(virDomainPtr dom, unsigned int iothread_id, virTypedParameterPtr params, int nparams, unsigned int flags) { ...
for (i = 0; i < nparams; i++) { qemuMonitorSetIOThreadAttr(mon, thread_id, param[i].str, param[i].val); } ... }
Anyway, I'll leave it up to you.
Michal
I kept a lot of what Pavel already had for simplicity and leaving the setting deeper in the _json code for all values rather than 'n' calls to essentially do the same thing. Those patches were posted before this discussion. I'm not against rewriting to conform to some other mechanism, just let me know.
At this point it is more of a personal preference than anything. From functional POV these two approaches are the same. So I am okay with you keeping what you suggested. Michal

We're about to add a new state "modify" and thus the function goes from just Add/Del. Use an enum to manage. Extracted from code originally posted by Pavel Hrdina <phrdina@redhat.com>, but placed into a separate patch. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ff87865fe6..ff466df4b7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6015,11 +6015,16 @@ qemuDomainDelIOThreadCheck(virDomainDefPtr def, return 0; } +typedef enum { + VIR_DOMAIN_IOTHREAD_ACTION_ADD, + VIR_DOMAIN_IOTHREAD_ACTION_DEL, +} virDomainIOThreadAction; + static int qemuDomainChgIOThread(virQEMUDriverPtr driver, virDomainObjPtr vm, unsigned int iothread_id, - bool add, + virDomainIOThreadAction action, unsigned int flags) { virQEMUDriverConfigPtr cfg = NULL; @@ -6045,18 +6050,24 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, goto endjob; } - if (add) { + switch (action) { + case VIR_DOMAIN_IOTHREAD_ACTION_ADD: if (qemuDomainAddIOThreadCheck(def, iothread_id) < 0) goto endjob; if (qemuDomainHotplugAddIOThread(driver, vm, iothread_id) < 0) goto endjob; - } else { + + break; + + case VIR_DOMAIN_IOTHREAD_ACTION_DEL: if (qemuDomainDelIOThreadCheck(def, iothread_id) < 0) goto endjob; if (qemuDomainHotplugDelIOThread(driver, vm, iothread_id) < 0) goto endjob; + + break; } if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) @@ -6064,18 +6075,23 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, } if (persistentDef) { - if (add) { + switch (action) { + case VIR_DOMAIN_IOTHREAD_ACTION_ADD: if (qemuDomainAddIOThreadCheck(persistentDef, iothread_id) < 0) goto endjob; if (!virDomainIOThreadIDAdd(persistentDef, iothread_id)) goto endjob; - } else { + break; + + case VIR_DOMAIN_IOTHREAD_ACTION_DEL: if (qemuDomainDelIOThreadCheck(persistentDef, iothread_id) < 0) goto endjob; virDomainIOThreadIDDel(persistentDef, iothread_id); + + break; } if (virDomainSaveConfig(cfg->configDir, driver->caps, @@ -6117,7 +6133,8 @@ qemuDomainAddIOThread(virDomainPtr dom, if (virDomainAddIOThreadEnsureACL(dom->conn, vm->def, flags) < 0) goto cleanup; - ret = qemuDomainChgIOThread(driver, vm, iothread_id, true, flags); + ret = qemuDomainChgIOThread(driver, vm, iothread_id, + VIR_DOMAIN_IOTHREAD_ACTION_ADD, flags); cleanup: virDomainObjEndAPI(&vm); @@ -6149,7 +6166,8 @@ qemuDomainDelIOThread(virDomainPtr dom, if (virDomainDelIOThreadEnsureACL(dom->conn, vm->def, flags) < 0) goto cleanup; - ret = qemuDomainChgIOThread(driver, vm, iothread_id, false, flags); + ret = qemuDomainChgIOThread(driver, vm, iothread_id, + VIR_DOMAIN_IOTHREAD_ACTION_DEL, flags); cleanup: virDomainObjEndAPI(&vm); -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
We're about to add a new state "modify" and thus the function goes from just Add/Del. Use an enum to manage.
Extracted from code originally posted by Pavel Hrdina <phrdina@redhat.com>, but placed into a separate patch.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
ACK Michal

Rather than passing an iothread_id, let's pass a qemuMonitorIOThreadInfo structure so that a subsequent change to modify the iothread info can just generate and pass one. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ff466df4b7..c87a0db86d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6023,7 +6023,7 @@ typedef enum { static int qemuDomainChgIOThread(virQEMUDriverPtr driver, virDomainObjPtr vm, - unsigned int iothread_id, + qemuMonitorIOThreadInfo iothread, virDomainIOThreadAction action, unsigned int flags) { @@ -6052,19 +6052,19 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, switch (action) { case VIR_DOMAIN_IOTHREAD_ACTION_ADD: - if (qemuDomainAddIOThreadCheck(def, iothread_id) < 0) + if (qemuDomainAddIOThreadCheck(def, iothread.iothread_id) < 0) goto endjob; - if (qemuDomainHotplugAddIOThread(driver, vm, iothread_id) < 0) + if (qemuDomainHotplugAddIOThread(driver, vm, iothread.iothread_id) < 0) goto endjob; break; case VIR_DOMAIN_IOTHREAD_ACTION_DEL: - if (qemuDomainDelIOThreadCheck(def, iothread_id) < 0) + if (qemuDomainDelIOThreadCheck(def, iothread.iothread_id) < 0) goto endjob; - if (qemuDomainHotplugDelIOThread(driver, vm, iothread_id) < 0) + if (qemuDomainHotplugDelIOThread(driver, vm, iothread.iothread_id) < 0) goto endjob; break; @@ -6077,19 +6077,19 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, if (persistentDef) { switch (action) { case VIR_DOMAIN_IOTHREAD_ACTION_ADD: - if (qemuDomainAddIOThreadCheck(persistentDef, iothread_id) < 0) + if (qemuDomainAddIOThreadCheck(persistentDef, iothread.iothread_id) < 0) goto endjob; - if (!virDomainIOThreadIDAdd(persistentDef, iothread_id)) + if (!virDomainIOThreadIDAdd(persistentDef, iothread.iothread_id)) goto endjob; break; case VIR_DOMAIN_IOTHREAD_ACTION_DEL: - if (qemuDomainDelIOThreadCheck(persistentDef, iothread_id) < 0) + if (qemuDomainDelIOThreadCheck(persistentDef, iothread.iothread_id) < 0) goto endjob; - virDomainIOThreadIDDel(persistentDef, iothread_id); + virDomainIOThreadIDDel(persistentDef, iothread.iothread_id); break; } @@ -6116,6 +6116,7 @@ qemuDomainAddIOThread(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm = NULL; + qemuMonitorIOThreadInfo iothread = {0}; int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -6133,7 +6134,8 @@ qemuDomainAddIOThread(virDomainPtr dom, if (virDomainAddIOThreadEnsureACL(dom->conn, vm->def, flags) < 0) goto cleanup; - ret = qemuDomainChgIOThread(driver, vm, iothread_id, + iothread.iothread_id = iothread_id; + ret = qemuDomainChgIOThread(driver, vm, iothread, VIR_DOMAIN_IOTHREAD_ACTION_ADD, flags); cleanup: @@ -6149,6 +6151,7 @@ qemuDomainDelIOThread(virDomainPtr dom, { virQEMUDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm = NULL; + qemuMonitorIOThreadInfo iothread = {0}; int ret = -1; virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -6166,7 +6169,8 @@ qemuDomainDelIOThread(virDomainPtr dom, if (virDomainDelIOThreadEnsureACL(dom->conn, vm->def, flags) < 0) goto cleanup; - ret = qemuDomainChgIOThread(driver, vm, iothread_id, + iothread.iothread_id = iothread_id; + ret = qemuDomainChgIOThread(driver, vm, iothread, VIR_DOMAIN_IOTHREAD_ACTION_DEL, flags); cleanup: -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Rather than passing an iothread_id, let's pass a qemuMonitorIOThreadInfo structure so that a subsequent change to modify the iothread info can just generate and pass one.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-)
ACK Michal

Add a capability check for IOThread polling (all were added at the same time, so only one check is necessary). Based on code originally posted by Pavel Hrdina <phrdina@redhat.com> with the only changes to include the more recent QEMU releases. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml | 1 + 20 files changed, 21 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index e228f52ec0..54589a740d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -508,6 +508,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, /* 315 */ "vfio-pci.display", "blockdev", + "iothread.poll-max-ns", ); @@ -1237,6 +1238,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "nbd-server-start/arg-type/tls-creds", QEMU_CAPS_NBD_TLS }, { "screendump/arg-type/device", QEMU_CAPS_SCREENDUMP_DEVICE }, { "block-commit/arg-type/*top", QEMU_CAPS_ACTIVE_COMMIT }, + { "query-iothreads/ret-type/poll-max-ns", QEMU_CAPS_IOTHREAD_POLLING }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 934620ed31..8dbe23de20 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -492,6 +492,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 315 */ QEMU_CAPS_VFIO_PCI_DISPLAY, /* -device vfio-pci.display */ QEMU_CAPS_BLOCKDEV, /* -blockdev and blockdev-add are supported */ + QEMU_CAPS_IOTHREAD_POLLING, /* -object iothread.poll-max-ns */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml index b9c4182a66..7061ba8f7e 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml @@ -151,6 +151,7 @@ <flag name='blockdev-del'/> <flag name='vhost-vsock'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>305067</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml index 66b25601e7..2a48b63efe 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml @@ -150,6 +150,7 @@ <flag name='blockdev-del'/> <flag name='vhost-vsock'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>384412</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index e000aac384..c35e014b32 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -113,6 +113,7 @@ <flag name='blockdev-del'/> <flag name='vhost-vsock'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>306247</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml index ebc5e771d9..a8d787f99a 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml @@ -192,6 +192,7 @@ <flag name='vhost-vsock'/> <flag name='mch'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2010000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>364386</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 4eb8a39d94..6ee53a1f21 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -120,6 +120,7 @@ <flag name='vhost-vsock'/> <flag name='tpm-emulator'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>345099</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml index 857a9a9f9a..4ba2a82b60 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml @@ -198,6 +198,7 @@ <flag name='mch'/> <flag name='mch.extended-tseg-mbytes'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>368875</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml index 7bf1fab8cb..c7e62d3723 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml @@ -162,6 +162,7 @@ <flag name='tpm-emulator'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>344910</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml index 8b8d8859c1..391c83eaaa 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml @@ -160,6 +160,7 @@ <flag name='machine.pseries.cap-htm'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>425694</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index 79320d5229..1e09f24c31 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -128,6 +128,7 @@ <flag name='tpm-emulator'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>2012000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>374287</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml index fcf94ab720..407c6e63cc 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml @@ -203,6 +203,7 @@ <flag name='sev-guest'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>413556</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml index f97ebdb9d4..d9ca8f3d2b 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml @@ -142,6 +142,7 @@ <flag name='hda-output'/> <flag name='blockdev-del'/> <flag name='vhost-vsock'/> + <flag name='iothread.poll-max-ns'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>349056</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index 5a4371ab83..a789403ca6 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -107,6 +107,7 @@ <flag name='sdl-gl'/> <flag name='blockdev-del'/> <flag name='vhost-vsock'/> + <flag name='iothread.poll-max-ns'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>267973</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml index 7bf31d9fd5..3c26b381da 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml @@ -186,6 +186,7 @@ <flag name='vmgenid'/> <flag name='vhost-vsock'/> <flag name='mch'/> + <flag name='iothread.poll-max-ns'/> <version>2009000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>340375</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml index a1e2ae6556..6aad2e0feb 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml @@ -160,6 +160,7 @@ <flag name='machine.pseries.cap-htm'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>2012050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>444131</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml b/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml index 254a4cf3d8..231213ae3a 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml @@ -100,6 +100,7 @@ <flag name='chardev-fd-pass'/> <flag name='tpm-emulator'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>0</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml b/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml index e7ab79e006..1722876dcc 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml @@ -100,6 +100,7 @@ <flag name='chardev-fd-pass'/> <flag name='tpm-emulator'/> <flag name='egl-headless'/> + <flag name='iothread.poll-max-ns'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>0</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml index 3b5f9818a5..b77e95510f 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml @@ -130,6 +130,7 @@ <flag name='tpm-emulator'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>387601</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml index 7ceea6b738..acfb1d45d2 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml @@ -205,6 +205,7 @@ <flag name='usb-storage.werror'/> <flag name='egl-headless'/> <flag name='vfio-pci.display'/> + <flag name='iothread.poll-max-ns'/> <version>3000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>425157</microcodeVersion> -- 2.17.1

On 10/07/2018 03:00 PM, John Ferlan wrote:
Add a capability check for IOThread polling (all were added at the same time, so only one check is necessary).
Based on code originally posted by Pavel Hrdina <phrdina@redhat.com> with the only changes to include the more recent QEMU releases.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.10.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.10.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.11.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.9.0.x86_64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml | 1 + 20 files changed, 21 insertions(+)
ACK Michal

https://bugzilla.redhat.com/show_bug.cgi?id=1545732 Implement the QEMU driver mechanism in order to set the polling parameters for an IOThread within the bounds specified by the QEMU qapi parameter passing. Based heavily on patches originally posted by Pavel Hrdina <phrdina@redhat.com>, but modified to only handle alterations for a running guest. For the most part the API names changed, the typed parameters removed the poll enabled value, and the capabilities check was moved to just before the live attempt to set. Since changes are only supported for a running guest, no guest XML alterations were kept. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 202 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c87a0db86d..be668b3217 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5899,6 +5899,35 @@ qemuDomainHotplugAddIOThread(virQEMUDriverPtr driver, goto cleanup; } + +static int +qemuDomainHotplugModIOThread(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuMonitorIOThreadInfo iothread) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int rc; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_IOTHREAD_POLLING)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("IOThreads polling is not supported for this QEMU")); + return -1; + } + + qemuDomainObjEnterMonitor(driver, vm); + + rc = qemuMonitorSetIOThread(priv->mon, &iothread); + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + + if (rc < 0) + return -1; + + return 0; +} + + static int qemuDomainHotplugDelIOThread(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -6015,9 +6044,107 @@ qemuDomainDelIOThreadCheck(virDomainDefPtr def, return 0; } + +/** + * @params: Pointer to params list + * @nparams: Number of params to be parsed + * @iothread: Buffer to store the values + * + * The following is a description of each value parsed: + * + * - "poll-max-ns" for each IOThread is the maximum time in nanoseconds + * to allow each polling interval to occur. A polling interval is a + * period of time allowed for a thread to process data before it returns + * the CPU quantum back to the host. A value set too small will not allow + * the IOThread to run long enough on a CPU to process data. A value set + * too high will consume too much CPU time per IOThread failing to allow + * other threads running on the CPU to get time. A value of 0 (zero) will + * disable the polling. + * + * - "poll-grow" - factor to grow the current polling time when deemed + * necessary. If a 0 (zero) value is provided, QEMU currently doubles + * its polling interval unless the current value is greater than the + * poll-max-ns. + * + * - "poll-shrink" - divisor to reduced the current polling time when deemed + * necessary. If a 0 (zero) value is provided, QEMU resets the polling + * interval to 0 (zero) allowing the poll-grow to manipulate the time. + * + * 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 + * ajustments are made. The polling time value is not available. + * + * Returns 0 on success, -1 on failure with error set. + */ +static int +qemuDomainIOThreadParseParams(virTypedParameterPtr params, + int nparams, + qemuMonitorIOThreadInfoPtr iothread) +{ + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, + VIR_TYPED_PARAM_ULLONG, + VIR_DOMAIN_IOTHREAD_POLL_GROW, + VIR_TYPED_PARAM_UINT, + VIR_DOMAIN_IOTHREAD_POLL_SHRINK, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + if (virTypedParamsGetULLong(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, + &iothread->poll_max_ns) < 0) + return -1; + + if (virTypedParamsGetUInt(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_GROW, + &iothread->poll_grow) < 0) + return -1; + + if (virTypedParamsGetUInt(params, nparams, + VIR_DOMAIN_IOTHREAD_POLL_SHRINK, + &iothread->poll_shrink) < 0) + return -1; + + if (iothread->poll_max_ns > INT_MAX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("poll-max-ns (%llu) must be less than or equal to %d"), + iothread->poll_max_ns, INT_MAX); + return -1; + } + + if (iothread->poll_grow > INT_MAX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("poll-grow (%u) must be less than or equal to %d"), + iothread->poll_grow, INT_MAX); + return -1; + } + + if (iothread->poll_shrink > INT_MAX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("poll-shrink (%u) must be less than or equal to %d"), + iothread->poll_shrink, INT_MAX); + return -1; + } + + if ((iothread->poll_grow > 0 || iothread->poll_shrink > 0) && + iothread->poll_max_ns == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("poll-grow or poll-shrink is set for iothread id " + "'%u' but poll-max-ns is not set"), + iothread->iothread_id); + return -1; + } + + return 0; +} + + typedef enum { VIR_DOMAIN_IOTHREAD_ACTION_ADD, VIR_DOMAIN_IOTHREAD_ACTION_DEL, + VIR_DOMAIN_IOTHREAD_ACTION_MOD, } virDomainIOThreadAction; static int @@ -6068,6 +6195,20 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, goto endjob; break; + + case VIR_DOMAIN_IOTHREAD_ACTION_MOD: + if (!(virDomainIOThreadIDFind(def, iothread.iothread_id))) { + virReportError(VIR_ERR_INVALID_ARG, + _("cannot find IOThread '%u' in iothreadids"), + iothread.iothread_id); + goto endjob; + } + + if (qemuDomainHotplugModIOThread(driver, vm, iothread) < 0) + goto endjob; + + break; + } if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) @@ -6091,6 +6232,14 @@ qemuDomainChgIOThread(virQEMUDriverPtr driver, virDomainIOThreadIDDel(persistentDef, iothread.iothread_id); + break; + + case VIR_DOMAIN_IOTHREAD_ACTION_MOD: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("configuring persistent polling values is " + "not supported")); + goto endjob; + break; } @@ -6178,6 +6327,58 @@ qemuDomainDelIOThread(virDomainPtr dom, return ret; } + +/** + * @dom: Domain to set IOThread params + * @iothread_id: IOThread 'id' that will be modified + * @params: List of parameters to change + * @nparams: Number of parameters in the list + * @flags: Flags for the set (only supports live alteration) + * + * Alter the specified @iothread_id with the values provided. + * + * Returs 0 on success, -1 on failure + */ +static int +qemuDomainSetIOThreadParams(virDomainPtr dom, + unsigned int iothread_id, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + qemuMonitorIOThreadInfo iothread = {0}; + int ret = -1; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE, -1); + + if (iothread_id == 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("invalid value of 0 for iothread_id")); + goto cleanup; + } + + iothread.iothread_id = iothread_id; + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainSetIOThreadParamsEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + if (qemuDomainIOThreadParseParams(params, nparams, &iothread) < 0) + goto cleanup; + + ret = qemuDomainChgIOThread(driver, vm, iothread, + VIR_DOMAIN_IOTHREAD_ACTION_MOD, flags); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + + static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) { virQEMUDriverPtr driver = dom->conn->privateData; @@ -21955,6 +22156,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainPinIOThread = qemuDomainPinIOThread, /* 1.2.14 */ .domainAddIOThread = qemuDomainAddIOThread, /* 1.2.15 */ .domainDelIOThread = qemuDomainDelIOThread, /* 1.2.15 */ + .domainSetIOThreadParams = qemuDomainSetIOThreadParams, /* 4.9.0 */ .domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */ .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */ .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */ -- 2.17.1

Add a command to allow for setting various dynamic IOThread polling interval scope (poll-max-ns, poll-grow, and poll-shrink). Describe the values in the virsh.pod in as generic terms as possible. The more specific QEMU algorithm has been divulged in the previous patch. Based heavily on code originally posted by Pavel Hrdina <phrdina@redhat.com>, but altered to only provide one command and to not managed a poll disabled state. Signed-off-by: John Ferlan <jferlan@redhat.com> --- tools/virsh-domain.c | 110 +++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 21 +++++++++ 2 files changed, 131 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 372bdb95d3..4ee6ddf956 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7734,6 +7734,110 @@ cmdIOThreadAdd(vshControl *ctl, const vshCmd *cmd) return ret; } + + /* + * "iothreadset" command + */ +static const vshCmdInfo info_iothreadset[] = { + {.name = "help", + .data = N_("modifies an existing IOThread of the guest domain") + }, + {.name = "desc", + .data = N_("Modifies an existing IOThread of the guest domain.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_iothreadset[] = { + VIRSH_COMMON_OPT_DOMAIN_FULL(0), + {.name = "id", + .type = VSH_OT_INT, + .flags = VSH_OFLAG_REQ, + .help = N_("iothread id of existing IOThread") + }, + {.name = "poll-max-ns", + .type = VSH_OT_INT, + .help = N_("set the maximum IOThread polling time in ns") + }, + {.name = "poll-grow", + .type = VSH_OT_INT, + .help = N_("set the value to increase the IOThread polling time") + }, + {.name = "poll-shrink", + .type = VSH_OT_INT, + .help = N_("set the value for reduction of the IOThread polling time ") + }, + VIRSH_COMMON_OPT_DOMAIN_LIVE, + VIRSH_COMMON_OPT_DOMAIN_CURRENT, + {.name = NULL} +}; + +static bool +cmdIOThreadSet(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int id = 0; + bool ret = false; + bool live = vshCommandOptBool(cmd, "live"); + unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; + virTypedParameterPtr params = NULL; + int nparams = 0; + int maxparams = 0; + unsigned long long poll_max; + unsigned int poll_val; + int rc; + + if (live) + flags |= VIR_DOMAIN_AFFECT_LIVE; + + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptInt(ctl, cmd, "id", &id) < 0) + goto cleanup; + if (id <= 0) { + vshError(ctl, _("Invalid IOThread id value: '%d'"), id); + goto cleanup; + } + + poll_val = 0; + if ((rc = vshCommandOptULongLong(ctl, cmd, "poll-max-ns", &poll_max)) < 0) + goto cleanup; + if (rc > 0 && virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_DOMAIN_IOTHREAD_POLL_MAX_NS, + poll_max) < 0) + goto save_error; + +#define VSH_IOTHREAD_SET_UINT_PARAMS(opt, param) \ + poll_val = 0; \ + if ((rc = vshCommandOptUInt(ctl, cmd, opt, &poll_val)) < 0) \ + goto cleanup; \ + if (rc > 0 && \ + virTypedParamsAddUInt(¶ms, &nparams, &maxparams, \ + param, poll_val) < 0) \ + goto save_error; + + VSH_IOTHREAD_SET_UINT_PARAMS("poll-grow", VIR_DOMAIN_IOTHREAD_POLL_GROW) + VSH_IOTHREAD_SET_UINT_PARAMS("poll-shrink", VIR_DOMAIN_IOTHREAD_POLL_SHRINK) + +#undef VSH_IOTHREAD_SET_UINT_PARAMS + + if (virDomainSetIOThreadParams(dom, id, params, nparams, flags) < 0) + goto cleanup; + + ret = true; + + cleanup: + virTypedParamsFree(params, nparams); + virshDomainFree(dom); + return ret; + + save_error: + vshSaveLibvirtError(); + goto cleanup; +} + + /* * "iothreaddel" command */ @@ -14149,6 +14253,12 @@ const vshCmdDef domManagementCmds[] = { .info = info_iothreadadd, .flags = 0 }, + {.name = "iothreadset", + .handler = cmdIOThreadSet, + .opts = opts_iothreadset, + .info = info_iothreadset, + .flags = 0 + }, {.name = "iothreaddel", .handler = cmdIOThreadDel, .opts = opts_iothreaddel, diff --git a/tools/virsh.pod b/tools/virsh.pod index 90f3c1ef5c..48766567f8 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1732,6 +1732,27 @@ If I<--config> is specified, affect the next boot of a persistent guest. If I<--current> is specified or I<--live> and I<--config> are not specified, affect the current guest state. +=item B<iothreadset> I<domain> I<iothread_id> +[[I<--poll-max-ns> B<ns>] [I<--poll-grow> B<factor>] +[I<--poll-shrink> B<divisor>]] +[[I<--config>] [I<--live>] | [I<--current>]] + +Modifies an existing iothread of the domain using the specified +I<iothread_id>. The I<--poll-max-ns> provides the maximum polling +interval to be allowed for an IOThread in ns. If a 0 (zero) is provided, +then polling for the IOThread is disabled. The I<--poll-grow> is the +factor by which the current polling time will be adjusted in order to +reach the maximum polling time. If a 0 (zero) is provided, then the +default factor will be used. The I<--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. + +If I<--live> is specified, affect a running guest. If the guest is not +running an error is returned. +If I<--current> is specified or I<--live> is not specified, then handle +as if I<--live> was specified. + =item B<iothreaddel> I<domain> I<iothread_id> [[I<--config>] [I<--live>] | [I<--current>]] -- 2.17.1

ping? Any takers or thoughts? Tks, John On 10/7/18 9:00 AM, John Ferlan wrote:
This series attempts to resurrect the concept of being able to modify the IOThread polling parameters; however, in a slightly different manner than the previous series posted by posted by Pavel Hrdina <phrdina@redhat.com>:
https://www.redhat.com/archives/libvir-list/2017-February/msg01047.html
The work is prompted by continued pleas found in the bz:
https://bugzilla.redhat.com/show_bug.cgi?id=1545732
to provide some way to modify the paremters without needing to supply QEMU command line pass through values.
It's accepted that the values being changed are fairly or extremely low level type knobs; however, it's also shown that by being able to turn the knob it is possible for certain, specific appliances to be able to gain a performance benefit for the thread at the expense of other competing threads.
Unlike the previous series, this series does not attempt to save the polling values in the guest XML. Rather, it only modifies the live guest's IOThread with new values. It also doesn't provide the polling values in a virsh iothread* command, rather it uses the domstats in order to fetch and display the values. The theory being this leaves the onus on the higher level appliance/application to provide the "proper guidance" and "concerns" related to changing the values to the consumer. Not saving the values means whatever values that are chosen do not "live" in perpetuity. Once the guest is shut down or the IOThread removed from guest, the hypervisor default values take over again. Perhaps not a perfect situation in terms of what the bz requests; however, storage of default values that could cause performance issues is not an optimal situation. So this I figured is a "comprimise" of sorts.
If it's still felt that no we don't want to do this, then fine, but please in doing so own the bz, state your case, and close it. I'm 50/50 on it, but figured at least I'd present this option and see what the concensus was.
John Ferlan (11): qemu: Check for and return IOThread polling values if available qemu: Split qemuDomainGetIOThreadsLive qemu: Implement the ability to return IOThread stats virsh: Add ability to display IOThread stats lib: Introduce virDomainSetIOThreadParams qemu: Add monitor functions to set IOThread params qemu: Alter qemuDomainChgIOThread to take enum instead of bool qemu: Alter qemuDomainChgIOThread to take qemuMonitorIOThreadInfo qemu: Detect whether iothread polling is supported qemu: Introduce qemuDomainSetIOThreadParams tools: Add virsh iothreadset command
include/libvirt/libvirt-domain.h | 45 ++ src/driver-hypervisor.h | 8 + src/libvirt-domain.c | 109 +++++ src/libvirt_public.syms | 5 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_driver.c | 393 ++++++++++++++++-- src/qemu/qemu_monitor.c | 19 + src/qemu/qemu_monitor.h | 6 + src/qemu/qemu_monitor_json.c | 48 +++ src/qemu/qemu_monitor_json.h | 4 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 +- src/remote_protocol-structs | 10 + .../caps_2.10.0.aarch64.xml | 1 + .../caps_2.10.0.ppc64.xml | 1 + .../caps_2.10.0.s390x.xml | 1 + .../caps_2.10.0.x86_64.xml | 1 + .../caps_2.11.0.s390x.xml | 1 + .../caps_2.11.0.x86_64.xml | 1 + .../caps_2.12.0.aarch64.xml | 1 + .../caps_2.12.0.ppc64.xml | 1 + .../caps_2.12.0.s390x.xml | 1 + .../caps_2.12.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + .../caps_2.9.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.ppc64.xml | 1 + .../caps_3.0.0.riscv32.xml | 1 + .../caps_3.0.0.riscv64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + .../caps_3.0.0.x86_64.xml | 1 + tools/virsh-domain-monitor.c | 7 + tools/virsh-domain.c | 110 +++++ tools/virsh.pod | 47 ++- 35 files changed, 810 insertions(+), 44 deletions(-)

On 10/15/2018 04:28 PM, John Ferlan wrote:
ping?
Any takers or thoughts?
No review, but I think it makes a lot of sense to expose these tuneables.
Tks,
John
On 10/7/18 9:00 AM, John Ferlan wrote:
This series attempts to resurrect the concept of being able to modify the IOThread polling parameters; however, in a slightly different manner than the previous series posted by posted by Pavel Hrdina <phrdina@redhat.com>:
https://www.redhat.com/archives/libvir-list/2017-February/msg01047.html
The work is prompted by continued pleas found in the bz:
https://bugzilla.redhat.com/show_bug.cgi?id=1545732
to provide some way to modify the paremters without needing to supply QEMU command line pass through values.
It's accepted that the values being changed are fairly or extremely low level type knobs; however, it's also shown that by being able to turn the knob it is possible for certain, specific appliances to be able to gain a performance benefit for the thread at the expense of other competing threads.
Unlike the previous series, this series does not attempt to save the polling values in the guest XML. Rather, it only modifies the live guest's IOThread with new values. It also doesn't provide the polling values in a virsh iothread* command, rather it uses the domstats in order to fetch and display the values. The theory being this leaves the onus on the higher level appliance/application to provide the "proper guidance" and "concerns" related to changing the values to the consumer. Not saving the values means whatever values that are chosen do not "live" in perpetuity. Once the guest is shut down or the IOThread removed from guest, the hypervisor default values take over again. Perhaps not a perfect situation in terms of what the bz requests; however, storage of default values that could cause performance issues is not an optimal situation. So this I figured is a "comprimise" of sorts.
If it's still felt that no we don't want to do this, then fine, but please in doing so own the bz, state your case, and close it. I'm 50/50 on it, but figured at least I'd present this option and see what the concensus was.
John Ferlan (11): qemu: Check for and return IOThread polling values if available qemu: Split qemuDomainGetIOThreadsLive qemu: Implement the ability to return IOThread stats virsh: Add ability to display IOThread stats lib: Introduce virDomainSetIOThreadParams qemu: Add monitor functions to set IOThread params qemu: Alter qemuDomainChgIOThread to take enum instead of bool qemu: Alter qemuDomainChgIOThread to take qemuMonitorIOThreadInfo qemu: Detect whether iothread polling is supported qemu: Introduce qemuDomainSetIOThreadParams tools: Add virsh iothreadset command
include/libvirt/libvirt-domain.h | 45 ++ src/driver-hypervisor.h | 8 + src/libvirt-domain.c | 109 +++++ src/libvirt_public.syms | 5 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_driver.c | 393 ++++++++++++++++-- src/qemu/qemu_monitor.c | 19 + src/qemu/qemu_monitor.h | 6 + src/qemu/qemu_monitor_json.c | 48 +++ src/qemu/qemu_monitor_json.h | 4 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 21 +- src/remote_protocol-structs | 10 + .../caps_2.10.0.aarch64.xml | 1 + .../caps_2.10.0.ppc64.xml | 1 + .../caps_2.10.0.s390x.xml | 1 + .../caps_2.10.0.x86_64.xml | 1 + .../caps_2.11.0.s390x.xml | 1 + .../caps_2.11.0.x86_64.xml | 1 + .../caps_2.12.0.aarch64.xml | 1 + .../caps_2.12.0.ppc64.xml | 1 + .../caps_2.12.0.s390x.xml | 1 + .../caps_2.12.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.ppc64.xml | 1 + .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 1 + .../caps_2.9.0.x86_64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.ppc64.xml | 1 + .../caps_3.0.0.riscv32.xml | 1 + .../caps_3.0.0.riscv64.xml | 1 + .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 1 + .../caps_3.0.0.x86_64.xml | 1 + tools/virsh-domain-monitor.c | 7 + tools/virsh-domain.c | 110 +++++ tools/virsh.pod | 47 ++- 35 files changed, 810 insertions(+), 44 deletions(-)
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
participants (4)
-
Christian Borntraeger
-
John Ferlan
-
Michal Privoznik
-
Michal Prívozník