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

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