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

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