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

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