Skip to content

Commit

Permalink
migration/multifd: Implement zero page transmission on the multifd th…
Browse files Browse the repository at this point in the history
…read.

1. Add zero_pages field in MultiFDPacket_t.
2. Implements the zero page detection and handling on the multifd
threads for non-compression, zlib and zstd compression backends.
3. Added a new value 'multifd' in ZeroPageDetection enumeration.
4. Adds zero page counters and updates multifd send/receive tracing
format to track the newly added counters.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Link: https://lore.kernel.org/r/20240311180015.3359271-5-hao.xiang@linux.dev
Signed-off-by: Peter Xu <peterx@redhat.com>
  • Loading branch information
haoxiangbd authored and xzpeter committed Mar 11, 2024
1 parent 5fdbb1d commit 303e6f5
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 32 deletions.
2 changes: 1 addition & 1 deletion hw/core/qdev-properties-system.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ const PropertyInfo qdev_prop_granule_mode = {
const PropertyInfo qdev_prop_zero_page_detection = {
.name = "ZeroPageDetection",
.description = "zero_page_detection values, "
"none,legacy",
"none,legacy,multifd",
.enum_table = &ZeroPageDetection_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
Expand Down
1 change: 1 addition & 0 deletions migration/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ system_ss.add(files(
'migration.c',
'multifd.c',
'multifd-zlib.c',
'multifd-zero-page.c',
'ram-compress.c',
'options.c',
'postcopy-ram.c',
Expand Down
87 changes: 87 additions & 0 deletions migration/multifd-zero-page.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Multifd zero page detection implementation.
*
* Copyright (c) 2024 Bytedance Inc
*
* Authors:
* Hao Xiang <hao.xiang@bytedance.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/

#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "exec/ramblock.h"
#include "migration.h"
#include "multifd.h"
#include "options.h"
#include "ram.h"

static bool multifd_zero_page_enabled(void)
{
return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD;
}

static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
{
ram_addr_t temp;

if (a == b) {
return;
}

temp = pages_offset[a];
pages_offset[a] = pages_offset[b];
pages_offset[b] = temp;
}

/**
* multifd_send_zero_page_detect: Perform zero page detection on all pages.
*
* Sorts normal pages before zero pages in p->pages->offset and updates
* p->pages->normal_num.
*
* @param p A pointer to the send params.
*/
void multifd_send_zero_page_detect(MultiFDSendParams *p)
{
MultiFDPages_t *pages = p->pages;
RAMBlock *rb = pages->block;
int i = 0;
int j = pages->num - 1;

if (!multifd_zero_page_enabled()) {
pages->normal_num = pages->num;
return;
}

/*
* Sort the page offset array by moving all normal pages to
* the left and all zero pages to the right of the array.
*/
while (i <= j) {
uint64_t offset = pages->offset[i];

if (!buffer_is_zero(rb->host + offset, p->page_size)) {
i++;
continue;
}

swap_page_offset(pages->offset, i, j);
ram_release_page(rb->idstr, offset);
j--;
}

pages->normal_num = i;
}

void multifd_recv_zero_page_process(MultiFDRecvParams *p)
{
for (int i = 0; i < p->zero_num; i++) {
void *page = p->host + p->zero[i];
if (!buffer_is_zero(page, p->page_size)) {
memset(page, 0, p->page_size);
}
}
}
21 changes: 16 additions & 5 deletions migration/multifd-zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
int ret;
uint32_t i;

multifd_send_prepare_header(p);
if (!multifd_send_prepare_common(p)) {
goto out;
}

for (i = 0; i < pages->num; i++) {
for (i = 0; i < pages->normal_num; i++) {
uint32_t available = z->zbuff_len - out_size;
int flush = Z_NO_FLUSH;

if (i == pages->num - 1) {
if (i == pages->normal_num - 1) {
flush = Z_SYNC_FLUSH;
}

Expand Down Expand Up @@ -172,10 +174,10 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
p->iov[p->iovs_num].iov_len = out_size;
p->iovs_num++;
p->next_packet_size = out_size;
p->flags |= MULTIFD_FLAG_ZLIB;

out:
p->flags |= MULTIFD_FLAG_ZLIB;
multifd_send_fill_packet(p);

return 0;
}

Expand Down Expand Up @@ -261,6 +263,14 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
p->id, flags, MULTIFD_FLAG_ZLIB);
return -1;
}

multifd_recv_zero_page_process(p);

if (!p->normal_num) {
assert(in_size == 0);
return 0;
}

ret = qio_channel_read_all(p->c, (void *)z->zbuff, in_size, errp);

if (ret != 0) {
Expand Down Expand Up @@ -310,6 +320,7 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
p->id, out_size, expected_size);
return -1;
}

return 0;
}

Expand Down
20 changes: 15 additions & 5 deletions migration/multifd-zstd.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,18 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
int ret;
uint32_t i;

multifd_send_prepare_header(p);
if (!multifd_send_prepare_common(p)) {
goto out;
}

z->out.dst = z->zbuff;
z->out.size = z->zbuff_len;
z->out.pos = 0;

for (i = 0; i < pages->num; i++) {
for (i = 0; i < pages->normal_num; i++) {
ZSTD_EndDirective flush = ZSTD_e_continue;

if (i == pages->num - 1) {
if (i == pages->normal_num - 1) {
flush = ZSTD_e_flush;
}
z->in.src = p->pages->block->host + pages->offset[i];
Expand Down Expand Up @@ -161,10 +163,10 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
p->iov[p->iovs_num].iov_len = z->out.pos;
p->iovs_num++;
p->next_packet_size = z->out.pos;
p->flags |= MULTIFD_FLAG_ZSTD;

out:
p->flags |= MULTIFD_FLAG_ZSTD;
multifd_send_fill_packet(p);

return 0;
}

Expand Down Expand Up @@ -257,6 +259,14 @@ static int zstd_recv(MultiFDRecvParams *p, Error **errp)
p->id, flags, MULTIFD_FLAG_ZSTD);
return -1;
}

multifd_recv_zero_page_process(p);

if (!p->normal_num) {
assert(in_size == 0);
return 0;
}

ret = qio_channel_read_all(p->c, (void *)z->zbuff, in_size, errp);

if (ret != 0) {
Expand Down

0 comments on commit 303e6f5

Please sign in to comment.