[PATCH 0/3] qemu: migration: implement zstd compression

QEMU now supports multifd-compression=zstd for migration with enabled multifd. Bring the support to libvirt as well. Claudio Fontana (1): qemu: migration: expose qemuMigrationParamsSetString Oleg Vasilev (2): qemu: migration: implement zstd compression tests: qemumigparams: test for zstd compression include/libvirt/libvirt-domain.h | 10 ++++ src/qemu/qemu_migration.h | 1 + src/qemu/qemu_migration_params.c | 79 +++++++++++++++++--------- src/qemu/qemu_migration_params.h | 7 +++ tests/qemumigparamsdata/zstd.json | 4 ++ tests/qemumigparamsdata/zstd.reply | 7 +++ tests/qemumigparamsdata/zstd.xml | 6 ++ tests/qemumigparamstest.c | 90 +++++++++++++++++++++++++++--- tools/virsh-completer-domain.c | 2 +- tools/virsh-domain.c | 14 +++++ 10 files changed, 187 insertions(+), 33 deletions(-) create mode 100644 tests/qemumigparamsdata/zstd.json create mode 100644 tests/qemumigparamsdata/zstd.reply create mode 100644 tests/qemumigparamsdata/zstd.xml -- 2.40.0

From: Claudio Fontana <cfontana@suse.de> change from static to external linkage, and move the function close to the other similar ones, near qemuMigrationParamsSetULL. Signed-off-by: Claudio Fontana <cfontana@suse.de> Signed-off-by: Oleg Vasilev <oleg.vasilev@virtuozzo.com> --- src/qemu/qemu_migration_params.c | 47 +++++++++++++++----------------- src/qemu/qemu_migration_params.h | 5 ++++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index 21997d4156..a40f791be6 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -955,31 +955,6 @@ qemuMigrationParamsApply(virDomainObj *vm, } -/** - * qemuMigrationParamsSetString: - * @migrParams: migration parameter object - * @param: parameter to set - * @value: new value - * - * Enables and sets the migration parameter @param in @migrParams. Returns 0 on - * success and -1 on error. Libvirt error is reported. - */ -static int -qemuMigrationParamsSetString(qemuMigrationParams *migParams, - qemuMigrationParam param, - const char *value) -{ - if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0) - return -1; - - migParams->params[param].value.s = g_strdup(value); - - migParams->params[param].set = true; - - return 0; -} - - /* qemuMigrationParamsEnableTLS * @driver: pointer to qemu driver * @vm: domain object @@ -1176,6 +1151,28 @@ qemuMigrationParamsSetULL(qemuMigrationParams *migParams, return 0; } +/** + * qemuMigrationParamsSetString: + * @migrParams: migration parameter object + * @param: parameter to set + * @value: new value + * + * Enables and sets the migration parameter @param in @migrParams. Returns 0 on + * success and -1 on error. Libvirt error is reported. + */ +int +qemuMigrationParamsSetString(qemuMigrationParams *migParams, + qemuMigrationParam param, + const char *value) +{ + if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_STRING) < 0) + return -1; + + migParams->params[param].value.s = g_strdup(value); + migParams->params[param].set = true; + return 0; +} + /** * Returns -1 on error, diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h index e7c65f6a21..458a7a4dfa 100644 --- a/src/qemu/qemu_migration_params.h +++ b/src/qemu/qemu_migration_params.h @@ -126,6 +126,11 @@ qemuMigrationParamsSetULL(qemuMigrationParams *migParams, qemuMigrationParam param, unsigned long long value); +int +qemuMigrationParamsSetString(qemuMigrationParams *migParams, + qemuMigrationParam param, + const char *value); + int qemuMigrationParamsGetULL(qemuMigrationParams *migParams, qemuMigrationParam param, -- 2.40.0

QEMU now supports multifd-compression=zstd for migration with enabled multifd. Bring the support to libvirt as well. Signed-off-by: Oleg Vasilev <oleg.vasilev@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 10 ++++++++++ src/qemu/qemu_migration.h | 1 + src/qemu/qemu_migration_params.c | 32 ++++++++++++++++++++++++++++++++ src/qemu/qemu_migration_params.h | 2 ++ tools/virsh-completer-domain.c | 2 +- tools/virsh-domain.c | 14 ++++++++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 3ebb2c6642..f267ca357b 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1319,6 +1319,16 @@ typedef enum { */ # define VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE "compression.xbzrle.cache" +/** + * VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL: + * + * virDomainMigrate* params field: the level of compression for zstd + * compression as VIR_TYPED_PARAM_INT. Accepted values are in range 1-22. + * + * Since: 9.0.0 + */ +# define VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL "compression.zstd.level" + /** * VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL: * diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index d21b6f67e8..09d21fd878 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -88,6 +88,7 @@ VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS, VIR_TYPED_PARAM_INT, \ VIR_MIGRATE_PARAM_TLS_DESTINATION, VIR_TYPED_PARAM_STRING, \ VIR_MIGRATE_PARAM_DISKS_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, VIR_TYPED_PARAM_INT, \ NULL diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index a40f791be6..2533353ccf 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -71,6 +71,7 @@ struct _qemuMigrationParams { typedef enum { QEMU_MIGRATION_COMPRESS_XBZRLE = 0, QEMU_MIGRATION_COMPRESS_MT, + QEMU_MIGRATION_COMPRESS_ZSTD, QEMU_MIGRATION_COMPRESS_LAST } qemuMigrationCompressMethod; @@ -79,6 +80,7 @@ VIR_ENUM_IMPL(qemuMigrationCompressMethod, QEMU_MIGRATION_COMPRESS_LAST, "xbzrle", "mt", + "zstd", ); VIR_ENUM_IMPL(qemuMigrationCapability, @@ -114,6 +116,8 @@ VIR_ENUM_IMPL(qemuMigrationParam, "xbzrle-cache-size", "max-postcopy-bandwidth", "multifd-channels", + "multifd-compression", + "multifd-zstd-level", ); typedef struct _qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOnItem; @@ -216,6 +220,10 @@ static const qemuMigrationParamsTPMapItem qemuMigrationParamsTPMap[] = { .param = QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE, .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION}, + {.typedParam = VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, + .param = QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL, + .party = QEMU_MIGRATION_SOURCE | QEMU_MIGRATION_DESTINATION}, + {.typedParam = VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY, .unit = 1024 * 1024, /* MiB/s */ .param = QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH, @@ -271,6 +279,12 @@ static const qemuMigrationParamInfoItem qemuMigrationParamInfo[] = { [QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS] = { .type = QEMU_MIGRATION_PARAM_TYPE_INT, }, + [QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION] = { + .type = QEMU_MIGRATION_PARAM_TYPE_STRING, + }, + [QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL] = { + .type = QEMU_MIGRATION_PARAM_TYPE_INT, + }, }; G_STATIC_ASSERT(G_N_ELEMENTS(qemuMigrationParamInfo) == QEMU_MIGRATION_PARAM_LAST); @@ -546,6 +560,10 @@ qemuMigrationParamsSetCompression(virTypedParameterPtr params, cap = QEMU_MIGRATION_CAP_COMPRESS; break; + case QEMU_MIGRATION_COMPRESS_ZSTD: + qemuMigrationParamsSetString(migParams, + QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION, + "zstd"); case QEMU_MIGRATION_COMPRESS_LAST: default: continue; @@ -569,6 +587,13 @@ qemuMigrationParamsSetCompression(virTypedParameterPtr params, return -1; } + if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL].set && + !(migParams->compMethods & (1ULL << QEMU_MIGRATION_COMPRESS_ZSTD))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Turn zstd compression on to tune it")); + return -1; + } + if (!migParams->compMethods && (flags & VIR_MIGRATE_COMPRESSED)) { migParams->compMethods = 1ULL << QEMU_MIGRATION_COMPRESS_XBZRLE; ignore_value(virBitmapSetBit(migParams->caps, @@ -669,6 +694,13 @@ qemuMigrationParamsFromFlags(virTypedParameterPtr params, return NULL; } + if (migParams->params[QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL].set && + !(flags & VIR_MIGRATE_PARALLEL)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Turn parallel migration on to tune zstd level")); + return NULL; + } + if (qemuMigrationParamsSetCompression(params, nparams, flags, migParams) < 0) return NULL; diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h index 458a7a4dfa..383b25ce63 100644 --- a/src/qemu/qemu_migration_params.h +++ b/src/qemu/qemu_migration_params.h @@ -59,6 +59,8 @@ typedef enum { QEMU_MIGRATION_PARAM_XBZRLE_CACHE_SIZE, QEMU_MIGRATION_PARAM_MAX_POSTCOPY_BANDWIDTH, QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS, + QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION, + QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL, QEMU_MIGRATION_PARAM_LAST } qemuMigrationParam; diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c index b54baf3577..66748b7b65 100644 --- a/tools/virsh-completer-domain.c +++ b/tools/virsh-completer-domain.c @@ -1012,7 +1012,7 @@ virshDomainMigrateCompMethodsCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int flags) { - const char *methods[] = {"xbzrle", "mt", NULL}; + const char *methods[] = {"xbzrle", "mt", "zstd", NULL}; const char *method = NULL; virCheckFlags(0, NULL); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 6850843a25..0813bd5de0 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -11056,6 +11056,10 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_INT, .help = N_("page cache size for xbzrle compression") }, + {.name = "comp-zstd-level", + .type = VSH_OT_INT, + .help = N_("zstd level for zstd compression") + }, {.name = "auto-converge-initial", .type = VSH_OT_INT, .help = N_("initial CPU throttling rate for auto-convergence") @@ -11238,6 +11242,16 @@ doMigrate(void *opaque) goto save_error; } + if ((rv = vshCommandOptInt(ctl, cmd, "comp-zstd-level", &intOpt)) < 0) { + goto out; + } else if (rv > 0) { + if (virTypedParamsAddInt(¶ms, &nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, + intOpt) < 0) + goto save_error; + } + + if (vshCommandOptStringReq(ctl, cmd, "xml", &opt) < 0) goto out; if (opt) { -- 2.40.0

Here we add one more way to test migration parameters, namely: from vir params. This allows to test the logic of (libvirt) compression->(qemu) multifd-compression Signed-off-by: Oleg Vasilev <oleg.vasilev@virtuozzo.com> --- tests/qemumigparamsdata/zstd.json | 4 ++ tests/qemumigparamsdata/zstd.reply | 7 +++ tests/qemumigparamsdata/zstd.xml | 6 ++ tests/qemumigparamstest.c | 90 +++++++++++++++++++++++++++--- 4 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 tests/qemumigparamsdata/zstd.json create mode 100644 tests/qemumigparamsdata/zstd.reply create mode 100644 tests/qemumigparamsdata/zstd.xml diff --git a/tests/qemumigparamsdata/zstd.json b/tests/qemumigparamsdata/zstd.json new file mode 100644 index 0000000000..61e8b7c2f1 --- /dev/null +++ b/tests/qemumigparamsdata/zstd.json @@ -0,0 +1,4 @@ +{ + "multifd-compression": "zstd", + "multifd-zstd-level": 3 +} diff --git a/tests/qemumigparamsdata/zstd.reply b/tests/qemumigparamsdata/zstd.reply new file mode 100644 index 0000000000..8818bc0b3e --- /dev/null +++ b/tests/qemumigparamsdata/zstd.reply @@ -0,0 +1,7 @@ +{ + "id": "libvirt-1", + "return": { + "multifd-compression": "zstd", + "multifd-zstd-level": 3 + } +} diff --git a/tests/qemumigparamsdata/zstd.xml b/tests/qemumigparamsdata/zstd.xml new file mode 100644 index 0000000000..38f11bda90 --- /dev/null +++ b/tests/qemumigparamsdata/zstd.xml @@ -0,0 +1,6 @@ +<test> + <migParams> + <param name='multifd-compression' value='zstd'/> + <param name='multifd-zstd-level' value='3'/> + </migParams> +</test> diff --git a/tests/qemumigparamstest.c b/tests/qemumigparamstest.c index 5d45a9dd58..b0e1ad89a0 100644 --- a/tests/qemumigparamstest.c +++ b/tests/qemumigparamstest.c @@ -33,11 +33,20 @@ #define VIR_FROM_THIS VIR_FROM_NONE +typedef struct _qemuMigParamsSourceData qemuMigParamsSourceData; +struct _qemuMigParamsSourceData { + virTypedParameterPtr params; + int nparams; + unsigned long flags; + qemuMigrationParty party; +}; + typedef struct _qemuMigParamsData qemuMigParamsData; struct _qemuMigParamsData { virDomainXMLOption *xmlopt; const char *name; GHashTable *qmpschema; + qemuMigParamsSourceData *src; }; @@ -177,6 +186,50 @@ qemuMigParamsTestJSON(const void *opaque) return 0; } +static int +qemuMigParamsTestParams(const void *opaque) +{ + const qemuMigParamsData *data = opaque; + g_autofree char *jsonFile = NULL; + g_autoptr(virJSONValue) paramsOut = NULL; + g_autoptr(qemuMigrationParams) migParams = NULL; + g_autofree char *actualJSON = NULL; + g_auto(virBuffer) debug = VIR_BUFFER_INITIALIZER; + + jsonFile = g_strdup_printf("%s/qemumigparamsdata/%s.json", + abs_srcdir, data->name); + + migParams = qemuMigrationParamsFromFlags(data->src->params, + data->src->nparams, + data->src->flags, + data->src->party); + if (!migParams) { + VIR_TEST_VERBOSE("can't construct params"); + return -1; + } + + if (!(paramsOut = qemuMigrationParamsToJSON(migParams, false)) || + !(actualJSON = virJSONValueToString(paramsOut, true))) + return -1; + + if (testQEMUSchemaValidateCommand("migrate-set-parameters", + paramsOut, + data->qmpschema, + false, + false, + false, + &debug) < 0) { + VIR_TEST_VERBOSE("failed to validate migration params '%s' against QMP schema: %s", + actualJSON, virBufferCurrentContent(&debug)); + return -1; + } + + if (virTestCompareToFile(actualJSON, jsonFile) < 0) + return -1; + + return 0; +} + static int mymain(void) @@ -184,6 +237,13 @@ mymain(void) g_autoptr(GHashTable) qmpschema = NULL; virQEMUDriver driver; int ret = 0; + qemuMigParamsSourceData src = { + .params = NULL, + .nparams = 0, + .flags = 0, + .party = QEMU_MIGRATION_SOURCE, + }; + int maxparams = 0; if (qemuTestDriverInit(&driver) < 0) return EXIT_FAILURE; @@ -195,10 +255,10 @@ mymain(void) return EXIT_FAILURE; } -#define DO_TEST(name) \ +#define DO_TEST(name, src) \ do { \ qemuMigParamsData data = { \ - driver.xmlopt, name, qmpschema \ + driver.xmlopt, name, qmpschema, src \ }; \ if (virTestRun(name " (xml)", qemuMigParamsTestXML, &data) < 0) \ ret = -1; \ @@ -206,13 +266,29 @@ mymain(void) ret = -1; \ if (virTestRun(name " (xml2xml)", qemuMigParamsTestXML2XML, &data) < 0) \ ret = -1; \ + if ((src != NULL) && virTestRun(name " (src)", qemuMigParamsTestParams, &data) < 0) \ + ret = -1; \ } while (0) - DO_TEST("empty"); - DO_TEST("basic"); - DO_TEST("tls"); - DO_TEST("tls-enabled"); - DO_TEST("tls-hostname"); + DO_TEST("empty", NULL); + DO_TEST("basic", NULL); + DO_TEST("tls", NULL); + DO_TEST("tls-enabled", NULL); + DO_TEST("tls-hostname", NULL); + + src.flags |= VIR_MIGRATE_PARALLEL; + + if (virTypedParamsAddString(&src.params, &src.nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION, "zstd") < 0 || + virTypedParamsAddInt(&src.params, &src.nparams, &maxparams, + VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL, 3) < 0) { + ret = -1; + goto cleanup; + } + DO_TEST("zstd", &src); + + cleanup: + virTypedParamsFree(src.params, src.nparams); qemuTestDriverFree(&driver); -- 2.40.0

On Tue, Apr 18, 2023 at 14:44:47 +0600, Oleg Vasilev wrote:
QEMU now supports multifd-compression=zstd for migration with enabled multifd. Bring the support to libvirt as well.
There is an earlier series implementing this functionality (with zlib as well): [PATCH V3 0/3] migration: add qemu parallel migration options I just forgot to review the last version of it... I did it now. Jirka
participants (2)
-
Jiri Denemark
-
Oleg Vasilev