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