|
|
26ba25 |
From 2caad7e48038f5303651bde85b559b3ad19dd262 Mon Sep 17 00:00:00 2001
|
|
|
26ba25 |
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
|
|
|
26ba25 |
Date: Wed, 1 Aug 2018 13:55:07 +0100
|
|
|
26ba25 |
Subject: [PATCH 03/21] migration: stop decompression to allocate and free
|
|
|
26ba25 |
memory frequently
|
|
|
26ba25 |
|
|
|
26ba25 |
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
26ba25 |
Message-id: <20180801135522.11658-4-dgilbert@redhat.com>
|
|
|
26ba25 |
Patchwork-id: 81571
|
|
|
26ba25 |
O-Subject: [qemu-kvm RHEL8/virt212 PATCH 03/18] migration: stop decompression to allocate and free memory frequently
|
|
|
26ba25 |
Bugzilla: 1594384
|
|
|
26ba25 |
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
|
|
26ba25 |
RH-Acked-by: John Snow <jsnow@redhat.com>
|
|
|
26ba25 |
RH-Acked-by: Juan Quintela <quintela@redhat.com>
|
|
|
26ba25 |
|
|
|
26ba25 |
From: Xiao Guangrong <xiaoguangrong@tencent.com>
|
|
|
26ba25 |
|
|
|
26ba25 |
Current code uses uncompress() to decompress memory which manages
|
|
|
26ba25 |
memory internally, that causes huge memory is allocated and freed
|
|
|
26ba25 |
very frequently, more worse, frequently returning memory to kernel
|
|
|
26ba25 |
will flush TLBs
|
|
|
26ba25 |
|
|
|
26ba25 |
So, we maintain the memory by ourselves and reuse it for each
|
|
|
26ba25 |
decompression
|
|
|
26ba25 |
|
|
|
26ba25 |
Reviewed-by: Peter Xu <peterx@redhat.com>
|
|
|
26ba25 |
Reviewed-by: Jiang Biao <jiang.biao2@zte.com.cn>
|
|
|
26ba25 |
Signed-off-by: Xiao Guangrong <xiaoguangrong@tencent.com>
|
|
|
26ba25 |
Message-Id: <20180330075128.26919-4-xiaoguangrong@tencent.com>
|
|
|
26ba25 |
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
26ba25 |
(cherry picked from commit 797ca154b4c68dbd8e93382f714388ab311f672d)
|
|
|
26ba25 |
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
|
|
|
26ba25 |
---
|
|
|
26ba25 |
migration/ram.c | 112 +++++++++++++++++++++++++++++++++++++++++---------------
|
|
|
26ba25 |
1 file changed, 82 insertions(+), 30 deletions(-)
|
|
|
26ba25 |
|
|
|
26ba25 |
diff --git a/migration/ram.c b/migration/ram.c
|
|
|
26ba25 |
index 7d3b1da..be89cd8 100644
|
|
|
26ba25 |
--- a/migration/ram.c
|
|
|
26ba25 |
+++ b/migration/ram.c
|
|
|
26ba25 |
@@ -281,6 +281,7 @@ struct DecompressParam {
|
|
|
26ba25 |
void *des;
|
|
|
26ba25 |
uint8_t *compbuf;
|
|
|
26ba25 |
int len;
|
|
|
26ba25 |
+ z_stream stream;
|
|
|
26ba25 |
};
|
|
|
26ba25 |
typedef struct DecompressParam DecompressParam;
|
|
|
26ba25 |
|
|
|
26ba25 |
@@ -2525,6 +2526,31 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
|
|
|
26ba25 |
}
|
|
|
26ba25 |
}
|
|
|
26ba25 |
|
|
|
26ba25 |
+/* return the size after decompression, or negative value on error */
|
|
|
26ba25 |
+static int
|
|
|
26ba25 |
+qemu_uncompress_data(z_stream *stream, uint8_t *dest, size_t dest_len,
|
|
|
26ba25 |
+ const uint8_t *source, size_t source_len)
|
|
|
26ba25 |
+{
|
|
|
26ba25 |
+ int err;
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ err = inflateReset(stream);
|
|
|
26ba25 |
+ if (err != Z_OK) {
|
|
|
26ba25 |
+ return -1;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ stream->avail_in = source_len;
|
|
|
26ba25 |
+ stream->next_in = (uint8_t *)source;
|
|
|
26ba25 |
+ stream->avail_out = dest_len;
|
|
|
26ba25 |
+ stream->next_out = dest;
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ err = inflate(stream, Z_NO_FLUSH);
|
|
|
26ba25 |
+ if (err != Z_STREAM_END) {
|
|
|
26ba25 |
+ return -1;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ return stream->total_out;
|
|
|
26ba25 |
+}
|
|
|
26ba25 |
+
|
|
|
26ba25 |
static void *do_data_decompress(void *opaque)
|
|
|
26ba25 |
{
|
|
|
26ba25 |
DecompressParam *param = opaque;
|
|
|
26ba25 |
@@ -2541,13 +2567,13 @@ static void *do_data_decompress(void *opaque)
|
|
|
26ba25 |
qemu_mutex_unlock(¶m->mutex);
|
|
|
26ba25 |
|
|
|
26ba25 |
pagesize = TARGET_PAGE_SIZE;
|
|
|
26ba25 |
- /* uncompress() will return failed in some case, especially
|
|
|
26ba25 |
- * when the page is dirted when doing the compression, it's
|
|
|
26ba25 |
- * not a problem because the dirty page will be retransferred
|
|
|
26ba25 |
+ /* qemu_uncompress_data() will return failed in some case,
|
|
|
26ba25 |
+ * especially when the page is dirtied when doing the compression,
|
|
|
26ba25 |
+ * it's not a problem because the dirty page will be retransferred
|
|
|
26ba25 |
* and uncompress() won't break the data in other pages.
|
|
|
26ba25 |
*/
|
|
|
26ba25 |
- uncompress((Bytef *)des, &pagesize,
|
|
|
26ba25 |
- (const Bytef *)param->compbuf, len);
|
|
|
26ba25 |
+ qemu_uncompress_data(¶m->stream, des, pagesize, param->compbuf,
|
|
|
26ba25 |
+ len);
|
|
|
26ba25 |
|
|
|
26ba25 |
qemu_mutex_lock(&decomp_done_lock);
|
|
|
26ba25 |
param->done = true;
|
|
|
26ba25 |
@@ -2582,30 +2608,6 @@ static void wait_for_decompress_done(void)
|
|
|
26ba25 |
qemu_mutex_unlock(&decomp_done_lock);
|
|
|
26ba25 |
}
|
|
|
26ba25 |
|
|
|
26ba25 |
-static void compress_threads_load_setup(void)
|
|
|
26ba25 |
-{
|
|
|
26ba25 |
- int i, thread_count;
|
|
|
26ba25 |
-
|
|
|
26ba25 |
- if (!migrate_use_compression()) {
|
|
|
26ba25 |
- return;
|
|
|
26ba25 |
- }
|
|
|
26ba25 |
- thread_count = migrate_decompress_threads();
|
|
|
26ba25 |
- decompress_threads = g_new0(QemuThread, thread_count);
|
|
|
26ba25 |
- decomp_param = g_new0(DecompressParam, thread_count);
|
|
|
26ba25 |
- qemu_mutex_init(&decomp_done_lock);
|
|
|
26ba25 |
- qemu_cond_init(&decomp_done_cond);
|
|
|
26ba25 |
- for (i = 0; i < thread_count; i++) {
|
|
|
26ba25 |
- qemu_mutex_init(&decomp_param[i].mutex);
|
|
|
26ba25 |
- qemu_cond_init(&decomp_param[i].cond);
|
|
|
26ba25 |
- decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE));
|
|
|
26ba25 |
- decomp_param[i].done = true;
|
|
|
26ba25 |
- decomp_param[i].quit = false;
|
|
|
26ba25 |
- qemu_thread_create(decompress_threads + i, "decompress",
|
|
|
26ba25 |
- do_data_decompress, decomp_param + i,
|
|
|
26ba25 |
- QEMU_THREAD_JOINABLE);
|
|
|
26ba25 |
- }
|
|
|
26ba25 |
-}
|
|
|
26ba25 |
-
|
|
|
26ba25 |
static void compress_threads_load_cleanup(void)
|
|
|
26ba25 |
{
|
|
|
26ba25 |
int i, thread_count;
|
|
|
26ba25 |
@@ -2615,16 +2617,30 @@ static void compress_threads_load_cleanup(void)
|
|
|
26ba25 |
}
|
|
|
26ba25 |
thread_count = migrate_decompress_threads();
|
|
|
26ba25 |
for (i = 0; i < thread_count; i++) {
|
|
|
26ba25 |
+ /*
|
|
|
26ba25 |
+ * we use it as a indicator which shows if the thread is
|
|
|
26ba25 |
+ * properly init'd or not
|
|
|
26ba25 |
+ */
|
|
|
26ba25 |
+ if (!decomp_param[i].compbuf) {
|
|
|
26ba25 |
+ break;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
qemu_mutex_lock(&decomp_param[i].mutex);
|
|
|
26ba25 |
decomp_param[i].quit = true;
|
|
|
26ba25 |
qemu_cond_signal(&decomp_param[i].cond);
|
|
|
26ba25 |
qemu_mutex_unlock(&decomp_param[i].mutex);
|
|
|
26ba25 |
}
|
|
|
26ba25 |
for (i = 0; i < thread_count; i++) {
|
|
|
26ba25 |
+ if (!decomp_param[i].compbuf) {
|
|
|
26ba25 |
+ break;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
qemu_thread_join(decompress_threads + i);
|
|
|
26ba25 |
qemu_mutex_destroy(&decomp_param[i].mutex);
|
|
|
26ba25 |
qemu_cond_destroy(&decomp_param[i].cond);
|
|
|
26ba25 |
+ inflateEnd(&decomp_param[i].stream);
|
|
|
26ba25 |
g_free(decomp_param[i].compbuf);
|
|
|
26ba25 |
+ decomp_param[i].compbuf = NULL;
|
|
|
26ba25 |
}
|
|
|
26ba25 |
g_free(decompress_threads);
|
|
|
26ba25 |
g_free(decomp_param);
|
|
|
26ba25 |
@@ -2632,6 +2648,39 @@ static void compress_threads_load_cleanup(void)
|
|
|
26ba25 |
decomp_param = NULL;
|
|
|
26ba25 |
}
|
|
|
26ba25 |
|
|
|
26ba25 |
+static int compress_threads_load_setup(void)
|
|
|
26ba25 |
+{
|
|
|
26ba25 |
+ int i, thread_count;
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ if (!migrate_use_compression()) {
|
|
|
26ba25 |
+ return 0;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ thread_count = migrate_decompress_threads();
|
|
|
26ba25 |
+ decompress_threads = g_new0(QemuThread, thread_count);
|
|
|
26ba25 |
+ decomp_param = g_new0(DecompressParam, thread_count);
|
|
|
26ba25 |
+ qemu_mutex_init(&decomp_done_lock);
|
|
|
26ba25 |
+ qemu_cond_init(&decomp_done_cond);
|
|
|
26ba25 |
+ for (i = 0; i < thread_count; i++) {
|
|
|
26ba25 |
+ if (inflateInit(&decomp_param[i].stream) != Z_OK) {
|
|
|
26ba25 |
+ goto exit;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
+ decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE));
|
|
|
26ba25 |
+ qemu_mutex_init(&decomp_param[i].mutex);
|
|
|
26ba25 |
+ qemu_cond_init(&decomp_param[i].cond);
|
|
|
26ba25 |
+ decomp_param[i].done = true;
|
|
|
26ba25 |
+ decomp_param[i].quit = false;
|
|
|
26ba25 |
+ qemu_thread_create(decompress_threads + i, "decompress",
|
|
|
26ba25 |
+ do_data_decompress, decomp_param + i,
|
|
|
26ba25 |
+ QEMU_THREAD_JOINABLE);
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+ return 0;
|
|
|
26ba25 |
+exit:
|
|
|
26ba25 |
+ compress_threads_load_cleanup();
|
|
|
26ba25 |
+ return -1;
|
|
|
26ba25 |
+}
|
|
|
26ba25 |
+
|
|
|
26ba25 |
static void decompress_data_with_multi_threads(QEMUFile *f,
|
|
|
26ba25 |
void *host, int len)
|
|
|
26ba25 |
{
|
|
|
26ba25 |
@@ -2671,8 +2720,11 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
|
|
|
26ba25 |
*/
|
|
|
26ba25 |
static int ram_load_setup(QEMUFile *f, void *opaque)
|
|
|
26ba25 |
{
|
|
|
26ba25 |
+ if (compress_threads_load_setup()) {
|
|
|
26ba25 |
+ return -1;
|
|
|
26ba25 |
+ }
|
|
|
26ba25 |
+
|
|
|
26ba25 |
xbzrle_load_setup();
|
|
|
26ba25 |
- compress_threads_load_setup();
|
|
|
26ba25 |
ramblock_recv_map_init();
|
|
|
26ba25 |
return 0;
|
|
|
26ba25 |
}
|
|
|
26ba25 |
--
|
|
|
26ba25 |
1.8.3.1
|
|
|
26ba25 |
|