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

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