[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 09/16] migration: stop decompression to allocate and
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[Qemu-devel] [PULL 09/16] migration: stop decompression to allocate and free memory frequently |
Date: |
Wed, 25 Apr 2018 21:03:19 +0100 |
From: Xiao Guangrong <address@hidden>
Current code uses uncompress() to decompress memory which manages
memory internally, that causes huge memory is allocated and freed
very frequently, more worse, frequently returning memory to kernel
will flush TLBs
So, we maintain the memory by ourselves and reuse it for each
decompression
Reviewed-by: Peter Xu <address@hidden>
Reviewed-by: Jiang Biao <address@hidden>
Signed-off-by: Xiao Guangrong <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
migration/ram.c | 112 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 82 insertions(+), 30 deletions(-)
diff --git a/migration/ram.c b/migration/ram.c
index a21514a469..fb24b2f32f 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -281,6 +281,7 @@ struct DecompressParam {
void *des;
uint8_t *compbuf;
int len;
+ z_stream stream;
};
typedef struct DecompressParam DecompressParam;
@@ -2524,6 +2525,31 @@ void ram_handle_compressed(void *host, uint8_t ch,
uint64_t size)
}
}
+/* return the size after decompression, or negative value on error */
+static int
+qemu_uncompress_data(z_stream *stream, uint8_t *dest, size_t dest_len,
+ const uint8_t *source, size_t source_len)
+{
+ int err;
+
+ err = inflateReset(stream);
+ if (err != Z_OK) {
+ return -1;
+ }
+
+ stream->avail_in = source_len;
+ stream->next_in = (uint8_t *)source;
+ stream->avail_out = dest_len;
+ stream->next_out = dest;
+
+ err = inflate(stream, Z_NO_FLUSH);
+ if (err != Z_STREAM_END) {
+ return -1;
+ }
+
+ return stream->total_out;
+}
+
static void *do_data_decompress(void *opaque)
{
DecompressParam *param = opaque;
@@ -2540,13 +2566,13 @@ static void *do_data_decompress(void *opaque)
qemu_mutex_unlock(¶m->mutex);
pagesize = TARGET_PAGE_SIZE;
- /* uncompress() will return failed in some case, especially
- * when the page is dirted when doing the compression, it's
- * not a problem because the dirty page will be retransferred
+ /* qemu_uncompress_data() will return failed in some case,
+ * especially when the page is dirtied when doing the compression,
+ * it's not a problem because the dirty page will be retransferred
* and uncompress() won't break the data in other pages.
*/
- uncompress((Bytef *)des, &pagesize,
- (const Bytef *)param->compbuf, len);
+ qemu_uncompress_data(¶m->stream, des, pagesize, param->compbuf,
+ len);
qemu_mutex_lock(&decomp_done_lock);
param->done = true;
@@ -2581,30 +2607,6 @@ static void wait_for_decompress_done(void)
qemu_mutex_unlock(&decomp_done_lock);
}
-static void compress_threads_load_setup(void)
-{
- int i, thread_count;
-
- if (!migrate_use_compression()) {
- return;
- }
- thread_count = migrate_decompress_threads();
- decompress_threads = g_new0(QemuThread, thread_count);
- decomp_param = g_new0(DecompressParam, thread_count);
- qemu_mutex_init(&decomp_done_lock);
- qemu_cond_init(&decomp_done_cond);
- for (i = 0; i < thread_count; i++) {
- qemu_mutex_init(&decomp_param[i].mutex);
- qemu_cond_init(&decomp_param[i].cond);
- decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE));
- decomp_param[i].done = true;
- decomp_param[i].quit = false;
- qemu_thread_create(decompress_threads + i, "decompress",
- do_data_decompress, decomp_param + i,
- QEMU_THREAD_JOINABLE);
- }
-}
-
static void compress_threads_load_cleanup(void)
{
int i, thread_count;
@@ -2614,16 +2616,30 @@ static void compress_threads_load_cleanup(void)
}
thread_count = migrate_decompress_threads();
for (i = 0; i < thread_count; i++) {
+ /*
+ * we use it as a indicator which shows if the thread is
+ * properly init'd or not
+ */
+ if (!decomp_param[i].compbuf) {
+ break;
+ }
+
qemu_mutex_lock(&decomp_param[i].mutex);
decomp_param[i].quit = true;
qemu_cond_signal(&decomp_param[i].cond);
qemu_mutex_unlock(&decomp_param[i].mutex);
}
for (i = 0; i < thread_count; i++) {
+ if (!decomp_param[i].compbuf) {
+ break;
+ }
+
qemu_thread_join(decompress_threads + i);
qemu_mutex_destroy(&decomp_param[i].mutex);
qemu_cond_destroy(&decomp_param[i].cond);
+ inflateEnd(&decomp_param[i].stream);
g_free(decomp_param[i].compbuf);
+ decomp_param[i].compbuf = NULL;
}
g_free(decompress_threads);
g_free(decomp_param);
@@ -2631,6 +2647,39 @@ static void compress_threads_load_cleanup(void)
decomp_param = NULL;
}
+static int compress_threads_load_setup(void)
+{
+ int i, thread_count;
+
+ if (!migrate_use_compression()) {
+ return 0;
+ }
+
+ thread_count = migrate_decompress_threads();
+ decompress_threads = g_new0(QemuThread, thread_count);
+ decomp_param = g_new0(DecompressParam, thread_count);
+ qemu_mutex_init(&decomp_done_lock);
+ qemu_cond_init(&decomp_done_cond);
+ for (i = 0; i < thread_count; i++) {
+ if (inflateInit(&decomp_param[i].stream) != Z_OK) {
+ goto exit;
+ }
+
+ decomp_param[i].compbuf = g_malloc0(compressBound(TARGET_PAGE_SIZE));
+ qemu_mutex_init(&decomp_param[i].mutex);
+ qemu_cond_init(&decomp_param[i].cond);
+ decomp_param[i].done = true;
+ decomp_param[i].quit = false;
+ qemu_thread_create(decompress_threads + i, "decompress",
+ do_data_decompress, decomp_param + i,
+ QEMU_THREAD_JOINABLE);
+ }
+ return 0;
+exit:
+ compress_threads_load_cleanup();
+ return -1;
+}
+
static void decompress_data_with_multi_threads(QEMUFile *f,
void *host, int len)
{
@@ -2670,8 +2719,11 @@ static void decompress_data_with_multi_threads(QEMUFile
*f,
*/
static int ram_load_setup(QEMUFile *f, void *opaque)
{
+ if (compress_threads_load_setup()) {
+ return -1;
+ }
+
xbzrle_load_setup();
- compress_threads_load_setup();
ramblock_recv_map_init();
return 0;
}
--
2.17.0
- [Qemu-devel] [PULL 00/16] migration queue, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 04/16] migration: postcopy_blocktime documentation, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 01/16] migration: introduce postcopy-blocktime capability, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 02/16] migration: add postcopy blocktime ctx into MigrationIncomingState, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 05/16] migration: add blocktime calculation into migration-test, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 08/16] migration: stop compression to allocate and free memory frequently, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 07/16] migration: stop compressing page in migration thread, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 09/16] migration: stop decompression to allocate and free memory frequently,
Dr. David Alan Gilbert (git) <=
- [Qemu-devel] [PULL 06/16] migration: add postcopy total blocktime into query-migrate, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 15/16] migration: introduce save_normal_page(), Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 14/16] migration: move calling save_zero_page to the common place, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 03/16] migration: calculate vCPU blocktime on dst side, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 10/16] migration: detect compression and decompression errors, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 12/16] migration: move some code to ram_save_host_page, Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 11/16] migration: introduce control_save_page(), Dr. David Alan Gilbert (git), 2018/04/25
- [Qemu-devel] [PULL 13/16] migration: move calling control_save_page to the common place, Dr. David Alan Gilbert (git), 2018/04/25