1303e6f54SHao Xiang /*
2303e6f54SHao Xiang * Multifd zero page detection implementation.
3303e6f54SHao Xiang *
4303e6f54SHao Xiang * Copyright (c) 2024 Bytedance Inc
5303e6f54SHao Xiang *
6303e6f54SHao Xiang * Authors:
7303e6f54SHao Xiang * Hao Xiang <hao.xiang@bytedance.com>
8303e6f54SHao Xiang *
9303e6f54SHao Xiang * This work is licensed under the terms of the GNU GPL, version 2 or later.
10303e6f54SHao Xiang * See the COPYING file in the top-level directory.
11303e6f54SHao Xiang */
12303e6f54SHao Xiang
13303e6f54SHao Xiang #include "qemu/osdep.h"
14303e6f54SHao Xiang #include "qemu/cutils.h"
15303e6f54SHao Xiang #include "exec/ramblock.h"
16303e6f54SHao Xiang #include "migration.h"
17303e6f54SHao Xiang #include "multifd.h"
18303e6f54SHao Xiang #include "options.h"
19303e6f54SHao Xiang #include "ram.h"
20303e6f54SHao Xiang
multifd_zero_page_enabled(void)21303e6f54SHao Xiang static bool multifd_zero_page_enabled(void)
22303e6f54SHao Xiang {
23303e6f54SHao Xiang return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD;
24303e6f54SHao Xiang }
25303e6f54SHao Xiang
swap_page_offset(ram_addr_t * pages_offset,int a,int b)26303e6f54SHao Xiang static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
27303e6f54SHao Xiang {
28303e6f54SHao Xiang ram_addr_t temp;
29303e6f54SHao Xiang
30303e6f54SHao Xiang if (a == b) {
31303e6f54SHao Xiang return;
32303e6f54SHao Xiang }
33303e6f54SHao Xiang
34303e6f54SHao Xiang temp = pages_offset[a];
35303e6f54SHao Xiang pages_offset[a] = pages_offset[b];
36303e6f54SHao Xiang pages_offset[b] = temp;
37303e6f54SHao Xiang }
38303e6f54SHao Xiang
39303e6f54SHao Xiang /**
40303e6f54SHao Xiang * multifd_send_zero_page_detect: Perform zero page detection on all pages.
41303e6f54SHao Xiang *
42303e6f54SHao Xiang * Sorts normal pages before zero pages in p->pages->offset and updates
43303e6f54SHao Xiang * p->pages->normal_num.
44303e6f54SHao Xiang *
45303e6f54SHao Xiang * @param p A pointer to the send params.
46303e6f54SHao Xiang */
multifd_send_zero_page_detect(MultiFDSendParams * p)47303e6f54SHao Xiang void multifd_send_zero_page_detect(MultiFDSendParams *p)
48303e6f54SHao Xiang {
49303e6f54SHao Xiang MultiFDPages_t *pages = p->pages;
50303e6f54SHao Xiang RAMBlock *rb = pages->block;
51303e6f54SHao Xiang int i = 0;
52303e6f54SHao Xiang int j = pages->num - 1;
53303e6f54SHao Xiang
54303e6f54SHao Xiang if (!multifd_zero_page_enabled()) {
55303e6f54SHao Xiang pages->normal_num = pages->num;
56303e6f54SHao Xiang return;
57303e6f54SHao Xiang }
58303e6f54SHao Xiang
59303e6f54SHao Xiang /*
60303e6f54SHao Xiang * Sort the page offset array by moving all normal pages to
61303e6f54SHao Xiang * the left and all zero pages to the right of the array.
62303e6f54SHao Xiang */
63303e6f54SHao Xiang while (i <= j) {
64303e6f54SHao Xiang uint64_t offset = pages->offset[i];
65303e6f54SHao Xiang
66303e6f54SHao Xiang if (!buffer_is_zero(rb->host + offset, p->page_size)) {
67303e6f54SHao Xiang i++;
68303e6f54SHao Xiang continue;
69303e6f54SHao Xiang }
70303e6f54SHao Xiang
71303e6f54SHao Xiang swap_page_offset(pages->offset, i, j);
72303e6f54SHao Xiang ram_release_page(rb->idstr, offset);
73303e6f54SHao Xiang j--;
74303e6f54SHao Xiang }
75303e6f54SHao Xiang
76303e6f54SHao Xiang pages->normal_num = i;
77303e6f54SHao Xiang }
78303e6f54SHao Xiang
multifd_recv_zero_page_process(MultiFDRecvParams * p)79303e6f54SHao Xiang void multifd_recv_zero_page_process(MultiFDRecvParams *p)
80303e6f54SHao Xiang {
81303e6f54SHao Xiang for (int i = 0; i < p->zero_num; i++) {
82303e6f54SHao Xiang void *page = p->host + p->zero[i];
83*5ef7e26bSYuan Liu if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) {
84303e6f54SHao Xiang memset(page, 0, p->page_size);
85*5ef7e26bSYuan Liu } else {
86*5ef7e26bSYuan Liu ramblock_recv_bitmap_set_offset(p->block, p->zero[i]);
87303e6f54SHao Xiang }
88303e6f54SHao Xiang }
89303e6f54SHao Xiang }
90