[libvirt] [PATCH v3 0/7] migration: add multithread compression

Add options to turn multithread compression on during migration and to configure its parameters. Changes from v2: 1. Multiple field parameter is used to specify compression methods that should be used during migration. VIR_MIGRATE_COMPRESSED option flag now specifies that default compression methods should be used so we keep backward compatibility. This method is lxbzrle for qemu. 2. Patch that adds monitor commands to configure multithread compression parameters and patch that adds compression options to migrate command are reworked. This series has not patches to configure compression parameters before migration. Do we need it? Also it has not patch to introspect compression methods supported by driver as Jiri suggested because I want to publish this series ealier to check that I'm going in right direction. Eli Qiao (1): qemumonitorjsontest: add test for getting multithread compress params Nikolay Shirokovskiy (4): qemu migration: factor out setting migration option migration: add compress method option qemu migration: add multithread compression options qemu migration: add xbzrle compression options ShaoHe Feng (2): qemu monitor: add multithread compress parameters accessors virsh: add compression options for migration include/libvirt/libvirt-domain.h | 44 ++++++- src/qemu/qemu_domain.c | 4 + src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 116 +++++++++++++++++- src/qemu/qemu_migration.c | 256 +++++++++++++++++++-------------------- src/qemu/qemu_migration.h | 24 ++++ src/qemu/qemu_monitor.c | 31 ++++- src/qemu/qemu_monitor.h | 17 +++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++ src/qemu/qemu_monitor_json.h | 5 + src/qemu/qemu_monitor_text.c | 100 +++++++++++++++ src/qemu/qemu_monitor_text.h | 5 + tests/qemumonitorjsontest.c | 53 ++++++++ tools/virsh-domain.c | 84 +++++++++++++ tools/virsh.pod | 25 +++- 15 files changed, 711 insertions(+), 142 deletions(-) -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_migration.c | 138 ++++++++++------------------------------------ 1 file changed, 28 insertions(+), 110 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 51e7125..a6412ce 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2364,97 +2364,10 @@ qemuMigrationSetOffline(virQEMUDriverPtr driver, return ret; } - -static int -qemuMigrationSetCompression(virQEMUDriverPtr driver, - virDomainObjPtr vm, - bool state, - qemuDomainAsyncJob job) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - int ret; - - if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) - return -1; - - ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE); - - if (ret < 0) { - goto cleanup; - } else if (ret == 0 && !state) { - /* Unsupported but we want it off anyway */ - goto cleanup; - } else if (ret == 0) { - if (job == QEMU_ASYNC_JOB_MIGRATION_IN) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Compressed migration is not supported by " - "target QEMU binary")); - } else { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Compressed migration is not supported by " - "source QEMU binary")); - } - ret = -1; - goto cleanup; - } - - ret = qemuMonitorSetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - state); - - cleanup: - if (qemuDomainObjExitMonitor(driver, vm) < 0) - ret = -1; - return ret; -} - -static int -qemuMigrationSetAutoConverge(virQEMUDriverPtr driver, - virDomainObjPtr vm, - bool state, - qemuDomainAsyncJob job) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - int ret; - - if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) - return -1; - - ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); - - if (ret < 0) { - goto cleanup; - } else if (ret == 0 && !state) { - /* Unsupported but we want it off anyway */ - goto cleanup; - } else if (ret == 0) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Auto-Converge is not supported by " - "QEMU binary")); - ret = -1; - goto cleanup; - } - - ret = qemuMonitorSetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, - state); - - cleanup: - if (qemuDomainObjExitMonitor(driver, vm) < 0) - ret = -1; - return ret; -} - - static int -qemuMigrationSetPinAll(virQEMUDriverPtr driver, +qemuMigrationSetOption(virQEMUDriverPtr driver, virDomainObjPtr vm, + qemuMonitorMigrationCaps capability, bool state, qemuDomainAsyncJob job) { @@ -2464,9 +2377,7 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver, if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) return -1; - ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL); + ret = qemuMonitorGetMigrationCapability(priv->mon, capability); if (ret < 0) { goto cleanup; @@ -2475,13 +2386,15 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver, goto cleanup; } else if (ret == 0) { if (job == QEMU_ASYNC_JOB_MIGRATION_IN) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("rdma pinning migration is not supported by " - "target QEMU binary")); + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Migration option '%s' is not supported by " + "target QEMU binary"), + qemuMonitorMigrationCapsTypeToString(capability)); } else { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("rdma pinning migration is not supported by " - "source QEMU binary")); + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Migration option '%s' is not supported by " + "source QEMU binary"), + qemuMonitorMigrationCapsTypeToString(capability)); } ret = -1; goto cleanup; @@ -2489,7 +2402,7 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver, ret = qemuMonitorSetMigrationCapability( priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, + capability, state); cleanup: @@ -3582,9 +3495,10 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, dataFD[1] = -1; /* 'st' owns the FD now & will close it */ } - if (qemuMigrationSetCompression(driver, vm, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_IN) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + flags & VIR_MIGRATE_COMPRESSED, + QEMU_ASYNC_JOB_MIGRATION_IN) < 0) goto stopjob; if (STREQ_NULLABLE(protocol, "rdma") && @@ -3592,7 +3506,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, goto stopjob; } - if (qemuMigrationSetPinAll(driver, vm, + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, flags & VIR_MIGRATE_RDMA_PIN_ALL, QEMU_ASYNC_JOB_MIGRATION_IN) < 0) goto stopjob; @@ -4447,17 +4362,20 @@ qemuMigrationRun(virQEMUDriverPtr driver, goto cleanup; } - if (qemuMigrationSetCompression(driver, vm, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + flags & VIR_MIGRATE_COMPRESSED, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; - if (qemuMigrationSetAutoConverge(driver, vm, - flags & VIR_MIGRATE_AUTO_CONVERGE, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, + flags & VIR_MIGRATE_AUTO_CONVERGE, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; - if (qemuMigrationSetPinAll(driver, vm, + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, flags & VIR_MIGRATE_RDMA_PIN_ALL, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com>
I'd be happy if you added a bit info into the commit message what functions you are removing and to what function you are combining them. Otherwise ACK.
--- src/qemu/qemu_migration.c | 138 ++++++++++------------------------------------ 1 file changed, 28 insertions(+), 110 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 51e7125..a6412ce 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2364,97 +2364,10 @@ qemuMigrationSetOffline(virQEMUDriverPtr driver, return ret; }
- -static int -qemuMigrationSetCompression(virQEMUDriverPtr driver, - virDomainObjPtr vm, - bool state, - qemuDomainAsyncJob job) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - int ret; - - if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) - return -1; - - ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE); - - if (ret < 0) { - goto cleanup; - } else if (ret == 0 && !state) { - /* Unsupported but we want it off anyway */ - goto cleanup; - } else if (ret == 0) { - if (job == QEMU_ASYNC_JOB_MIGRATION_IN) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Compressed migration is not supported by " - "target QEMU binary")); - } else { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Compressed migration is not supported by " - "source QEMU binary")); - } - ret = -1; - goto cleanup; - } - - ret = qemuMonitorSetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - state); - - cleanup: - if (qemuDomainObjExitMonitor(driver, vm) < 0) - ret = -1; - return ret; -} - -static int -qemuMigrationSetAutoConverge(virQEMUDriverPtr driver, - virDomainObjPtr vm, - bool state, - qemuDomainAsyncJob job) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - int ret; - - if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) - return -1; - - ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); - - if (ret < 0) { - goto cleanup; - } else if (ret == 0 && !state) { - /* Unsupported but we want it off anyway */ - goto cleanup; - } else if (ret == 0) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("Auto-Converge is not supported by " - "QEMU binary")); - ret = -1; - goto cleanup; - } - - ret = qemuMonitorSetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, - state); - - cleanup: - if (qemuDomainObjExitMonitor(driver, vm) < 0) - ret = -1; - return ret; -} - - static int -qemuMigrationSetPinAll(virQEMUDriverPtr driver, +qemuMigrationSetOption(virQEMUDriverPtr driver, virDomainObjPtr vm, + qemuMonitorMigrationCaps capability, bool state, qemuDomainAsyncJob job) { @@ -2464,9 +2377,7 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver, if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) return -1;
- ret = qemuMonitorGetMigrationCapability( - priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL); + ret = qemuMonitorGetMigrationCapability(priv->mon, capability);
if (ret < 0) { goto cleanup; @@ -2475,13 +2386,15 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver, goto cleanup; } else if (ret == 0) { if (job == QEMU_ASYNC_JOB_MIGRATION_IN) { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("rdma pinning migration is not supported by " - "target QEMU binary")); + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Migration option '%s' is not supported by " + "target QEMU binary"), + qemuMonitorMigrationCapsTypeToString(capability)); } else { - virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("rdma pinning migration is not supported by " - "source QEMU binary")); + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("Migration option '%s' is not supported by " + "source QEMU binary"), + qemuMonitorMigrationCapsTypeToString(capability)); } ret = -1; goto cleanup; @@ -2489,7 +2402,7 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver,
ret = qemuMonitorSetMigrationCapability( priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, + capability, state);
cleanup: @@ -3582,9 +3495,10 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, dataFD[1] = -1; /* 'st' owns the FD now & will close it */ }
- if (qemuMigrationSetCompression(driver, vm, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_IN) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + flags & VIR_MIGRATE_COMPRESSED, + QEMU_ASYNC_JOB_MIGRATION_IN) < 0) goto stopjob;
if (STREQ_NULLABLE(protocol, "rdma") && @@ -3592,7 +3506,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, goto stopjob; }
- if (qemuMigrationSetPinAll(driver, vm, + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, flags & VIR_MIGRATE_RDMA_PIN_ALL, QEMU_ASYNC_JOB_MIGRATION_IN) < 0) goto stopjob; @@ -4447,17 +4362,20 @@ qemuMigrationRun(virQEMUDriverPtr driver, goto cleanup; }
- if (qemuMigrationSetCompression(driver, vm, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + flags & VIR_MIGRATE_COMPRESSED, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup;
- if (qemuMigrationSetAutoConverge(driver, vm, - flags & VIR_MIGRATE_AUTO_CONVERGE, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, + flags & VIR_MIGRATE_AUTO_CONVERGE, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup;
- if (qemuMigrationSetPinAll(driver, vm, + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, flags & VIR_MIGRATE_RDMA_PIN_ALL, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup;

On Thu, Jan 28, 2016 at 10:04:27 +0300, Nikolay Shirokovskiy wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_migration.c | 138 ++++++++++------------------------------------ 1 file changed, 28 insertions(+), 110 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 51e7125..a6412ce 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c ... @@ -2489,7 +2402,7 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver,
ret = qemuMonitorSetMigrationCapability( priv->mon, - QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, + capability, state);
All the arguments will fit on a single line now. ACK and pushed since this patch is nice to have independently of the rest of this series. Jirka

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 13 +++++- src/qemu/qemu_driver.c | 75 +++++++++++++++++++++++++++++--- src/qemu/qemu_migration.c | 94 ++++++++++++++++++++++++++++------------ src/qemu/qemu_migration.h | 16 +++++++ src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 1 + 6 files changed, 166 insertions(+), 35 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 65f1618..e868515 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -655,7 +655,7 @@ typedef enum { * when supported */ VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */ VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ - VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ + VIR_MIGRATE_COMPRESSED = (1 << 11), /* use default compression method */ VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */ VIR_MIGRATE_AUTO_CONVERGE = (1 << 13), /* force convergence */ VIR_MIGRATE_RDMA_PIN_ALL = (1 << 14), /* RDMA memory pinning */ @@ -757,6 +757,17 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_MIGRATE_DISKS "migrate_disks" +/** + * VIR_MIGRATE_PARAM_COMPRESSION: + * + * virDomainMigrate* params multiple field: string list of compression methods + * that are used to compress migration traffic. Note that this option cannot + * be used together with VIR_MIGRATE_COMPRESSED flag, use only one of them. + */ + +# define VIR_MIGRATE_PARAM_COMPRESSION "compression" + + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 351e529..129da6d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12163,7 +12163,7 @@ qemuDomainMigratePrepare2(virConnectPtr dconn, ret = qemuMigrationPrepareDirect(driver, dconn, NULL, 0, NULL, NULL, /* No cookies */ uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags); cleanup: VIR_FREE(origname); @@ -12216,7 +12216,7 @@ qemuDomainMigratePerform(virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - NULL, dconnuri, uri, NULL, NULL, 0, NULL, + NULL, dconnuri, uri, NULL, NULL, 0, NULL, NULL, cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, false); @@ -12389,7 +12389,7 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags); cleanup: VIR_FREE(origname); @@ -12398,6 +12398,60 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, } static int +qemuAddCompressionMethod(qemuMigrationCompressMethod value, + qemuMigrationCompressMethod *method) +{ + if (*method & value) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Compression method is specified twice.")); + return -1; + } + + *method |= value; + return 0; +} + +static int +qemuGetCompression(virTypedParameterPtr params, int nparams, + unsigned int flags, + qemuMigrationCompressionPtr compression) +{ + size_t i; + + memset(compression, 0, sizeof(*compression)); + + for (i = 0; i < nparams; i++) { + if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION)) + continue; + + if (STREQ(params[i].value.s, "xbzrle")) { + if (qemuAddCompressionMethod(QEMU_MIGRATION_COMPESS_XBZRLE, + &compression->method) < 0) + return -1; + } else if (STREQ(params[i].value.s, "multithread")) { + if (qemuAddCompressionMethod(QEMU_MIGRATION_COMPESS_MULTITHREAD, + &compression->method) < 0) + return -1; + } else { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Unsupported compression method")); + return -1; + } + } + + if (flags & VIR_MIGRATE_COMPRESSED) { + if (compression->method) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify default compression with " + "other compression parameters")); + return -1; + } + } + + return 0; +} + +static int qemuDomainMigratePrepare3Params(virConnectPtr dconn, virTypedParameterPtr params, int nparams, @@ -12418,6 +12472,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, int nmigrate_disks; const char **migrate_disks = NULL; char *origname = NULL; + qemuMigrationCompression compression; int ret = -1; virCheckFlagsGoto(QEMU_MIGRATION_FLAGS, cleanup); @@ -12445,6 +12500,9 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, if (nmigrate_disks < 0) goto cleanup; + if (qemuGetCompression(params, nparams, flags, &compression) < 0) + goto cleanup; + if (flags & VIR_MIGRATE_TUNNELLED) { /* this is a logical error; we never should have gotten here with * VIR_MIGRATE_TUNNELLED set @@ -12466,7 +12524,8 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, cookieout, cookieoutlen, uri_in, uri_out, &def, origname, listenAddress, - nmigrate_disks, migrate_disks, flags); + nmigrate_disks, migrate_disks, + &compression, flags); cleanup: VIR_FREE(migrate_disks); @@ -12600,7 +12659,7 @@ qemuDomainMigratePerform3(virDomainPtr dom, } return qemuMigrationPerform(driver, dom->conn, vm, xmlin, - dconnuri, uri, NULL, NULL, 0, NULL, + dconnuri, uri, NULL, NULL, 0, NULL, NULL, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, true); @@ -12627,6 +12686,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, int nmigrate_disks; const char **migrate_disks = NULL; unsigned long long bandwidth = 0; + qemuMigrationCompression compression; int ret = -1; virCheckFlags(QEMU_MIGRATION_FLAGS, -1); @@ -12660,6 +12720,9 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, if (nmigrate_disks < 0) goto cleanup; + if (qemuGetCompression(params, nparams, flags, &compression) < 0) + goto cleanup; + if (!(vm = qemuDomObjFromDomain(dom))) goto cleanup; @@ -12670,7 +12733,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, ret = qemuMigrationPerform(driver, dom->conn, vm, dom_xml, dconnuri, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, + nmigrate_disks, migrate_disks, &compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, bandwidth, true); cleanup: diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a6412ce..d37e416 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3300,6 +3300,37 @@ qemuMigrationPrepareIncoming(virDomainObjPtr vm, } static int +qemuMigrationSetCompression(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob job, + qemuMigrationCompressionPtr compression, + unsigned int flags) +{ + qemuMigrationCompression deflt; + + if (!compression) { + memset(&deflt, 0, sizeof(deflt)); + if (flags & VIR_MIGRATE_COMPRESSED) + deflt.method = QEMU_MIGRATION_COMPESS_XBZRLE; + compression = &deflt; + } + + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + compression->method & QEMU_MIGRATION_COMPESS_XBZRLE, + job) < 0) + return -1; + + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_COMPRESS, + compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD, + job) < 0) + return -1; + + return 0; +} + +static int qemuMigrationPrepareAny(virQEMUDriverPtr driver, virConnectPtr dconn, const char *cookiein, @@ -3315,6 +3346,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags) { virDomainObjPtr vm = NULL; @@ -3495,10 +3527,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, dataFD[1] = -1; /* 'st' owns the FD now & will close it */ } - if (qemuMigrationSetOption(driver, vm, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_IN) < 0) + if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN, + compression, flags) < 0) goto stopjob; if (STREQ_NULLABLE(protocol, "rdma") && @@ -3636,7 +3666,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver, ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - st, NULL, 0, false, NULL, 0, NULL, flags); + st, NULL, 0, false, NULL, 0, NULL, NULL, flags); return ret; } @@ -3678,6 +3708,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags) { unsigned short port = 0; @@ -3800,7 +3831,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, cookieout, cookieoutlen, def, origname, NULL, uri ? uri->scheme : "tcp", port, autoPort, listenAddress, - nmigrate_disks, migrate_disks, flags); + nmigrate_disks, migrate_disks, compression, + flags); cleanup: virURIFree(uri); VIR_FREE(hostname); @@ -4280,7 +4312,8 @@ qemuMigrationRun(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { int ret = -1; unsigned int migrate_flags = QEMU_MONITOR_MIGRATE_BACKGROUND; @@ -4362,10 +4395,8 @@ qemuMigrationRun(virQEMUDriverPtr driver, goto cleanup; } - if (qemuMigrationSetOption(driver, vm, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT, + compression, flags) < 0) goto cleanup; if (qemuMigrationSetOption(driver, vm, @@ -4579,7 +4610,8 @@ static int doNativeMigrate(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { qemuDomainObjPrivatePtr priv = vm->privateData; virURIPtr uribits = NULL; @@ -4629,7 +4661,8 @@ static int doNativeMigrate(virQEMUDriverPtr driver, ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, &spec, dconn, - graphicsuri, nmigrate_disks, migrate_disks); + graphicsuri, nmigrate_disks, migrate_disks, + compression); if (spec.destType == MIGRATION_DEST_FD) VIR_FORCE_CLOSE(spec.dest.fd.qemu); @@ -4653,7 +4686,8 @@ static int doTunnelMigrate(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { virNetSocketPtr sock = NULL; int ret = -1; @@ -4690,7 +4724,8 @@ static int doTunnelMigrate(virQEMUDriverPtr driver, ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, &spec, dconn, - graphicsuri, nmigrate_disks, migrate_disks); + graphicsuri, nmigrate_disks, migrate_disks, + compression); cleanup: if (spec.destType == MIGRATION_DEST_FD) { @@ -4801,12 +4836,12 @@ static int doPeer2PeerMigrate2(virQEMUDriverPtr driver, ret = doTunnelMigrate(driver, vm, st, NULL, 0, NULL, NULL, flags, resource, dconn, - NULL, 0, NULL); + NULL, 0, NULL, NULL); else ret = doNativeMigrate(driver, vm, uri_out, cookie, cookielen, NULL, NULL, /* No out cookie with v2 migration */ - flags, resource, dconn, NULL, 0, NULL); + flags, resource, dconn, NULL, 0, NULL, NULL); /* Perform failed. Make sure Finish doesn't overwrite the error */ if (ret < 0) @@ -4870,6 +4905,7 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long long bandwidth, bool useParams, unsigned long flags) @@ -5032,13 +5068,13 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, cookiein, cookieinlen, &cookieout, &cookieoutlen, flags, bandwidth, dconn, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression); } else { ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, &cookieout, &cookieoutlen, flags, bandwidth, dconn, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression); } /* Perform failed. Make sure Finish doesn't overwrite the error */ @@ -5213,6 +5249,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags, const char *dname, unsigned long resource, @@ -5326,8 +5363,8 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, if (*v3proto) { ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin, dname, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, resource, - useParams, flags); + nmigrate_disks, migrate_disks, compression, + resource, useParams, flags); } else { ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm, dconnuri, flags, dname, resource); @@ -5364,6 +5401,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5399,13 +5437,13 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) { ret = doPeer2PeerMigrate(driver, conn, vm, xmlin, dconnuri, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, + nmigrate_disks, migrate_disks, compression, flags, dname, resource, &v3proto); } else { qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2); ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, cookieout, cookieoutlen, - flags, resource, NULL, NULL, 0, NULL); + flags, resource, NULL, NULL, 0, NULL, NULL); } if (ret < 0) goto endjob; @@ -5465,6 +5503,7 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver, const char *graphicsuri, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5490,7 +5529,7 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver, ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, NULL, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression); if (ret < 0) { if (qemuMigrationRestoreDomainState(conn, vm)) { @@ -5532,6 +5571,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5561,7 +5601,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri, uri, graphicsuri, listenAddress, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); } else { @@ -5575,14 +5615,14 @@ qemuMigrationPerform(virQEMUDriverPtr driver, return qemuMigrationPerformPhase(driver, conn, vm, uri, graphicsuri, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource); } else { return qemuMigrationPerformJob(driver, conn, vm, xmlin, NULL, uri, graphicsuri, listenAddress, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); } diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 2445e13..45de616 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -25,6 +25,9 @@ # include "qemu_conf.h" # include "qemu_domain.h" +typedef struct _qemuMigrationCompression qemuMigrationCompression; +typedef qemuMigrationCompression *qemuMigrationCompressionPtr; + /* All supported qemu migration flags. */ # define QEMU_MIGRATION_FLAGS \ (VIR_MIGRATE_LIVE | \ @@ -53,6 +56,8 @@ VIR_MIGRATE_PARAM_LISTEN_ADDRESS, VIR_TYPED_PARAM_STRING, \ VIR_MIGRATE_PARAM_MIGRATE_DISKS, VIR_TYPED_PARAM_STRING | \ VIR_TYPED_PARAM_MULTIPLE, \ + VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | \ + VIR_TYPED_PARAM_MULTIPLE, \ NULL @@ -72,6 +77,15 @@ typedef enum { } qemuMigrationJobPhase; VIR_ENUM_DECL(qemuMigrationJobPhase) +typedef enum { + QEMU_MIGRATION_COMPESS_XBZRLE = (1 << 0), + QEMU_MIGRATION_COMPESS_MULTITHREAD = (1 << 1), +} qemuMigrationCompressMethod; + +struct _qemuMigrationCompression { + qemuMigrationCompressMethod method; +}; + int qemuMigrationJobStart(virQEMUDriverPtr driver, virDomainObjPtr vm, qemuDomainAsyncJob job) @@ -134,6 +148,7 @@ int qemuMigrationPrepareDirect(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags); int qemuMigrationPerform(virQEMUDriverPtr driver, @@ -146,6 +161,7 @@ int qemuMigrationPerform(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 6b23e88..cf1cdfb 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -167,7 +167,7 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus, VIR_ENUM_IMPL(qemuMonitorMigrationCaps, QEMU_MONITOR_MIGRATION_CAPS_LAST, - "xbzrle", "auto-converge", "rdma-pin-all", "events") + "xbzrle", "auto-converge", "rdma-pin-all", "events", "compress") VIR_ENUM_IMPL(qemuMonitorVMStatus, QEMU_MONITOR_VM_STATUS_LAST, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 9d7d5f3..c2a0ed6 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -525,6 +525,7 @@ typedef enum { QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, QEMU_MONITOR_MIGRATION_CAPS_EVENTS, + QEMU_MONITOR_MIGRATION_CAPS_COMPRESS, QEMU_MONITOR_MIGRATION_CAPS_LAST } qemuMonitorMigrationCaps; -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 13 +++++- src/qemu/qemu_driver.c | 75 +++++++++++++++++++++++++++++--- src/qemu/qemu_migration.c | 94 ++++++++++++++++++++++++++++------------ src/qemu/qemu_migration.h | 16 +++++++ src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 1 + 6 files changed, 166 insertions(+), 35 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 65f1618..e868515 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -655,7 +655,7 @@ typedef enum { * when supported */ VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */ VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ - VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ + VIR_MIGRATE_COMPRESSED = (1 << 11), /* use default compression method */ VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */ VIR_MIGRATE_AUTO_CONVERGE = (1 << 13), /* force convergence */ VIR_MIGRATE_RDMA_PIN_ALL = (1 << 14), /* RDMA memory pinning */ @@ -757,6 +757,17 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_MIGRATE_DISKS "migrate_disks"
+/** + * VIR_MIGRATE_PARAM_COMPRESSION: + * + * virDomainMigrate* params multiple field: string list of compression methods + * that are used to compress migration traffic. Note that this option cannot + * be used together with VIR_MIGRATE_COMPRESSED flag, use only one of them. + */ + +# define VIR_MIGRATE_PARAM_COMPRESSION "compression" + + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 351e529..129da6d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12163,7 +12163,7 @@ qemuDomainMigratePrepare2(virConnectPtr dconn, ret = qemuMigrationPrepareDirect(driver, dconn, NULL, 0, NULL, NULL, /* No cookies */ uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags);
cleanup: VIR_FREE(origname); @@ -12216,7 +12216,7 @@ qemuDomainMigratePerform(virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - NULL, dconnuri, uri, NULL, NULL, 0, NULL, + NULL, dconnuri, uri, NULL, NULL, 0, NULL, NULL, cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, false); @@ -12389,7 +12389,7 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags);
cleanup: VIR_FREE(origname); @@ -12398,6 +12398,60 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, }
static int +qemuAddCompressionMethod(qemuMigrationCompressMethod value, + qemuMigrationCompressMethod *method) +{ + if (*method & value) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Compression method is specified twice.")); + return -1; + } + + *method |= value; + return 0; +} + +static int +qemuGetCompression(virTypedParameterPtr params, int nparams, + unsigned int flags, + qemuMigrationCompressionPtr compression) +{ + size_t i; + + memset(compression, 0, sizeof(*compression)); + + for (i = 0; i < nparams; i++) { + if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION)) + continue; + + if (STREQ(params[i].value.s, "xbzrle")) { + if (qemuAddCompressionMethod(QEMU_MIGRATION_COMPESS_XBZRLE, + &compression->method) < 0) + return -1; + } else if (STREQ(params[i].value.s, "multithread")) { + if (qemuAddCompressionMethod(QEMU_MIGRATION_COMPESS_MULTITHREAD, + &compression->method) < 0) + return -1; + } else { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Unsupported compression method")); + return -1; + } + } + + if (flags & VIR_MIGRATE_COMPRESSED) { + if (compression->method) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify default compression with " + "other compression parameters")); + return -1; + } + } + + return 0; +} + +static int qemuDomainMigratePrepare3Params(virConnectPtr dconn, virTypedParameterPtr params, int nparams, @@ -12418,6 +12472,7 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, int nmigrate_disks; const char **migrate_disks = NULL; char *origname = NULL; + qemuMigrationCompression compression; int ret = -1;
virCheckFlagsGoto(QEMU_MIGRATION_FLAGS, cleanup); @@ -12445,6 +12500,9 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, if (nmigrate_disks < 0) goto cleanup;
+ if (qemuGetCompression(params, nparams, flags, &compression) < 0) + goto cleanup; + if (flags & VIR_MIGRATE_TUNNELLED) { /* this is a logical error; we never should have gotten here with * VIR_MIGRATE_TUNNELLED set @@ -12466,7 +12524,8 @@ qemuDomainMigratePrepare3Params(virConnectPtr dconn, cookieout, cookieoutlen, uri_in, uri_out, &def, origname, listenAddress, - nmigrate_disks, migrate_disks, flags); + nmigrate_disks, migrate_disks, + &compression, flags);
cleanup: VIR_FREE(migrate_disks); @@ -12600,7 +12659,7 @@ qemuDomainMigratePerform3(virDomainPtr dom, }
return qemuMigrationPerform(driver, dom->conn, vm, xmlin, - dconnuri, uri, NULL, NULL, 0, NULL, + dconnuri, uri, NULL, NULL, 0, NULL, NULL, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, true); @@ -12627,6 +12686,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, int nmigrate_disks; const char **migrate_disks = NULL; unsigned long long bandwidth = 0; + qemuMigrationCompression compression; int ret = -1;
virCheckFlags(QEMU_MIGRATION_FLAGS, -1); @@ -12660,6 +12720,9 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, if (nmigrate_disks < 0) goto cleanup;
+ if (qemuGetCompression(params, nparams, flags, &compression) < 0) + goto cleanup; + if (!(vm = qemuDomObjFromDomain(dom))) goto cleanup;
@@ -12670,7 +12733,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom,
ret = qemuMigrationPerform(driver, dom->conn, vm, dom_xml, dconnuri, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, + nmigrate_disks, migrate_disks, &compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, bandwidth, true); cleanup: diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a6412ce..d37e416 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3300,6 +3300,37 @@ qemuMigrationPrepareIncoming(virDomainObjPtr vm, }
static int +qemuMigrationSetCompression(virQEMUDriverPtr driver, + virDomainObjPtr vm, + qemuDomainAsyncJob job, + qemuMigrationCompressionPtr compression, + unsigned int flags) +{ + qemuMigrationCompression deflt; + + if (!compression) { + memset(&deflt, 0, sizeof(deflt)); + if (flags & VIR_MIGRATE_COMPRESSED) + deflt.method = QEMU_MIGRATION_COMPESS_XBZRLE; + compression = &deflt; + } + + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + compression->method & QEMU_MIGRATION_COMPESS_XBZRLE, + job) < 0) + return -1; + + if (qemuMigrationSetOption(driver, vm, + QEMU_MONITOR_MIGRATION_CAPS_COMPRESS, + compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD, + job) < 0) + return -1; + + return 0; +} + +static int qemuMigrationPrepareAny(virQEMUDriverPtr driver, virConnectPtr dconn, const char *cookiein, @@ -3315,6 +3346,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags) { virDomainObjPtr vm = NULL; @@ -3495,10 +3527,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, dataFD[1] = -1; /* 'st' owns the FD now & will close it */ }
- if (qemuMigrationSetOption(driver, vm, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_IN) < 0) + if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN, + compression, flags) < 0) goto stopjob;
if (STREQ_NULLABLE(protocol, "rdma") && @@ -3636,7 +3666,7 @@ qemuMigrationPrepareTunnel(virQEMUDriverPtr driver,
ret = qemuMigrationPrepareAny(driver, dconn, cookiein, cookieinlen, cookieout, cookieoutlen, def, origname, - st, NULL, 0, false, NULL, 0, NULL, flags); + st, NULL, 0, false, NULL, 0, NULL, NULL, flags); return ret; }
@@ -3678,6 +3708,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags) { unsigned short port = 0; @@ -3800,7 +3831,8 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, cookieout, cookieoutlen, def, origname, NULL, uri ? uri->scheme : "tcp", port, autoPort, listenAddress, - nmigrate_disks, migrate_disks, flags); + nmigrate_disks, migrate_disks, compression, + flags); cleanup: virURIFree(uri); VIR_FREE(hostname); @@ -4280,7 +4312,8 @@ qemuMigrationRun(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { int ret = -1; unsigned int migrate_flags = QEMU_MONITOR_MIGRATE_BACKGROUND; @@ -4362,10 +4395,8 @@ qemuMigrationRun(virQEMUDriverPtr driver, goto cleanup; }
- if (qemuMigrationSetOption(driver, vm, - QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, - flags & VIR_MIGRATE_COMPRESSED, - QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + if (qemuMigrationSetCompression(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT, + compression, flags) < 0) goto cleanup;
if (qemuMigrationSetOption(driver, vm, @@ -4579,7 +4610,8 @@ static int doNativeMigrate(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { qemuDomainObjPrivatePtr priv = vm->privateData; virURIPtr uribits = NULL; @@ -4629,7 +4661,8 @@ static int doNativeMigrate(virQEMUDriverPtr driver,
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, &spec, dconn, - graphicsuri, nmigrate_disks, migrate_disks); + graphicsuri, nmigrate_disks, migrate_disks, + compression);
if (spec.destType == MIGRATION_DEST_FD) VIR_FORCE_CLOSE(spec.dest.fd.qemu); @@ -4653,7 +4686,8 @@ static int doTunnelMigrate(virQEMUDriverPtr driver, virConnectPtr dconn, const char *graphicsuri, size_t nmigrate_disks, - const char **migrate_disks) + const char **migrate_disks, + qemuMigrationCompressionPtr compression) { virNetSocketPtr sock = NULL; int ret = -1; @@ -4690,7 +4724,8 @@ static int doTunnelMigrate(virQEMUDriverPtr driver,
ret = qemuMigrationRun(driver, vm, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, &spec, dconn, - graphicsuri, nmigrate_disks, migrate_disks); + graphicsuri, nmigrate_disks, migrate_disks, + compression);
cleanup: if (spec.destType == MIGRATION_DEST_FD) { @@ -4801,12 +4836,12 @@ static int doPeer2PeerMigrate2(virQEMUDriverPtr driver, ret = doTunnelMigrate(driver, vm, st, NULL, 0, NULL, NULL, flags, resource, dconn, - NULL, 0, NULL); + NULL, 0, NULL, NULL); else ret = doNativeMigrate(driver, vm, uri_out, cookie, cookielen, NULL, NULL, /* No out cookie with v2 migration */ - flags, resource, dconn, NULL, 0, NULL); + flags, resource, dconn, NULL, 0, NULL, NULL);
/* Perform failed. Make sure Finish doesn't overwrite the error */ if (ret < 0) @@ -4870,6 +4905,7 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long long bandwidth, bool useParams, unsigned long flags) @@ -5032,13 +5068,13 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, cookiein, cookieinlen, &cookieout, &cookieoutlen, flags, bandwidth, dconn, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression); } else { ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, &cookieout, &cookieoutlen, flags, bandwidth, dconn, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression); }
/* Perform failed. Make sure Finish doesn't overwrite the error */ @@ -5213,6 +5249,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags, const char *dname, unsigned long resource, @@ -5326,8 +5363,8 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver, if (*v3proto) { ret = doPeer2PeerMigrate3(driver, sconn, dconn, dconnuri, vm, xmlin, dname, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, resource, - useParams, flags); + nmigrate_disks, migrate_disks, compression, + resource, useParams, flags); } else { ret = doPeer2PeerMigrate2(driver, sconn, dconn, vm, dconnuri, flags, dname, resource); @@ -5364,6 +5401,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5399,13 +5437,13 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver, if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) { ret = doPeer2PeerMigrate(driver, conn, vm, xmlin, dconnuri, uri, graphicsuri, listenAddress, - nmigrate_disks, migrate_disks, + nmigrate_disks, migrate_disks, compression, flags, dname, resource, &v3proto); } else { qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM2); ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, cookieout, cookieoutlen, - flags, resource, NULL, NULL, 0, NULL); + flags, resource, NULL, NULL, 0, NULL, NULL); } if (ret < 0) goto endjob; @@ -5465,6 +5503,7 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver, const char *graphicsuri, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5490,7 +5529,7 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver, ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource, NULL, graphicsuri, - nmigrate_disks, migrate_disks); + nmigrate_disks, migrate_disks, compression);
if (ret < 0) { if (qemuMigrationRestoreDomainState(conn, vm)) { @@ -5532,6 +5571,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, @@ -5561,7 +5601,7 @@ qemuMigrationPerform(virQEMUDriverPtr driver, return qemuMigrationPerformJob(driver, conn, vm, xmlin, dconnuri, uri, graphicsuri, listenAddress, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); } else { @@ -5575,14 +5615,14 @@ qemuMigrationPerform(virQEMUDriverPtr driver, return qemuMigrationPerformPhase(driver, conn, vm, uri, graphicsuri, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, resource); } else { return qemuMigrationPerformJob(driver, conn, vm, xmlin, NULL, uri, graphicsuri, listenAddress, nmigrate_disks, migrate_disks, - cookiein, cookieinlen, + compression, cookiein, cookieinlen, cookieout, cookieoutlen, flags, dname, resource, v3proto); } diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 2445e13..45de616 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -25,6 +25,9 @@ # include "qemu_conf.h" # include "qemu_domain.h"
+typedef struct _qemuMigrationCompression qemuMigrationCompression; +typedef qemuMigrationCompression *qemuMigrationCompressionPtr; + /* All supported qemu migration flags. */ # define QEMU_MIGRATION_FLAGS \ (VIR_MIGRATE_LIVE | \ @@ -53,6 +56,8 @@ VIR_MIGRATE_PARAM_LISTEN_ADDRESS, VIR_TYPED_PARAM_STRING, \ VIR_MIGRATE_PARAM_MIGRATE_DISKS, VIR_TYPED_PARAM_STRING | \ VIR_TYPED_PARAM_MULTIPLE, \ + VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | \ + VIR_TYPED_PARAM_MULTIPLE, \ NULL
@@ -72,6 +77,15 @@ typedef enum { } qemuMigrationJobPhase; VIR_ENUM_DECL(qemuMigrationJobPhase)
+typedef enum { + QEMU_MIGRATION_COMPESS_XBZRLE = (1 << 0), + QEMU_MIGRATION_COMPESS_MULTITHREAD = (1 << 1), +} qemuMigrationCompressMethod; + +struct _qemuMigrationCompression { + qemuMigrationCompressMethod method; +}; + int qemuMigrationJobStart(virQEMUDriverPtr driver, virDomainObjPtr vm, qemuDomainAsyncJob job) @@ -134,6 +148,7 @@ int qemuMigrationPrepareDirect(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, unsigned long flags);
int qemuMigrationPerform(virQEMUDriverPtr driver, @@ -146,6 +161,7 @@ int qemuMigrationPerform(virQEMUDriverPtr driver, const char *listenAddress, size_t nmigrate_disks, const char **migrate_disks, + qemuMigrationCompressionPtr compression, const char *cookiein, int cookieinlen, char **cookieout, diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 6b23e88..cf1cdfb 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -167,7 +167,7 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
VIR_ENUM_IMPL(qemuMonitorMigrationCaps, QEMU_MONITOR_MIGRATION_CAPS_LAST, - "xbzrle", "auto-converge", "rdma-pin-all", "events") + "xbzrle", "auto-converge", "rdma-pin-all", "events", "compress")
VIR_ENUM_IMPL(qemuMonitorVMStatus, QEMU_MONITOR_VM_STATUS_LAST, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 9d7d5f3..c2a0ed6 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -525,6 +525,7 @@ typedef enum { QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, QEMU_MONITOR_MIGRATION_CAPS_RDMA_PIN_ALL, QEMU_MONITOR_MIGRATION_CAPS_EVENTS, + QEMU_MONITOR_MIGRATION_CAPS_COMPRESS,
QEMU_MONITOR_MIGRATION_CAPS_LAST } qemuMonitorMigrationCaps; Looks good to me.

I still think that to enable migration in a nice backward compatible way, a user should use VIR_MIGRATE_COMPRESSED flag *and* optionally select the compression algorithm(s) via VIR_MIGRATE_PARAM_COMPRESSION parameter. If VIR_MIGRATE_PARAM_COMPRESSION is not used, the hypervisor (driver) will choose a default method. On Thu, Jan 28, 2016 at 10:04:28 +0300, Nikolay Shirokovskiy wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 13 +++++- src/qemu/qemu_driver.c | 75 +++++++++++++++++++++++++++++--- src/qemu/qemu_migration.c | 94 ++++++++++++++++++++++++++++------------ src/qemu/qemu_migration.h | 16 +++++++ src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 1 + 6 files changed, 166 insertions(+), 35 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 65f1618..e868515 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -655,7 +655,7 @@ typedef enum { * when supported */ VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */ VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ - VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ + VIR_MIGRATE_COMPRESSED = (1 << 11), /* use default compression method */
I'd imagine something like "compress data during migration using a method selected by the hypervisor or via VIR_MIGRATE_PARAM_COMPRESSION parameter.
VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */ VIR_MIGRATE_AUTO_CONVERGE = (1 << 13), /* force convergence */ VIR_MIGRATE_RDMA_PIN_ALL = (1 << 14), /* RDMA memory pinning */ @@ -757,6 +757,17 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_MIGRATE_DISKS "migrate_disks"
+/** + * VIR_MIGRATE_PARAM_COMPRESSION: + * + * virDomainMigrate* params multiple field: string list of compression methods + * that are used to compress migration traffic. Note that this option cannot + * be used together with VIR_MIGRATE_COMPRESSED flag, use only one of them.
I'd drop the last sentence.
+ */ +
This empty line should be dropped.
+# define VIR_MIGRATE_PARAM_COMPRESSION "compression" + + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 351e529..129da6d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12163,7 +12163,7 @@ qemuDomainMigratePrepare2(virConnectPtr dconn, ret = qemuMigrationPrepareDirect(driver, dconn, NULL, 0, NULL, NULL, /* No cookies */ uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags);
cleanup: VIR_FREE(origname); @@ -12216,7 +12216,7 @@ qemuDomainMigratePerform(virDomainPtr dom, * Consume any cookie we were able to decode though */ ret = qemuMigrationPerform(driver, dom->conn, vm, - NULL, dconnuri, uri, NULL, NULL, 0, NULL, + NULL, dconnuri, uri, NULL, NULL, 0, NULL, NULL, cookie, cookielen, NULL, NULL, /* No output cookies in v2 */ flags, dname, resource, false); @@ -12389,7 +12389,7 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in, uri_out, - &def, origname, NULL, 0, NULL, flags); + &def, origname, NULL, 0, NULL, NULL, flags);
cleanup: VIR_FREE(origname); @@ -12398,6 +12398,60 @@ qemuDomainMigratePrepare3(virConnectPtr dconn, }
static int +qemuAddCompressionMethod(qemuMigrationCompressMethod value, + qemuMigrationCompressMethod *method) +{ + if (*method & value) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Compression method is specified twice.")); + return -1; + } + + *method |= value; + return 0; +} + +static int +qemuGetCompression(virTypedParameterPtr params, int nparams, + unsigned int flags, + qemuMigrationCompressionPtr compression) +{ + size_t i; + + memset(compression, 0, sizeof(*compression));
Hmm, I think qemuMigrationCompression structure should be allocated on the heap (rather than on the stack) and the allocator would also take care of setting appropriate "unspecified" values. And please, move these migration related functions in qemu_migrate.c. Jirka

On 05.02.2016 18:34, Jiri Denemark wrote:
I still think that to enable migration in a nice backward compatible way, a user should use VIR_MIGRATE_COMPRESSED flag *and* optionally select the compression algorithm(s) via VIR_MIGRATE_PARAM_COMPRESSION parameter. If VIR_MIGRATE_PARAM_COMPRESSION is not used, the hypervisor (driver) will choose a default method.
On Thu, Jan 28, 2016 at 10:04:28 +0300, Nikolay Shirokovskiy wrote:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 13 +++++- src/qemu/qemu_driver.c | 75 +++++++++++++++++++++++++++++--- src/qemu/qemu_migration.c | 94 ++++++++++++++++++++++++++++------------ src/qemu/qemu_migration.h | 16 +++++++ src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor.h | 1 + 6 files changed, 166 insertions(+), 35 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 65f1618..e868515 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -655,7 +655,7 @@ typedef enum { * when supported */ VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */ VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ - VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ + VIR_MIGRATE_COMPRESSED = (1 << 11), /* use default compression method */
I'd imagine something like "compress data during migration using a method selected by the hypervisor or via VIR_MIGRATE_PARAM_COMPRESSION parameter.
ok
+static int +qemuGetCompression(virTypedParameterPtr params, int nparams, + unsigned int flags, + qemuMigrationCompressionPtr compression) +{ + size_t i; + + memset(compression, 0, sizeof(*compression));
Hmm, I think qemuMigrationCompression structure should be allocated on the heap (rather than on the stack) and the allocator would also take care of setting appropriate "unspecified" values. And please, move these migration related functions in qemu_migrate.c.
ok
Jirka

From: ShaoHe Feng <shaohe.feng@intel.com> Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters. Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++ 6 files changed, 242 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index cf1cdfb..e9b1ce4 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2116,6 +2116,35 @@ qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon, int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONGetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextGetMigrationCompressParametersMT(mon, params); +} + +int +qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + VIR_DEBUG("level=%d threads=%d dthreads=%d", params->level, + params->threads, + params->dthreads); + + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONSetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextSetMigrationCompressParametersMT(mon, params); +} + + +int qemuMonitorGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2a0ed6..5a5e0e2 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -463,6 +463,22 @@ int qemuMonitorGetMigrationCacheSize(qemuMonitorPtr mon, int qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon, unsigned long long cacheSize); +typedef struct _qemuMonitorMigrationMTParameters qemuMonitorMigrationMTParameters; +typedef qemuMonitorMigrationMTParameters *qemuMonitorMigrationMTParametersPtr; +struct _qemuMonitorMigrationMTParameters { + /* -1 is value of unspecified */ + int level; + /* 0 is value of unspecified */ + unsigned int threads; + /* 0 is value of unspecified */ + unsigned int dthreads; +}; + +int qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + typedef enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_SETUP, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 24a8865..62aba88 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2437,6 +2437,93 @@ qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon, } +int qemuMonitorJSONGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr result; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if ((cmd = qemuMonitorJSONMakeCommand("query-migrate-parameters", NULL)) == NULL) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if ((ret = qemuMonitorJSONCheckError(cmd, reply)) < 0) + goto cleanup; + + if (!(result = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-migrate-parameters reply was missing " + "'return' data")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberInt(result, "compress-level", + ¶ms->level) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-level " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "compress-threads", + ¶ms->threads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "decompress-threads", + ¶ms->dthreads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing decompress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (params->level < 0 || params->threads < 1 || params->dthreads < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected compress parameters")); + goto cleanup; + } + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + ret = qemuMonitorJSONCheckError(cmd, reply); + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + static int qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply, qemuMonitorMigrationStatsPtr stats) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 2c27c6f..e10f7c7 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -123,6 +123,11 @@ int qemuMonitorJSONGetMigrationCacheSize(qemuMonitorPtr mon, int qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon, unsigned long long cacheSize); +int qemuMonitorJSONGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index bb87397..a3768df 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1345,6 +1345,106 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, } +int qemuMonitorTextGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + char *reply = NULL; + int ret = -1; + char *end; + char *p; + + if (qemuMonitorHMPCommand(mon, "info migrate_parameters", &reply) < 0) + goto cleanup; + + if (STRPREFIX(reply, "unknown command:")) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Command 'info migrate_parameters' is not found")); + goto cleanup; + } + + /* reply is like: + * parameters: compress-level: 1 compress-threads: 8 decompress-threads: 2 + */ + +#define parseCompressionParameter(name, parse, value) \ + if ((p = strstr(reply, name)) == NULL) \ + goto cleanup; \ + if (parse(p + strlen(name), &end, 10, &value) < 0) \ + goto cleanup; + + parseCompressionParameter("compress-level: ", + virStrToLong_i, params->level) + parseCompressionParameter("compress-threads: ", + virStrToLong_ui, params->threads) + parseCompressionParameter("decompress-threads: ", + virStrToLong_ui, params->dthreads) + +#undef parseCompressionParameter + + if (params->level < 0 || params->threads < 1 || params->dthreads < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected compress parameters")); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(reply); + return ret; +} + +/* frees cmd */ +static +int executeHMPCommand(qemuMonitorPtr mon, char *cmd) +{ + char *reply = NULL; + int ret = -1; + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (STRPREFIX(reply, "unknown command:")) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Command 'migrate_set_parameter' is not found")); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + +int qemuMonitorTextSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + char *cmd = NULL; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-level %d", + params->level) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-threads %u", + params->threads) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-dthreads %u", + params->dthreads) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + return 0; +} + + #define MIGRATION_PREFIX "Migration status: " #define MIGRATION_TRANSFER_PREFIX "transferred ram: " #define MIGRATION_REMAINING_PREFIX "remaining ram: " diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 44a5330..e6022a9 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -106,6 +106,11 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, int qemuMonitorTextGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats); +int qemuMonitorTextGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorTextSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + int qemuMonitorTextMigrate(qemuMonitorPtr mon, unsigned int flags, const char *uri); -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Comments inline. Otherwise ACK.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++ 6 files changed, 242 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index cf1cdfb..e9b1ce4 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2116,6 +2116,35 @@ qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon,
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONGetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextGetMigrationCompressParametersMT(mon, params); +} + +int +qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + VIR_DEBUG("level=%d threads=%d dthreads=%d", params->level, + params->threads, + params->dthreads); + + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONSetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextSetMigrationCompressParametersMT(mon, params); +} + + +int qemuMonitorGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2a0ed6..5a5e0e2 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -463,6 +463,22 @@ int qemuMonitorGetMigrationCacheSize(qemuMonitorPtr mon, int qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon, unsigned long long cacheSize);
+typedef struct _qemuMonitorMigrationMTParameters qemuMonitorMigrationMTParameters; +typedef qemuMonitorMigrationMTParameters *qemuMonitorMigrationMTParametersPtr; +struct _qemuMonitorMigrationMTParameters { + /* -1 is value of unspecified */ + int level; + /* 0 is value of unspecified */ + unsigned int threads; + /* 0 is value of unspecified */ + unsigned int dthreads; +}; + +int qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + typedef enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_SETUP, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 24a8865..62aba88 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2437,6 +2437,93 @@ qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon, }
+int qemuMonitorJSONGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr result; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if ((cmd = qemuMonitorJSONMakeCommand("query-migrate-parameters", NULL)) == NULL) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if ((ret = qemuMonitorJSONCheckError(cmd, reply)) < 0) + goto cleanup; + + if (!(result = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-migrate-parameters reply was missing " + "'return' data")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberInt(result, "compress-level", + ¶ms->level) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-level " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "compress-threads", + ¶ms->threads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "decompress-threads", + ¶ms->dthreads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing decompress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (params->level < 0 || params->threads < 1 || params->dthreads < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected compress parameters")); + goto cleanup; + } + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL); + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + ret = qemuMonitorJSONCheckError(cmd, reply); + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + static int qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply, qemuMonitorMigrationStatsPtr stats) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 2c27c6f..e10f7c7 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -123,6 +123,11 @@ int qemuMonitorJSONGetMigrationCacheSize(qemuMonitorPtr mon, int qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon, unsigned long long cacheSize);
+int qemuMonitorJSONGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index bb87397..a3768df 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1345,6 +1345,106 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, }
+int qemuMonitorTextGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + char *reply = NULL; + int ret = -1; + char *end; + char *p; + + if (qemuMonitorHMPCommand(mon, "info migrate_parameters", &reply) < 0) + goto cleanup; + + if (STRPREFIX(reply, "unknown command:")) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Command 'info migrate_parameters' is not found")); + goto cleanup; + } + + /* reply is like: + * parameters: compress-level: 1 compress-threads: 8 decompress-threads: 2 + */ + +#define parseCompressionParameter(name, parse, value) \ + if ((p = strstr(reply, name)) == NULL) \ + goto cleanup; \ + if (parse(p + strlen(name), &end, 10, &value) < 0) \ + goto cleanup; + + parseCompressionParameter("compress-level: ", + virStrToLong_i, params->level) + parseCompressionParameter("compress-threads: ", + virStrToLong_ui, params->threads) + parseCompressionParameter("decompress-threads: ", + virStrToLong_ui, params->dthreads) + +#undef parseCompressionParameter + + if (params->level < 0 || params->threads < 1 || params->dthreads < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected compress parameters")); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(reply); + return ret; +} + +/* frees cmd */ I don't like such a comment because it doesn't explain anything rather it makes me think that the function does nothing but frees cmd, which is wrong. +static +int executeHMPCommand(qemuMonitorPtr mon, char *cmd)
Maybe name it qemuMigrateSetHMPCommandFreeCmd then?
+{ + char *reply = NULL; + int ret = -1; + + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (STRPREFIX(reply, "unknown command:")) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Command 'migrate_set_parameter' is not found")); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(reply); + VIR_FREE(cmd); + return ret; +} + +int qemuMonitorTextSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + char *cmd = NULL; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-level %d", + params->level) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-threads %u", + params->threads) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + if (virAsprintf(&cmd, "migrate_set_parameter compress-dthreads %u", + params->dthreads) < 0) + return -1; + if (executeHMPCommand(mon, cmd) < 0) + return -1; + + return 0; +} + + #define MIGRATION_PREFIX "Migration status: " #define MIGRATION_TRANSFER_PREFIX "transferred ram: " #define MIGRATION_REMAINING_PREFIX "remaining ram: " diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 44a5330..e6022a9 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -106,6 +106,11 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, int qemuMonitorTextGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats);
+int qemuMonitorTextGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorTextSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + int qemuMonitorTextMigrate(qemuMonitorPtr mon, unsigned int flags, const char *uri);

On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
Please, remove everything related to HMP monitor, multithreaded compression is not supported by any QEMU for which we would use text monitor.
6 files changed, 242 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index cf1cdfb..e9b1ce4 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2116,6 +2116,35 @@ qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon,
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
+{ + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONGetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextGetMigrationCompressParametersMT(mon, params);
Since support for text monitor is not desirable, this function will be as simple as QEMU_CHECK_MONITOR_JSON(mon); return qemuMonitorJSON...;
+} + +int +qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + VIR_DEBUG("level=%d threads=%d dthreads=%d", params->level, + params->threads, + params->dthreads);
Either VIR_DEBUG("level=%d threads=%d dthreads=%d", params->level, params->threads, params->dthreads); or VIR_DEBUG("level=%d threads=%d dthreads=%d", params->level, params->threads, params->dthreads);
+ + QEMU_CHECK_MONITOR(mon); + + if (mon->json) + return qemuMonitorJSONSetMigrationCompressParametersMT(mon, params); + else + return qemuMonitorTextSetMigrationCompressParametersMT(mon, params); +} + + +int qemuMonitorGetMigrationStats(qemuMonitorPtr mon, qemuMonitorMigrationStatsPtr stats) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c2a0ed6..5a5e0e2 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -463,6 +463,22 @@ int qemuMonitorGetMigrationCacheSize(qemuMonitorPtr mon, int qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon, unsigned long long cacheSize);
+typedef struct _qemuMonitorMigrationMTParameters qemuMonitorMigrationMTParameters; +typedef qemuMonitorMigrationMTParameters *qemuMonitorMigrationMTParametersPtr; +struct _qemuMonitorMigrationMTParameters { + /* -1 is value of unspecified */ + int level; + /* 0 is value of unspecified */ + unsigned int threads; + /* 0 is value of unspecified */ + unsigned int dthreads; +}; + +int qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); +int qemuMonitorSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params); + typedef enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_SETUP, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 24a8865..62aba88 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2437,6 +2437,93 @@ qemuMonitorJSONSetMigrationCacheSize(qemuMonitorPtr mon, }
+int qemuMonitorJSONGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr result; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if ((cmd = qemuMonitorJSONMakeCommand("query-migrate-parameters", NULL)) == NULL) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + if ((ret = qemuMonitorJSONCheckError(cmd, reply)) < 0) + goto cleanup; + + if (!(result = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-migrate-parameters reply was missing " + "'return' data")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberInt(result, "compress-level", + ¶ms->level) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-level " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "compress-threads", + ¶ms->threads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing compress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(result, "decompress-threads", + ¶ms->dthreads) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing decompress-threads " + "in migrate parameters")); + goto cleanup; + } + + if (params->level < 0 || params->threads < 1 || params->dthreads < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected compress parameters")); + goto cleanup; + } + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
+ if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0) + goto cleanup; + + ret = qemuMonitorJSONCheckError(cmd, reply); + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + ...
Jirka

On 04.02.2016 21:11, Jiri Denemark wrote:
On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
AFAIK it is not so. We can't set(get) xbzrle options (only size now) and multithread options togather. We neet "query-migrate-cache-size" for the first and "query-migrate-parameters" for the second.
+int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
QEMU is good enough to take partial parameters specs. In this case the other just stay untouched. But I never use this command in this mode and specify all parameters. I do it to make sure we don't get compression parameters from previous failed migration attempt. See patch number 5. Basically instead of reverting parameters on unsuccessful migration I use hardcoded default values for parameters that are not specified on migration.

On Fri, Feb 05, 2016 at 18:01:30 +0300, Nikolay Shirokovskiy wrote:
On 04.02.2016 21:11, Jiri Denemark wrote:
On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
AFAIK it is not so. We can't set(get) xbzrle options (only size now) and multithread options togather. We neet "query-migrate-cache-size" for the first and "query-migrate-parameters" for the second.
Yes, that's true. I didn't explicitly say so, but I was thinking about future additions to query-migrate-perameters. It's very likely that new parameters will be added and I think we should cover them all in one QMP call. Rather than calling several qemuMonitorGet* functions which would all run query-migrate-perameters command, but each of them would be interested only in a subset of parameters. We did similar stuff in the past with some query-block... command which we called for every single disk again and again even though it returned all of them at once. It's cleaner to just call it once, fill in a structure describing the whole reply and do the filtering one layer up to avoid calling the same command and parsing the same reply several times.
+int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
QEMU is good enough to take partial parameters specs. In this case the other just stay untouched. But I never use this command in this mode and specify all parameters. I do it to make sure we don't get compression parameters from previous failed migration attempt. See patch number 5.
Yeah, I saw that and it was the reason I asked the question :-)
Basically instead of reverting parameters on unsuccessful migration I use hardcoded default values for parameters that are not specified on migration.
Somehow I don't like the hardcoded default values. Either we should force users to specify all parameters or we could check current values from QEMU, change some of them as requested by a user, migrate, and revert the values back to their original values. Or we can just let another migration attempt reuse the previous values (as we do with other parameters, I believe). Jirka

On 05.02.2016 18:24, Jiri Denemark wrote:
On Fri, Feb 05, 2016 at 18:01:30 +0300, Nikolay Shirokovskiy wrote:
On 04.02.2016 21:11, Jiri Denemark wrote:
On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
AFAIK it is not so. We can't set(get) xbzrle options (only size now) and multithread options togather. We neet "query-migrate-cache-size" for the first and "query-migrate-parameters" for the second.
Yes, that's true. I didn't explicitly say so, but I was thinking about future additions to query-migrate-perameters. It's very likely that new parameters will be added and I think we should cover them all in one QMP call. Rather than calling several qemuMonitorGet* functions which would all run query-migrate-perameters command, but each of them would be interested only in a subset of parameters.
We did similar stuff in the past with some query-block... command which we called for every single disk again and again even though it returned all of them at once. It's cleaner to just call it once, fill in a structure describing the whole reply and do the filtering one layer up to avoid calling the same command and parsing the same reply several times.
I see. So it basically about naming. I'll use 'migrate parameters' without specifying explicitly current set of multihreaded in name.
+int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
QEMU is good enough to take partial parameters specs. In this case the other just stay untouched. But I never use this command in this mode and specify all parameters. I do it to make sure we don't get compression parameters from previous failed migration attempt. See patch number 5.
Yeah, I saw that and it was the reason I asked the question :-)
Basically instead of reverting parameters on unsuccessful migration I use hardcoded default values for parameters that are not specified on migration.
Somehow I don't like the hardcoded default values. Either we should force users to specify all parameters or we could check current values from QEMU, change some of them as requested by a user, migrate, and revert the values back to their original values. Or we can just let another migration attempt reuse the previous values (as we do with other parameters, I believe).
I don't like hardcodes here either. I cannot find a reference but I wrote the series with а explicit requirement in mind that migration command should be reproducible. I recollect that you or Daniel formulated it in the discussion of previous versions of series. If it so then reusing options from previous migration is not an option. Do we really have such a goal or it just some glitch in my head?)
Jirka

On 05.02.2016 18:24, Jiri Denemark wrote:
On Fri, Feb 05, 2016 at 18:01:30 +0300, Nikolay Shirokovskiy wrote:
On 04.02.2016 21:11, Jiri Denemark wrote:
On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
AFAIK it is not so. We can't set(get) xbzrle options (only size now) and multithread options togather. We neet "query-migrate-cache-size" for the first and "query-migrate-parameters" for the second.
Yes, that's true. I didn't explicitly say so, but I was thinking about future additions to query-migrate-perameters. It's very likely that new parameters will be added and I think we should cover them all in one QMP call. Rather than calling several qemuMonitorGet* functions which would all run query-migrate-perameters command, but each of them would be interested only in a subset of parameters.
We did similar stuff in the past with some query-block... command which we called for every single disk again and again even though it returned all of them at once. It's cleaner to just call it once, fill in a structure describing the whole reply and do the filtering one layer up to avoid calling the same command and parsing the same reply several times.
+int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
QEMU is good enough to take partial parameters specs. In this case the other just stay untouched. But I never use this command in this mode and specify all parameters. I do it to make sure we don't get compression parameters from previous failed migration attempt. See patch number 5.
Yeah, I saw that and it was the reason I asked the question :-)
Basically instead of reverting parameters on unsuccessful migration I use hardcoded default values for parameters that are not specified on migration.
Somehow I don't like the hardcoded default values. Either we should force users to specify all parameters or we could check current values from QEMU, change some of them as requested by a user, migrate, and revert the values back to their original values. Or we can just let another migration attempt reuse the previous values (as we do with other parameters, I believe).
Jirka
Hi, Jiri. I'm thinking on how should we pass compression parameters to migration. The problem is how to deal with partially specified parameters. The initial attempt was to set unspecified parameters to some hardcoded values. This is gross but have some good qualities nethertheless. You suggested next 3 options. 1. Don't bother and just always pass all parameters. The compression parameters are totally predictable. No problems except for that we need to specify too many options on command line. 2. Don't bother and just set only that parameters that are specified. Here we get unpredictable behaviour. If you don't specify value of a parameter its value can be default one, or one that was setted on previous unsuccessfull attempt or that was set during successfull migration from different host. 3. Trying to be smarter. Say read default values at good point in time and restore them after migration is done. This way we trying to keep the parameters equal to default values all time except for the time of migration. Here we can fail for example in case of libvirt crash and restart during migration. Looks like current QEMU interface can't be used in this way reliably. Thus only the first option looks viable to me. But I hesitate to implement it as this way we get too verbose. May be we should stick with hardcodes? Another question. If we take hardcodes or 'set-them-all' approaches we don't really ever need to read this parameters from QEMU. Can we skip implementing monitor read command in this case?

ping On 17.02.2016 11:48, Nikolay Shirokovskiy wrote:
On 05.02.2016 18:24, Jiri Denemark wrote:
On Fri, Feb 05, 2016 at 18:01:30 +0300, Nikolay Shirokovskiy wrote:
On 04.02.2016 21:11, Jiri Denemark wrote:
On Thu, Jan 28, 2016 at 10:04:29 +0300, Nikolay Shirokovskiy wrote:
From: ShaoHe Feng <shaohe.feng@intel.com>
Current compression does not use all range of parameter values so let's use some of them as 'unspecified' values. These values will be used to mark parameters that were not specified on migrate command line. Thus we check that qemu does not use these values when we read parameters.
Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/qemu/qemu_monitor.c | 29 +++++++++++++ src/qemu/qemu_monitor.h | 16 +++++++ src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++ src/qemu/qemu_monitor_text.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 +++
int +qemuMonitorGetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params)
I think a more general qemuMonitor[GS]etMigrationParameters [gs]etting all parameters at once would be a bit better. After all, it all boils down to query-migrate-parameters and migrate-set-parameters and having separate functions for each group of parameters would mean we'd have to call the QMP commands several times.
AFAIK it is not so. We can't set(get) xbzrle options (only size now) and multithread options togather. We neet "query-migrate-cache-size" for the first and "query-migrate-parameters" for the second.
Yes, that's true. I didn't explicitly say so, but I was thinking about future additions to query-migrate-perameters. It's very likely that new parameters will be added and I think we should cover them all in one QMP call. Rather than calling several qemuMonitorGet* functions which would all run query-migrate-perameters command, but each of them would be interested only in a subset of parameters.
We did similar stuff in the past with some query-block... command which we called for every single disk again and again even though it returned all of them at once. It's cleaner to just call it once, fill in a structure describing the whole reply and do the filtering one layer up to avoid calling the same command and parsing the same reply several times.
+int qemuMonitorJSONSetMigrationCompressParametersMT(qemuMonitorPtr mon, + qemuMonitorMigrationMTParametersPtr params) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + cmd = qemuMonitorJSONMakeCommand("migrate-set-parameters", + "i:compress-level", params->level, + "u:compress-threads", params->threads, + "u:decompress-threads", params->dthreads, + NULL);
Is passing an "undefined" value for any of these parameters allowed (i.e., will QEMU use a default value) or do we always have to set all of them?
QEMU is good enough to take partial parameters specs. In this case the other just stay untouched. But I never use this command in this mode and specify all parameters. I do it to make sure we don't get compression parameters from previous failed migration attempt. See patch number 5.
Yeah, I saw that and it was the reason I asked the question :-)
Basically instead of reverting parameters on unsuccessful migration I use hardcoded default values for parameters that are not specified on migration.
Somehow I don't like the hardcoded default values. Either we should force users to specify all parameters or we could check current values from QEMU, change some of them as requested by a user, migrate, and revert the values back to their original values. Or we can just let another migration attempt reuse the previous values (as we do with other parameters, I believe).
Jirka
Hi, Jiri.
I'm thinking on how should we pass compression parameters to migration. The problem is how to deal with partially specified parameters. The initial attempt was to set unspecified parameters to some hardcoded values. This is gross but have some good qualities nethertheless. You suggested next 3 options.
1. Don't bother and just always pass all parameters.
The compression parameters are totally predictable. No problems except for that we need to specify too many options on command line.
2. Don't bother and just set only that parameters that are specified.
Here we get unpredictable behaviour. If you don't specify value of a parameter its value can be default one, or one that was setted on previous unsuccessfull attempt or that was set during successfull migration from different host.
3. Trying to be smarter.
Say read default values at good point in time and restore them after migration is done. This way we trying to keep the parameters equal to default values all time except for the time of migration. Here we can fail for example in case of libvirt crash and restart during migration. Looks like current QEMU interface can't be used in this way reliably.
Thus only the first option looks viable to me. But I hesitate to implement it as this way we get too verbose. May be we should stick with hardcodes?
Another question.
If we take hardcodes or 'set-them-all' approaches we don't really ever need to read this parameters from QEMU. Can we skip implementing monitor read command in this case?
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

From: Eli Qiao <liyong.qiao@intel.com> Signed-off-by: Eli Qiao <liyong.qiao@intel.com> Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- tests/qemumonitorjsontest.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 1be0bee..8f5e826 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1593,6 +1593,58 @@ testQemuMonitorJSONqemuMonitorJSONGetBlockStatsInfo(const void *data) } static int +testQemuMonitorJSONqemuMonitorJSONGetMigrationCompressParametersMT(const void *data) +{ + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt); + qemuMonitorMigrationMTParameters compression; + int ret = -1; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "query-migrate-parameters", + "{" + " \"return\": {" + " \"decompress-threads\": 2," + " \"compress-threads\": 8," + " \"compress-level\": 1" + " }" + "}") < 0) { + goto cleanup; + } + + if (qemuMonitorJSONGetMigrationCompressParametersMT( + qemuMonitorTestGetMonitor(test), &compression) < 0) + goto cleanup; + + if (compression.level != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 1", + compression.level); + goto cleanup; + } + if (compression.threads != 8) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 8", + compression.threads); + goto cleanup; + } + if (compression.dthreads != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 2", + compression.dthreads); + goto cleanup; + } + ret = 0; + + cleanup: + qemuMonitorTestFree(test); + return ret; +} + + +static int testQemuMonitorJSONqemuMonitorJSONGetMigrationCacheSize(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; @@ -2333,6 +2385,7 @@ mymain(void) DO_TEST(qemuMonitorJSONGetBlockInfo); DO_TEST(qemuMonitorJSONGetBlockStatsInfo); DO_TEST(qemuMonitorJSONGetMigrationCacheSize); + DO_TEST(qemuMonitorJSONGetMigrationCompressParametersMT); DO_TEST(qemuMonitorJSONGetMigrationStats); DO_TEST(qemuMonitorJSONGetChardevInfo); DO_TEST(qemuMonitorJSONSetBlockIoThrottle); -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
From: Eli Qiao <liyong.qiao@intel.com>
Signed-off-by: Eli Qiao <liyong.qiao@intel.com> Signed-off-by: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- tests/qemumonitorjsontest.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 1be0bee..8f5e826 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1593,6 +1593,58 @@ testQemuMonitorJSONqemuMonitorJSONGetBlockStatsInfo(const void *data) }
static int +testQemuMonitorJSONqemuMonitorJSONGetMigrationCompressParametersMT(const void *data) +{ + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt); + qemuMonitorMigrationMTParameters compression; + int ret = -1; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "query-migrate-parameters", + "{" + " \"return\": {" + " \"decompress-threads\": 2," + " \"compress-threads\": 8," + " \"compress-level\": 1" + " }" + "}") < 0) { + goto cleanup; + } + + if (qemuMonitorJSONGetMigrationCompressParametersMT( + qemuMonitorTestGetMonitor(test), &compression) < 0) + goto cleanup; + + if (compression.level != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 1", + compression.level); + goto cleanup; + } + if (compression.threads != 8) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 8", + compression.threads); + goto cleanup; + } + if (compression.dthreads != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Invalid decompress-threads: %d, expected 2", + compression.dthreads); + goto cleanup; + } + ret = 0; + + cleanup: + qemuMonitorTestFree(test); + return ret; +} + + +static int testQemuMonitorJSONqemuMonitorJSONGetMigrationCacheSize(const void *data) { virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; @@ -2333,6 +2385,7 @@ mymain(void) DO_TEST(qemuMonitorJSONGetBlockInfo); DO_TEST(qemuMonitorJSONGetBlockStatsInfo); DO_TEST(qemuMonitorJSONGetMigrationCacheSize); + DO_TEST(qemuMonitorJSONGetMigrationCompressParametersMT); DO_TEST(qemuMonitorJSONGetMigrationStats); DO_TEST(qemuMonitorJSONGetChardevInfo); DO_TEST(qemuMonitorJSONSetBlockIoThrottle); ACK

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 25 ++++++++++++++++++++++++- src/qemu/qemu_domain.c | 3 +++ src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 27 ++++++++++++++++++++++++++- src/qemu/qemu_migration.c | 36 ++++++++++++++++++++++++++++++++++-- src/qemu/qemu_migration.h | 6 ++++++ 6 files changed, 94 insertions(+), 4 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index e868515..36f6e09 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -764,9 +764,32 @@ typedef enum { * that are used to compress migration traffic. Note that this option cannot * be used together with VIR_MIGRATE_COMPRESSED flag, use only one of them. */ - # define VIR_MIGRATE_PARAM_COMPRESSION "compression" +/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL: + * + * virDomainMigrate* params field: the level of compression for multithread + * compression as VIR_TYPED_PARAM_INT. Accepted values * are in range 0-9. + * 0 is no compression, 1 is maximum speed and 9 is maximum compression. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL "compression.mt.level" + +/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS: + * + * virDomainMigrate* params field: the number of compression threads for + * multithread compression as VIR_TYPED_PARAM_UINT. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS "compression.mt.threads" + +/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS: + * + * virDomainMigrate* params field: the number of decompression threads for + * multithread compression as VIR_TYPED_PARAM_UINT. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS "compression.mt.dthreads" /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1df1b74..03ddee2 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -491,6 +491,9 @@ qemuDomainObjPrivateAlloc(void) goto error; priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX; + priv->migrationMT.level = 1; + priv->migrationMT.threads = 8; + priv->migrationMT.dthreads = 2; return priv; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 7fc4fff..48554cd 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -182,6 +182,7 @@ struct _qemuDomainObjPrivate { int nbdPort; /* Port used for migration with NBD */ unsigned short migrationPort; int preMigrationState; + qemuMonitorMigrationMTParameters migrationMT; virChrdevsPtr devs; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 129da6d..eb3fd80 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12418,7 +12418,7 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, { size_t i; - memset(compression, 0, sizeof(*compression)); + qemuMigrationCompressionInit(compression); for (i = 0; i < nparams; i++) { if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION)) @@ -12448,6 +12448,31 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, } } + if ((virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL) != NULL || + virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS) != NULL || + virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS) != NULL) && + !(compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify multithread compression " + "parameters without turning it on.")); + return -1; + } + + if (virTypedParamsGetInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, + &compression->mt.level) < 0 || + virTypedParamsGetUInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, + &compression->mt.threads) < 0 || + virTypedParamsGetUInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, + &compression->mt.dthreads) < 0) { + return -1; + } + return 0; } diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index d37e416..81ff6b3 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3307,9 +3307,12 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, unsigned int flags) { qemuMigrationCompression deflt; + qemuMigrationCompression merged; + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1; if (!compression) { - memset(&deflt, 0, sizeof(deflt)); + qemuMigrationCompressionInit(&deflt); if (flags & VIR_MIGRATE_COMPRESSED) deflt.method = QEMU_MIGRATION_COMPESS_XBZRLE; compression = &deflt; @@ -3327,7 +3330,30 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, job) < 0) return -1; - return 0; + merged.mt.level = compression->mt.level != -1 ? + compression->mt.level : + priv->migrationMT.level; + merged.mt.threads = compression->mt.threads != 0 ? + compression->mt.threads: + priv->migrationMT.threads; + merged.mt.dthreads = compression->mt.dthreads != 0 ? + compression->mt.dthreads : + priv->migrationMT.dthreads; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) + return -1; + + if ((compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD) && + qemuMonitorSetMigrationCompressParametersMT(priv->mon, &merged.mt) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (qemuDomainObjExitMonitor(driver, vm) < 0) + ret = -1; + + return ret; } static int @@ -6358,3 +6384,9 @@ qemuMigrationErrorReport(virQEMUDriverPtr driver, virSetError(err); virFreeError(err); } + +void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression) +{ + memset(compression, 0, sizeof(*compression)); + compression->mt.level = -1; +} diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 45de616..63c6a1a 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -58,6 +58,9 @@ typedef qemuMigrationCompression *qemuMigrationCompressionPtr; VIR_TYPED_PARAM_MULTIPLE, \ VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | \ VIR_TYPED_PARAM_MULTIPLE, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_UINT, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_UINT, \ NULL @@ -84,8 +87,11 @@ typedef enum { struct _qemuMigrationCompression { qemuMigrationCompressMethod method; + qemuMonitorMigrationMTParameters mt; }; +void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression); + int qemuMigrationJobStart(virQEMUDriverPtr driver, virDomainObjPtr vm, qemuDomainAsyncJob job) -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com>
Again, I miss some description in commit message. Otherwise ACK.
--- include/libvirt/libvirt-domain.h | 25 ++++++++++++++++++++++++- src/qemu/qemu_domain.c | 3 +++ src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 27 ++++++++++++++++++++++++++- src/qemu/qemu_migration.c | 36 ++++++++++++++++++++++++++++++++++-- src/qemu/qemu_migration.h | 6 ++++++ 6 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index e868515..36f6e09 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -764,9 +764,32 @@ typedef enum { * that are used to compress migration traffic. Note that this option cannot * be used together with VIR_MIGRATE_COMPRESSED flag, use only one of them. */ - # define VIR_MIGRATE_PARAM_COMPRESSION "compression"
+/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL: + * + * virDomainMigrate* params field: the level of compression for multithread + * compression as VIR_TYPED_PARAM_INT. Accepted values * are in range 0-9. + * 0 is no compression, 1 is maximum speed and 9 is maximum compression. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL "compression.mt.level" + +/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS: + * + * virDomainMigrate* params field: the number of compression threads for + * multithread compression as VIR_TYPED_PARAM_UINT. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS "compression.mt.threads" + +/** + * VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS: + * + * virDomainMigrate* params field: the number of decompression threads for + * multithread compression as VIR_TYPED_PARAM_UINT. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS "compression.mt.dthreads"
/* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1df1b74..03ddee2 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -491,6 +491,9 @@ qemuDomainObjPrivateAlloc(void) goto error;
priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX; + priv->migrationMT.level = 1; + priv->migrationMT.threads = 8; + priv->migrationMT.dthreads = 2;
Why not to define those defaults in qemu_domain.h and explain why such numbers are chosen?
return priv;
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 7fc4fff..48554cd 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -182,6 +182,7 @@ struct _qemuDomainObjPrivate { int nbdPort; /* Port used for migration with NBD */ unsigned short migrationPort; int preMigrationState; + qemuMonitorMigrationMTParameters migrationMT;
virChrdevsPtr devs;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 129da6d..eb3fd80 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12418,7 +12418,7 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, { size_t i;
- memset(compression, 0, sizeof(*compression)); + qemuMigrationCompressionInit(compression);
for (i = 0; i < nparams; i++) { if (STRNEQ(params[i].field, VIR_MIGRATE_PARAM_COMPRESSION)) @@ -12448,6 +12448,31 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, } }
+ if ((virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL) != NULL || + virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS) != NULL || + virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS) != NULL) && + !(compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify multithread compression " + "parameters without turning it on.")); + return -1; + } + + if (virTypedParamsGetInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, + &compression->mt.level) < 0 || + virTypedParamsGetUInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, + &compression->mt.threads) < 0 || + virTypedParamsGetUInt(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, + &compression->mt.dthreads) < 0) { + return -1; + } + return 0; }
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index d37e416..81ff6b3 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3307,9 +3307,12 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, unsigned int flags) { qemuMigrationCompression deflt; + qemuMigrationCompression merged; + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret = -1;
if (!compression) { - memset(&deflt, 0, sizeof(deflt)); + qemuMigrationCompressionInit(&deflt); if (flags & VIR_MIGRATE_COMPRESSED) deflt.method = QEMU_MIGRATION_COMPESS_XBZRLE; compression = &deflt; @@ -3327,7 +3330,30 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, job) < 0) return -1;
- return 0; + merged.mt.level = compression->mt.level != -1 ? + compression->mt.level : + priv->migrationMT.level; + merged.mt.threads = compression->mt.threads != 0 ? + compression->mt.threads: + priv->migrationMT.threads; + merged.mt.dthreads = compression->mt.dthreads != 0 ? + compression->mt.dthreads : + priv->migrationMT.dthreads; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) + return -1; + + if ((compression->method & QEMU_MIGRATION_COMPESS_MULTITHREAD) && + qemuMonitorSetMigrationCompressParametersMT(priv->mon, &merged.mt) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (qemuDomainObjExitMonitor(driver, vm) < 0) + ret = -1; + + return ret; }
static int @@ -6358,3 +6384,9 @@ qemuMigrationErrorReport(virQEMUDriverPtr driver, virSetError(err); virFreeError(err); } + +void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression) +{ + memset(compression, 0, sizeof(*compression)); + compression->mt.level = -1; +} diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 45de616..63c6a1a 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -58,6 +58,9 @@ typedef qemuMigrationCompression *qemuMigrationCompressionPtr; VIR_TYPED_PARAM_MULTIPLE, \ VIR_MIGRATE_PARAM_COMPRESSION, VIR_TYPED_PARAM_STRING | \ VIR_TYPED_PARAM_MULTIPLE, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_UINT, \ + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_UINT, \ NULL
@@ -84,8 +87,11 @@ typedef enum {
struct _qemuMigrationCompression { qemuMigrationCompressMethod method; + qemuMonitorMigrationMTParameters mt; };
+void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression); + int qemuMigrationJobStart(virQEMUDriverPtr driver, virDomainObjPtr vm, qemuDomainAsyncJob job)

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 8 ++++++++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 16 ++++++++++++++++ src/qemu/qemu_migration.c | 8 ++++++++ src/qemu/qemu_migration.h | 2 ++ 6 files changed, 36 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 36f6e09..c7388c0 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -791,6 +791,14 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS "compression.mt.dthreads" +/** + * VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE: + * + * virDomainMigrate* params field: the size of page cache for xbzrle + * compression as VIR_TYPED_PARAM_ULLONG. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE "compression.xbzrle.cache" + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 03ddee2..2a32c94 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -494,6 +494,7 @@ qemuDomainObjPrivateAlloc(void) priv->migrationMT.level = 1; priv->migrationMT.threads = 8; priv->migrationMT.dthreads = 2; + priv->xbzrleCache = 64 * (1 << 20); return priv; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 48554cd..98165a2 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -183,6 +183,7 @@ struct _qemuDomainObjPrivate { unsigned short migrationPort; int preMigrationState; qemuMonitorMigrationMTParameters migrationMT; + unsigned long long xbzrleCache; virChrdevsPtr devs; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index eb3fd80..6938e13 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12473,6 +12473,20 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, return -1; } + if (virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE) != NULL && + !(compression->method & QEMU_MIGRATION_COMPESS_XBZRLE)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify xbzrle compression " + "parameters without turning it on.")); + return -1; + } + + if (virTypedParamsGetULLong(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, + &compression->xbzrle_cache) < 0) + return -1; + return 0; } @@ -13491,6 +13505,8 @@ qemuDomainMigrateSetCompressionCache(virDomainPtr dom, } else if (ret > 0) { VIR_DEBUG("Setting compression cache to %llu B", cacheSize); ret = qemuMonitorSetMigrationCacheSize(priv->mon, cacheSize); + if (ret == 0) + priv->xbzrleCache = cacheSize; } if (qemuDomainObjExitMonitor(driver, vm) < 0) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 81ff6b3..efba84d 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3340,6 +3340,10 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, compression->mt.dthreads : priv->migrationMT.dthreads; + merged.xbzrle_cache = compression->xbzrle_cache != 0 ? + compression->xbzrle_cache : + priv->xbzrleCache; + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) return -1; @@ -3347,6 +3351,10 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, qemuMonitorSetMigrationCompressParametersMT(priv->mon, &merged.mt) < 0) goto cleanup; + if ((compression->method & QEMU_MIGRATION_COMPESS_XBZRLE) && + qemuMonitorSetMigrationCacheSize(priv->mon, merged.xbzrle_cache) < 0) + goto cleanup; + ret = 0; cleanup: diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 63c6a1a..70a37db 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -61,6 +61,7 @@ typedef qemuMigrationCompression *qemuMigrationCompressionPtr; VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT, \ VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_UINT, \ VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_UINT, \ + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, VIR_TYPED_PARAM_ULLONG, \ NULL @@ -88,6 +89,7 @@ typedef enum { struct _qemuMigrationCompression { qemuMigrationCompressMethod method; qemuMonitorMigrationMTParameters mt; + unsigned long long xbzrle_cache; }; void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression); -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 8 ++++++++ src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 16 ++++++++++++++++ src/qemu/qemu_migration.c | 8 ++++++++ src/qemu/qemu_migration.h | 2 ++ 6 files changed, 36 insertions(+)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 36f6e09..c7388c0 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -791,6 +791,14 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS "compression.mt.dthreads"
+/** + * VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE: + * + * virDomainMigrate* params field: the size of page cache for xbzrle + * compression as VIR_TYPED_PARAM_ULLONG. + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE "compression.xbzrle.cache" + /* Domain migration. */ virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn, unsigned long flags, const char *dname, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 03ddee2..2a32c94 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -494,6 +494,7 @@ qemuDomainObjPrivateAlloc(void) priv->migrationMT.level = 1; priv->migrationMT.threads = 8; priv->migrationMT.dthreads = 2; + priv->xbzrleCache = 64 * (1 << 20);
return priv;
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 48554cd..98165a2 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -183,6 +183,7 @@ struct _qemuDomainObjPrivate { unsigned short migrationPort; int preMigrationState; qemuMonitorMigrationMTParameters migrationMT; + unsigned long long xbzrleCache;
virChrdevsPtr devs;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index eb3fd80..6938e13 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12473,6 +12473,20 @@ qemuGetCompression(virTypedParameterPtr params, int nparams, return -1; }
+ if (virTypedParamsGet(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE) != NULL && + !(compression->method & QEMU_MIGRATION_COMPESS_XBZRLE)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("You cannot specify xbzrle compression " + "parameters without turning it on.")); + return -1; + } + + if (virTypedParamsGetULLong(params, nparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, + &compression->xbzrle_cache) < 0) + return -1; + return 0; }
@@ -13491,6 +13505,8 @@ qemuDomainMigrateSetCompressionCache(virDomainPtr dom, } else if (ret > 0) { VIR_DEBUG("Setting compression cache to %llu B", cacheSize); ret = qemuMonitorSetMigrationCacheSize(priv->mon, cacheSize); + if (ret == 0) + priv->xbzrleCache = cacheSize; }
if (qemuDomainObjExitMonitor(driver, vm) < 0) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 81ff6b3..efba84d 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3340,6 +3340,10 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, compression->mt.dthreads : priv->migrationMT.dthreads;
+ merged.xbzrle_cache = compression->xbzrle_cache != 0 ? + compression->xbzrle_cache : + priv->xbzrleCache; + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) return -1;
@@ -3347,6 +3351,10 @@ qemuMigrationSetCompression(virQEMUDriverPtr driver, qemuMonitorSetMigrationCompressParametersMT(priv->mon, &merged.mt) < 0) goto cleanup;
+ if ((compression->method & QEMU_MIGRATION_COMPESS_XBZRLE) && + qemuMonitorSetMigrationCacheSize(priv->mon, merged.xbzrle_cache) < 0) + goto cleanup; + ret = 0;
cleanup: diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index 63c6a1a..70a37db 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -61,6 +61,7 @@ typedef qemuMigrationCompression *qemuMigrationCompressionPtr; VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, VIR_TYPED_PARAM_INT, \ VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, VIR_TYPED_PARAM_UINT, \ VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, VIR_TYPED_PARAM_UINT, \ + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, VIR_TYPED_PARAM_ULLONG, \ NULL
@@ -88,6 +89,7 @@ typedef enum { struct _qemuMigrationCompression { qemuMigrationCompressMethod method; qemuMonitorMigrationMTParameters mt; + unsigned long long xbzrle_cache; };
void qemuMigrationCompressionInit(qemuMigrationCompressionPtr compression); ACK

From: ShaoHe Feng <shaohe.feng@intel.com> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- tools/virsh-domain.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 25 ++++++++++++---- 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index c2146d2..af81372 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -9644,6 +9644,31 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_STRING, .help = N_("comma separated list of disks to be migrated") }, + {.name = "compression-method", + .type = VSH_OT_STRING, + .help = N_("comma separated list of compression method to be used") + }, + {.name = "compression-mt-level", + .type = VSH_OT_INT, + .help = N_("compress level for multithread compression. " + "Values are in range 0-9, 9 means maximum compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-mt-threads", + .type = VSH_OT_INT, + .help = N_("number of compession threads from multithread compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-mt-dthreads", + .type = VSH_OT_INT, + .help = N_("number of decompession threads from multithread compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-xbzrle-cache", + .type = VSH_OT_INT, + .help = N_("page cache size for xbzrle compression. " + "'xbzrle' compression method must be selected with this option.") + }, {.name = NULL} }; @@ -9662,6 +9687,10 @@ doMigrate(void *opaque) virTypedParameterPtr params = NULL; int nparams = 0; int maxparams = 0; + int intOpt = 0; + unsigned int uintOpt = 0; + unsigned long long ullOpt = 0; + int rv; virConnectPtr dconn = data->dconn; sigemptyset(&sigmask); @@ -9722,6 +9751,61 @@ doMigrate(void *opaque) VIR_FREE(val); } + if (vshCommandOptStringReq(ctl, cmd, "compression-method", &opt) < 0) + goto out; + if (opt) { + char **val = NULL; + + val = virStringSplit(opt, ",", 0); + + if (virTypedParamsAddStringList(¶ms, + &nparams, + &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION, + (const char **)val) < 0) { + VIR_FREE(val); + goto save_error; + } + + VIR_FREE(val); + } + + if ((rv = vshCommandOptInt(ctl, cmd, "compression-mt-level", &intOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, + intOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptUInt(ctl, cmd, "compression-mt-threads", &uintOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, + uintOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptUInt(ctl, cmd, "compression-mt-dthreads", &uintOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, + uintOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptULongLong(ctl, cmd, "compression-xbzrle-cache", &ullOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, + ullOpt) < 0) + goto save_error; + } + if (vshCommandOptStringReq(ctl, cmd, "xml", &opt) < 0) goto out; if (opt) { diff --git a/tools/virsh.pod b/tools/virsh.pod index e830c59..9fb01ac 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1532,7 +1532,9 @@ to the I<uri> namespace is displayed instead of being modified. [I<--compressed>] [I<--abort-on-error>] [I<--auto-converge>] I<domain> I<desturi> [I<migrateuri>] [I<graphicsuri>] [I<listen-address>] [I<dname>] [I<--timeout> B<seconds>] [I<--xml> B<file>] -[I<--migrate-disks> B<disk-list>] +[I<--migrate-disks> B<disk-list>] [I<--compression-method> B<method-list>] +[I<--compression-mt-level>] [I<--compression-mt-threads>] [I<--compression-mt-dthreads>] +[I<--compression-xbzrle-cache>] Migrate domain to another host. Add I<--live> for live migration; <--p2p> for peer-2-peer migration; I<--direct> for direct migration; or I<--tunnelled> @@ -1555,10 +1557,14 @@ enforces that no incompatible configuration changes will be made to the domain while the migration is underway; this flag is implicitly enabled when supported by the hypervisor, but can be explicitly used to reject the migration if the hypervisor lacks change protection support. I<--verbose> displays the progress -of migration. I<--compressed> activates compression of memory pages that have -to be transferred repeatedly during live migration. I<--abort-on-error> cancels -the migration if a soft error (for example I/O error) happens during the -migration. I<--auto-converge> forces convergence during live migration. +of migration. I<--compressed> activates default compression method +during migration. I<--abort-on-error> cancels the migration if a soft error +(for example I/O error) happens during the migration. I<--auto-converge> +forces convergence during live migration. I<--compression-methods> +configures compression methods to use during migration in the comma separated +B<method-list> argument. Compression methods are driver specific. +Compression methods can be tuned further using various [--<compression-*>] +options. B<Note>: Individual hypervisors usually do not support all possible types of migration. For example, QEMU does not support direct migration. @@ -1594,6 +1600,15 @@ managed migration. B<Note>: The I<desturi> parameter for normal migration and peer2peer migration has different semantics: +QEMU supports "multithread" and "xbzrle" methods which can be used in any +combination. I<--compression-mt-level> sets compression level for multithread +method. Values are in range from 0 to 9, where 1 is maximum speed and 9 is maximum +compression. I<--compression-mt-threads> and I<--compression-mt-dthreads> set +the number of compress threads on source and the number of decompress threads +on target respectively. I<--compression-xbzrle-cache> sets size of page cache in +bytes for xbzrle method. I<--compressed> turns on "xbzrle" compression method with +current compression parameters. + =over 4 =item * normal migration: the I<desturi> is an address of the target host as -- 1.8.3.1

28.01.2016 10:04, Nikolay Shirokovskiy пишет:
From: ShaoHe Feng <shaohe.feng@intel.com>
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- tools/virsh-domain.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 25 ++++++++++++---- 2 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index c2146d2..af81372 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -9644,6 +9644,31 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_STRING, .help = N_("comma separated list of disks to be migrated") }, + {.name = "compression-method", + .type = VSH_OT_STRING, + .help = N_("comma separated list of compression method to be used") + }, + {.name = "compression-mt-level", + .type = VSH_OT_INT, + .help = N_("compress level for multithread compression. " + "Values are in range 0-9, 9 means maximum compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-mt-threads", + .type = VSH_OT_INT, + .help = N_("number of compession threads from multithread compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-mt-dthreads", + .type = VSH_OT_INT, + .help = N_("number of decompession threads from multithread compression. " + "'multithread' compression method must be selected with this option.") + }, + {.name = "compression-xbzrle-cache", + .type = VSH_OT_INT, + .help = N_("page cache size for xbzrle compression. " + "'xbzrle' compression method must be selected with this option.") + }, {.name = NULL} };
@@ -9662,6 +9687,10 @@ doMigrate(void *opaque) virTypedParameterPtr params = NULL; int nparams = 0; int maxparams = 0; + int intOpt = 0; + unsigned int uintOpt = 0; + unsigned long long ullOpt = 0; + int rv; virConnectPtr dconn = data->dconn;
sigemptyset(&sigmask); @@ -9722,6 +9751,61 @@ doMigrate(void *opaque) VIR_FREE(val); }
+ if (vshCommandOptStringReq(ctl, cmd, "compression-method", &opt) < 0) + goto out; + if (opt) { + char **val = NULL; + + val = virStringSplit(opt, ",", 0); + + if (virTypedParamsAddStringList(¶ms, + &nparams, + &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION, + (const char **)val) < 0) { + VIR_FREE(val); + goto save_error; + } + + VIR_FREE(val); + } + + if ((rv = vshCommandOptInt(ctl, cmd, "compression-mt-level", &intOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL, + intOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptUInt(ctl, cmd, "compression-mt-threads", &uintOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS, + uintOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptUInt(ctl, cmd, "compression-mt-dthreads", &uintOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS, + uintOpt) < 0) + goto save_error; + } + + if ((rv = vshCommandOptULongLong(ctl, cmd, "compression-xbzrle-cache", &ullOpt)) < 0) { + goto save_error; + } else if (rv > 0) { + if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE, + ullOpt) < 0) + goto save_error; + } + if (vshCommandOptStringReq(ctl, cmd, "xml", &opt) < 0) goto out; if (opt) { diff --git a/tools/virsh.pod b/tools/virsh.pod index e830c59..9fb01ac 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1532,7 +1532,9 @@ to the I<uri> namespace is displayed instead of being modified. [I<--compressed>] [I<--abort-on-error>] [I<--auto-converge>] I<domain> I<desturi> [I<migrateuri>] [I<graphicsuri>] [I<listen-address>] [I<dname>] [I<--timeout> B<seconds>] [I<--xml> B<file>] -[I<--migrate-disks> B<disk-list>] +[I<--migrate-disks> B<disk-list>] [I<--compression-method> B<method-list>] +[I<--compression-mt-level>] [I<--compression-mt-threads>] [I<--compression-mt-dthreads>] +[I<--compression-xbzrle-cache>]
Migrate domain to another host. Add I<--live> for live migration; <--p2p> for peer-2-peer migration; I<--direct> for direct migration; or I<--tunnelled> @@ -1555,10 +1557,14 @@ enforces that no incompatible configuration changes will be made to the domain while the migration is underway; this flag is implicitly enabled when supported by the hypervisor, but can be explicitly used to reject the migration if the hypervisor lacks change protection support. I<--verbose> displays the progress -of migration. I<--compressed> activates compression of memory pages that have -to be transferred repeatedly during live migration. I<--abort-on-error> cancels -the migration if a soft error (for example I/O error) happens during the -migration. I<--auto-converge> forces convergence during live migration. +of migration. I<--compressed> activates default compression method +during migration. I<--abort-on-error> cancels the migration if a soft error +(for example I/O error) happens during the migration. I<--auto-converge> +forces convergence during live migration. I<--compression-methods> +configures compression methods to use during migration in the comma separated +B<method-list> argument. Compression methods are driver specific. +Compression methods can be tuned further using various [--<compression-*>] +options.
B<Note>: Individual hypervisors usually do not support all possible types of migration. For example, QEMU does not support direct migration. @@ -1594,6 +1600,15 @@ managed migration. B<Note>: The I<desturi> parameter for normal migration and peer2peer migration has different semantics:
+QEMU supports "multithread" and "xbzrle" methods which can be used in any +combination. I<--compression-mt-level> sets compression level for multithread +method. Values are in range from 0 to 9, where 1 is maximum speed and 9 is maximum +compression. I<--compression-mt-threads> and I<--compression-mt-dthreads> set +the number of compress threads on source and the number of decompress threads +on target respectively. I<--compression-xbzrle-cache> sets size of page cache in +bytes for xbzrle method. I<--compressed> turns on "xbzrle" compression method with +current compression parameters. + =over 4
=item * normal migration: the I<desturi> is an address of the target host as ACK
participants (3)
-
Jiri Denemark
-
Maxim Nestratov
-
Nikolay Shirokovskiy