Blame SOURCES/kvm-migration-stop-compression-to-allocate-and-free-memo.patch

357786
From 6a6e25b0dff81b5a6dc4272a176f5987b7474a93 Mon Sep 17 00:00:00 2001
357786
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
357786
Date: Fri, 22 Jun 2018 18:59:49 +0200
357786
Subject: [PATCH 10/57] migration: stop compression to allocate and free memory
357786
 frequently
357786
357786
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
357786
Message-id: <20180622190005.21297-3-dgilbert@redhat.com>
357786
Patchwork-id: 80998
357786
O-Subject: [RHEL7.6 qemu-kvm-rhev PATCH 02/18] migration: stop compression 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 compress2() to compress memory which manages memory
357786
internally, that causes huge memory is allocated and freed very
357786
frequently
357786
357786
More worse, frequently returning memory to kernel will flush TLBs
357786
and trigger invalidation callbacks on mmu-notification which
357786
interacts with KVM MMU, that dramatically reduce the performance
357786
of VM
357786
357786
So, we maintain the memory by ourselves and reuse it for each
357786
compression
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-3-xiaoguangrong@tencent.com>
357786
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
357786
(cherry picked from commit dcaf446ebda5d87e05eb41cdbafb7ae4a7cc4a62)
357786
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
357786
---
357786
 migration/qemu-file.c | 39 ++++++++++++++++++++++++++++++++-------
357786
 migration/qemu-file.h |  6 ++++--
357786
 migration/ram.c       | 41 ++++++++++++++++++++++++++++++++---------
357786
 3 files changed, 68 insertions(+), 18 deletions(-)
357786
357786
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
357786
index bb63c77..bafe3a0 100644
357786
--- a/migration/qemu-file.c
357786
+++ b/migration/qemu-file.c
357786
@@ -658,8 +658,32 @@ uint64_t qemu_get_be64(QEMUFile *f)
357786
     return v;
357786
 }
357786
 
357786
-/* Compress size bytes of data start at p with specific compression
357786
- * level and store the compressed data to the buffer of f.
357786
+/* return the size after compression, or negative value on error */
357786
+static int qemu_compress_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 = deflateReset(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 = deflate(stream, Z_FINISH);
357786
+    if (err != Z_STREAM_END) {
357786
+        return -1;
357786
+    }
357786
+
357786
+    return stream->next_out - dest;
357786
+}
357786
+
357786
+/* Compress size bytes of data start at p and store the compressed
357786
+ * data to the buffer of f.
357786
  *
357786
  * When f is not writable, return -1 if f has no space to save the
357786
  * compressed data.
357786
@@ -667,9 +691,8 @@ uint64_t qemu_get_be64(QEMUFile *f)
357786
  * do fflush first, if f still has no space to save the compressed
357786
  * data, return -1.
357786
  */
357786
-
357786
-ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size,
357786
-                                  int level)
357786
+ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
357786
+                                  const uint8_t *p, size_t size)
357786
 {
357786
     ssize_t blen = IO_BUF_SIZE - f->buf_index - sizeof(int32_t);
357786
 
357786
@@ -683,8 +706,10 @@ ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size,
357786
             return -1;
357786
         }
357786
     }
357786
-    if (compress2(f->buf + f->buf_index + sizeof(int32_t), (uLongf *)&blen,
357786
-                  (Bytef *)p, size, level) != Z_OK) {
357786
+
357786
+    blen = qemu_compress_data(stream, f->buf + f->buf_index + sizeof(int32_t),
357786
+                              blen, p, size);
357786
+    if (blen < 0) {
357786
         error_report("Compress Failed!");
357786
         return 0;
357786
     }
357786
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
357786
index f4f356a..2ccfcfb 100644
357786
--- a/migration/qemu-file.h
357786
+++ b/migration/qemu-file.h
357786
@@ -25,6 +25,8 @@
357786
 #ifndef MIGRATION_QEMU_FILE_H
357786
 #define MIGRATION_QEMU_FILE_H
357786
 
357786
+#include <zlib.h>
357786
+
357786
 /* Read a chunk of data from a file at the given position.  The pos argument
357786
  * can be ignored if the file is only be used for streaming.  The number of
357786
  * bytes actually read should be returned.
357786
@@ -132,8 +134,8 @@ bool qemu_file_is_writable(QEMUFile *f);
357786
 
357786
 size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset);
357786
 size_t qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size);
357786
-ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size,
357786
-                                  int level);
357786
+ssize_t qemu_put_compression_data(QEMUFile *f, z_stream *stream,
357786
+                                  const uint8_t *p, size_t size);
357786
 int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src);
357786
 
357786
 /*
357786
diff --git a/migration/ram.c b/migration/ram.c
357786
index f27038a..7d3b1da 100644
357786
--- a/migration/ram.c
357786
+++ b/migration/ram.c
357786
@@ -269,6 +269,7 @@ struct CompressParam {
357786
     QemuCond cond;
357786
     RAMBlock *block;
357786
     ram_addr_t offset;
357786
+    z_stream stream;
357786
 };
357786
 typedef struct CompressParam CompressParam;
357786
 
357786
@@ -299,7 +300,7 @@ static QemuThread *decompress_threads;
357786
 static QemuMutex decomp_done_lock;
357786
 static QemuCond decomp_done_cond;
357786
 
357786
-static int do_compress_ram_page(QEMUFile *f, RAMBlock *block,
357786
+static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
357786
                                 ram_addr_t offset);
357786
 
357786
 static void *do_data_compress(void *opaque)
357786
@@ -316,7 +317,7 @@ static void *do_data_compress(void *opaque)
357786
             param->block = NULL;
357786
             qemu_mutex_unlock(&param->mutex);
357786
 
357786
-            do_compress_ram_page(param->file, block, offset);
357786
+            do_compress_ram_page(param->file, &param->stream, block, offset);
357786
 
357786
             qemu_mutex_lock(&comp_done_lock);
357786
             param->done = true;
357786
@@ -357,10 +358,19 @@ static void compress_threads_save_cleanup(void)
357786
     terminate_compression_threads();
357786
     thread_count = migrate_compress_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 (!comp_param[i].file) {
357786
+            break;
357786
+        }
357786
         qemu_thread_join(compress_threads + i);
357786
-        qemu_fclose(comp_param[i].file);
357786
         qemu_mutex_destroy(&comp_param[i].mutex);
357786
         qemu_cond_destroy(&comp_param[i].cond);
357786
+        deflateEnd(&comp_param[i].stream);
357786
+        qemu_fclose(comp_param[i].file);
357786
+        comp_param[i].file = NULL;
357786
     }
357786
     qemu_mutex_destroy(&comp_done_lock);
357786
     qemu_cond_destroy(&comp_done_cond);
357786
@@ -370,12 +380,12 @@ static void compress_threads_save_cleanup(void)
357786
     comp_param = NULL;
357786
 }
357786
 
357786
-static void compress_threads_save_setup(void)
357786
+static int compress_threads_save_setup(void)
357786
 {
357786
     int i, thread_count;
357786
 
357786
     if (!migrate_use_compression()) {
357786
-        return;
357786
+        return 0;
357786
     }
357786
     thread_count = migrate_compress_threads();
357786
     compress_threads = g_new0(QemuThread, thread_count);
357786
@@ -383,6 +393,11 @@ static void compress_threads_save_setup(void)
357786
     qemu_cond_init(&comp_done_cond);
357786
     qemu_mutex_init(&comp_done_lock);
357786
     for (i = 0; i < thread_count; i++) {
357786
+        if (deflateInit(&comp_param[i].stream,
357786
+                        migrate_compress_level()) != Z_OK) {
357786
+            goto exit;
357786
+        }
357786
+
357786
         /* comp_param[i].file is just used as a dummy buffer to save data,
357786
          * set its ops to empty.
357786
          */
357786
@@ -395,6 +410,11 @@ static void compress_threads_save_setup(void)
357786
                            do_data_compress, comp_param + i,
357786
                            QEMU_THREAD_JOINABLE);
357786
     }
357786
+    return 0;
357786
+
357786
+exit:
357786
+    compress_threads_save_cleanup();
357786
+    return -1;
357786
 }
357786
 
357786
 /* Multiple fd's */
357786
@@ -1032,7 +1052,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
357786
     return pages;
357786
 }
357786
 
357786
-static int do_compress_ram_page(QEMUFile *f, RAMBlock *block,
357786
+static int do_compress_ram_page(QEMUFile *f, z_stream *stream, RAMBlock *block,
357786
                                 ram_addr_t offset)
357786
 {
357786
     RAMState *rs = ram_state;
357786
@@ -1041,8 +1061,7 @@ static int do_compress_ram_page(QEMUFile *f, RAMBlock *block,
357786
 
357786
     bytes_sent = save_page_header(rs, f, block, offset |
357786
                                   RAM_SAVE_FLAG_COMPRESS_PAGE);
357786
-    blen = qemu_put_compression_data(f, p, TARGET_PAGE_SIZE,
357786
-                                     migrate_compress_level());
357786
+    blen = qemu_put_compression_data(f, stream, p, TARGET_PAGE_SIZE);
357786
     if (blen < 0) {
357786
         bytes_sent = 0;
357786
         qemu_file_set_error(migrate_get_current()->to_dst_file, blen);
357786
@@ -2215,9 +2234,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
357786
     RAMState **rsp = opaque;
357786
     RAMBlock *block;
357786
 
357786
+    if (compress_threads_save_setup()) {
357786
+        return -1;
357786
+    }
357786
+
357786
     /* migration has already setup the bitmap, reuse it. */
357786
     if (!migration_in_colo_state()) {
357786
         if (ram_init_all(rsp) != 0) {
357786
+            compress_threads_save_cleanup();
357786
             return -1;
357786
         }
357786
     }
357786
@@ -2237,7 +2261,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
357786
     }
357786
 
357786
     rcu_read_unlock();
357786
-    compress_threads_save_setup();
357786
 
357786
     ram_control_before_iterate(f, RAM_CONTROL_SETUP);
357786
     ram_control_after_iterate(f, RAM_CONTROL_SETUP);
357786
-- 
357786
1.8.3.1
357786