mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
qemu: make 'xz' image compression viable by using -3
For managed save we can choose between various compression methods. I randomly tested the 'xz' program on a 8 GB guest and was surprised to have to wait > 50 minutes for it to finish compressing, with 'xz' burning 100% cpu for the entire time. Despite the impressive compression, this is completely useless in the real world as it is far too long to wait to save the VM. The 'xz' binary defaults to '-6' optimization level which aims for high compression, with moderate memory usage, at the expense of speed. This change switches it to use the '-3' optimization level which is documented as being the one that optimizes speed at expense of compression. Even with this, it will still outperform all the other options in terms of compression level. It is a little less than x4 faster than '-6' which means it starts to be a viable choice to use 'xz' for people who really want best compression. The test results on a 1 GB, fairly freshly booted VM are as follows format | save | restore size =======+=======+============= raw | 05s | 1s | 428 MB lzop | 05s | 3s | 160 MB gzip | 29s | 5s | 118 MB bz2 | 54s | 22s | 114 MB xz | 4m37s | 13s | 86 MB xz -3 | 1m20s | 12s | 95 MB Based on this we can say * For moderate compression with no noticable loss in speed => use lzop * For high compression with moderate loss in speed => use gzip * For best compression with significant loss in speed => use xz Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
986ac40fbf
commit
8aaed287f5
@ -3177,7 +3177,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
|
|||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
const char *path,
|
const char *path,
|
||||||
virQEMUSaveDataPtr data,
|
virQEMUSaveDataPtr data,
|
||||||
const char *compressedpath,
|
virCommandPtr compressor,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
qemuDomainAsyncJob asyncJob)
|
qemuDomainAsyncJob asyncJob)
|
||||||
{
|
{
|
||||||
@ -3216,7 +3216,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Perform the migration */
|
/* Perform the migration */
|
||||||
if (qemuMigrationSrcToFile(driver, vm, fd, compressedpath, asyncJob) < 0)
|
if (qemuMigrationSrcToFile(driver, vm, fd, compressor, asyncJob) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Touch up file header to mark image complete. */
|
/* Touch up file header to mark image complete. */
|
||||||
@ -3259,7 +3259,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
|
|||||||
static int
|
static int
|
||||||
qemuDomainSaveInternal(virQEMUDriverPtr driver,
|
qemuDomainSaveInternal(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm, const char *path,
|
virDomainObjPtr vm, const char *path,
|
||||||
int compressed, const char *compressedpath,
|
int compressed, virCommandPtr compressor,
|
||||||
const char *xmlin, unsigned int flags)
|
const char *xmlin, unsigned int flags)
|
||||||
{
|
{
|
||||||
g_autofree char *xml = NULL;
|
g_autofree char *xml = NULL;
|
||||||
@ -3345,7 +3345,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver,
|
|||||||
goto endjob;
|
goto endjob;
|
||||||
xml = NULL;
|
xml = NULL;
|
||||||
|
|
||||||
ret = qemuDomainSaveMemory(driver, vm, path, data, compressedpath,
|
ret = qemuDomainSaveMemory(driver, vm, path, data, compressor,
|
||||||
flags, QEMU_ASYNC_JOB_SAVE);
|
flags, QEMU_ASYNC_JOB_SAVE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto endjob;
|
goto endjob;
|
||||||
@ -3406,13 +3406,14 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver,
|
|||||||
*/
|
*/
|
||||||
static int ATTRIBUTE_NONNULL(2)
|
static int ATTRIBUTE_NONNULL(2)
|
||||||
qemuGetCompressionProgram(const char *imageFormat,
|
qemuGetCompressionProgram(const char *imageFormat,
|
||||||
char **compresspath,
|
virCommandPtr *compressor,
|
||||||
const char *styleFormat,
|
const char *styleFormat,
|
||||||
bool use_raw_on_fail)
|
bool use_raw_on_fail)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
const char *prog;
|
||||||
|
|
||||||
*compresspath = NULL;
|
*compressor = NULL;
|
||||||
|
|
||||||
if (!imageFormat)
|
if (!imageFormat)
|
||||||
return QEMU_SAVE_FORMAT_RAW;
|
return QEMU_SAVE_FORMAT_RAW;
|
||||||
@ -3423,9 +3424,14 @@ qemuGetCompressionProgram(const char *imageFormat,
|
|||||||
if (ret == QEMU_SAVE_FORMAT_RAW)
|
if (ret == QEMU_SAVE_FORMAT_RAW)
|
||||||
return QEMU_SAVE_FORMAT_RAW;
|
return QEMU_SAVE_FORMAT_RAW;
|
||||||
|
|
||||||
if (!(*compresspath = virFindFileInPath(imageFormat)))
|
if (!(prog = virFindFileInPath(imageFormat)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
*compressor = virCommandNew(prog);
|
||||||
|
virCommandAddArg(*compressor, "-c");
|
||||||
|
if (ret == QEMU_SAVE_FORMAT_XZ)
|
||||||
|
virCommandAddArg(*compressor, "-3");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -3466,7 +3472,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
|
|||||||
{
|
{
|
||||||
virQEMUDriverPtr driver = dom->conn->privateData;
|
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||||
int compressed;
|
int compressed;
|
||||||
g_autofree char *compressedpath = NULL;
|
g_autoptr(virCommand) compressor = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virDomainObjPtr vm = NULL;
|
virDomainObjPtr vm = NULL;
|
||||||
g_autoptr(virQEMUDriverConfig) cfg = NULL;
|
g_autoptr(virQEMUDriverConfig) cfg = NULL;
|
||||||
@ -3477,7 +3483,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
|
|||||||
|
|
||||||
cfg = virQEMUDriverGetConfig(driver);
|
cfg = virQEMUDriverGetConfig(driver);
|
||||||
if ((compressed = qemuGetCompressionProgram(cfg->saveImageFormat,
|
if ((compressed = qemuGetCompressionProgram(cfg->saveImageFormat,
|
||||||
&compressedpath,
|
&compressor,
|
||||||
"save", false)) < 0)
|
"save", false)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -3491,7 +3497,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = qemuDomainSaveInternal(driver, vm, path, compressed,
|
ret = qemuDomainSaveInternal(driver, vm, path, compressed,
|
||||||
compressedpath, dxml, flags);
|
compressor, dxml, flags);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virDomainObjEndAPI(&vm);
|
virDomainObjEndAPI(&vm);
|
||||||
@ -3522,7 +3528,7 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
|
|||||||
virQEMUDriverPtr driver = dom->conn->privateData;
|
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||||
g_autoptr(virQEMUDriverConfig) cfg = NULL;
|
g_autoptr(virQEMUDriverConfig) cfg = NULL;
|
||||||
int compressed;
|
int compressed;
|
||||||
g_autofree char *compressedpath = NULL;
|
g_autoptr(virCommand) compressor = NULL;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
g_autofree char *name = NULL;
|
g_autofree char *name = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -3548,7 +3554,7 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
|
|||||||
|
|
||||||
cfg = virQEMUDriverGetConfig(driver);
|
cfg = virQEMUDriverGetConfig(driver);
|
||||||
if ((compressed = qemuGetCompressionProgram(cfg->saveImageFormat,
|
if ((compressed = qemuGetCompressionProgram(cfg->saveImageFormat,
|
||||||
&compressedpath,
|
&compressor,
|
||||||
"save", false)) < 0)
|
"save", false)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -3558,7 +3564,7 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
|
|||||||
VIR_INFO("Saving state of domain '%s' to '%s'", vm->def->name, name);
|
VIR_INFO("Saving state of domain '%s' to '%s'", vm->def->name, name);
|
||||||
|
|
||||||
ret = qemuDomainSaveInternal(driver, vm, name, compressed,
|
ret = qemuDomainSaveInternal(driver, vm, name, compressed,
|
||||||
compressedpath, NULL, flags);
|
compressor, NULL, flags);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
vm->hasManagedSave = true;
|
vm->hasManagedSave = true;
|
||||||
|
|
||||||
@ -3754,14 +3760,14 @@ doCoreDump(virQEMUDriverPtr driver,
|
|||||||
unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
|
unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
|
||||||
const char *memory_dump_format = NULL;
|
const char *memory_dump_format = NULL;
|
||||||
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
||||||
g_autofree char *compressedpath = NULL;
|
g_autoptr(virCommand) compressor = NULL;
|
||||||
|
|
||||||
/* We reuse "save" flag for "dump" here. Then, we can support the same
|
/* We reuse "save" flag for "dump" here. Then, we can support the same
|
||||||
* format in "save" and "dump". This path doesn't need the compression
|
* format in "save" and "dump". This path doesn't need the compression
|
||||||
* program to exist and can ignore the return value - it only cares to
|
* program to exist and can ignore the return value - it only cares to
|
||||||
* get the compressedpath */
|
* get the compressor */
|
||||||
ignore_value(qemuGetCompressionProgram(cfg->dumpImageFormat,
|
ignore_value(qemuGetCompressionProgram(cfg->dumpImageFormat,
|
||||||
&compressedpath,
|
&compressor,
|
||||||
"dump", true));
|
"dump", true));
|
||||||
|
|
||||||
/* Create an empty file with appropriate ownership. */
|
/* Create an empty file with appropriate ownership. */
|
||||||
@ -3809,7 +3815,7 @@ doCoreDump(virQEMUDriverPtr driver,
|
|||||||
if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
|
if (!qemuMigrationSrcIsAllowed(driver, vm, false, 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = qemuMigrationSrcToFile(driver, vm, fd, compressedpath,
|
ret = qemuMigrationSrcToFile(driver, vm, fd, compressor,
|
||||||
QEMU_ASYNC_JOB_DUMP);
|
QEMU_ASYNC_JOB_DUMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15586,7 +15592,7 @@ qemuDomainSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
|
|||||||
int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
|
int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
|
||||||
bool pmsuspended = false;
|
bool pmsuspended = false;
|
||||||
int compressed;
|
int compressed;
|
||||||
g_autofree char *compressedpath = NULL;
|
g_autoptr(virCommand) compressor = NULL;
|
||||||
virQEMUSaveDataPtr data = NULL;
|
virQEMUSaveDataPtr data = NULL;
|
||||||
|
|
||||||
/* If quiesce was requested, then issue a freeze command, and a
|
/* If quiesce was requested, then issue a freeze command, and a
|
||||||
@ -15656,7 +15662,7 @@ qemuDomainSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
|
|||||||
JOB_MASK(QEMU_JOB_MIGRATION_OP)));
|
JOB_MASK(QEMU_JOB_MIGRATION_OP)));
|
||||||
|
|
||||||
if ((compressed = qemuGetCompressionProgram(cfg->snapshotImageFormat,
|
if ((compressed = qemuGetCompressionProgram(cfg->snapshotImageFormat,
|
||||||
&compressedpath,
|
&compressor,
|
||||||
"snapshot", false)) < 0)
|
"snapshot", false)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -15673,7 +15679,7 @@ qemuDomainSnapshotCreateActiveExternal(virQEMUDriverPtr driver,
|
|||||||
xml = NULL;
|
xml = NULL;
|
||||||
|
|
||||||
if ((ret = qemuDomainSaveMemory(driver, vm, snapdef->file, data,
|
if ((ret = qemuDomainSaveMemory(driver, vm, snapdef->file, data,
|
||||||
compressedpath, 0,
|
compressor, 0,
|
||||||
QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
|
QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
@ -5170,13 +5170,12 @@ qemuMigrationDstFinish(virQEMUDriverPtr driver,
|
|||||||
int
|
int
|
||||||
qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||||
int fd,
|
int fd,
|
||||||
const char *compressor,
|
virCommandPtr compressor,
|
||||||
qemuDomainAsyncJob asyncJob)
|
qemuDomainAsyncJob asyncJob)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
int rc;
|
int rc;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virCommandPtr cmd = NULL;
|
|
||||||
int pipeFD[2] = { -1, -1 };
|
int pipeFD[2] = { -1, -1 };
|
||||||
unsigned long saveMigBandwidth = priv->migMaxBandwidth;
|
unsigned long saveMigBandwidth = priv->migMaxBandwidth;
|
||||||
char *errbuf = NULL;
|
char *errbuf = NULL;
|
||||||
@ -5221,25 +5220,17 @@ qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
|||||||
QEMU_MONITOR_MIGRATE_BACKGROUND,
|
QEMU_MONITOR_MIGRATE_BACKGROUND,
|
||||||
fd);
|
fd);
|
||||||
} else {
|
} else {
|
||||||
const char *prog = compressor;
|
virCommandSetInputFD(compressor, pipeFD[0]);
|
||||||
const char *args[] = {
|
virCommandSetOutputFD(compressor, &fd);
|
||||||
prog,
|
virCommandSetErrorBuffer(compressor, &errbuf);
|
||||||
"-c",
|
virCommandDoAsyncIO(compressor);
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
cmd = virCommandNewArgs(args);
|
|
||||||
virCommandSetInputFD(cmd, pipeFD[0]);
|
|
||||||
virCommandSetOutputFD(cmd, &fd);
|
|
||||||
virCommandSetErrorBuffer(cmd, &errbuf);
|
|
||||||
virCommandDoAsyncIO(cmd);
|
|
||||||
if (virSetCloseExec(pipeFD[1]) < 0) {
|
if (virSetCloseExec(pipeFD[1]) < 0) {
|
||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
_("Unable to set cloexec flag"));
|
_("Unable to set cloexec flag"));
|
||||||
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (virCommandRunAsync(cmd, NULL) < 0) {
|
if (virCommandRunAsync(compressor, NULL) < 0) {
|
||||||
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -5260,7 +5251,7 @@ qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
|||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (rc == -2) {
|
if (rc == -2) {
|
||||||
virErrorPreserveLast(&orig_err);
|
virErrorPreserveLast(&orig_err);
|
||||||
virCommandAbort(cmd);
|
virCommandAbort(compressor);
|
||||||
if (virDomainObjIsActive(vm) &&
|
if (virDomainObjIsActive(vm) &&
|
||||||
qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
|
qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
|
||||||
qemuMonitorMigrateCancel(priv->mon);
|
qemuMonitorMigrateCancel(priv->mon);
|
||||||
@ -5270,7 +5261,7 @@ qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd && virCommandWait(cmd, NULL) < 0)
|
if (compressor && virCommandWait(compressor, NULL) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
qemuDomainEventEmitJobCompleted(driver, vm);
|
qemuDomainEventEmitJobCompleted(driver, vm);
|
||||||
@ -5290,10 +5281,9 @@ qemuMigrationSrcToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
|||||||
|
|
||||||
VIR_FORCE_CLOSE(pipeFD[0]);
|
VIR_FORCE_CLOSE(pipeFD[0]);
|
||||||
VIR_FORCE_CLOSE(pipeFD[1]);
|
VIR_FORCE_CLOSE(pipeFD[1]);
|
||||||
if (cmd) {
|
if (errbuf) {
|
||||||
VIR_DEBUG("Compression binary stderr: %s", NULLSTR(errbuf));
|
VIR_DEBUG("Compression binary stderr: %s", NULLSTR(errbuf));
|
||||||
VIR_FREE(errbuf);
|
VIR_FREE(errbuf);
|
||||||
virCommandFree(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virErrorRestore(&orig_err);
|
virErrorRestore(&orig_err);
|
||||||
|
@ -204,7 +204,7 @@ int
|
|||||||
qemuMigrationSrcToFile(virQEMUDriverPtr driver,
|
qemuMigrationSrcToFile(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
int fd,
|
int fd,
|
||||||
const char *compressor,
|
virCommandPtr compressor,
|
||||||
qemuDomainAsyncJob asyncJob)
|
qemuDomainAsyncJob asyncJob)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user