Blame SOURCES/kvm-migration-stop-decompression-to-allocate-and-free-me.patch

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(&param->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(&param->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