1 /*
2 * Multifd zero page detection implementation.
3 *
4 * Copyright (c) 2024 Bytedance Inc
5 *
6 * Authors:
7 * Hao Xiang <hao.xiang@bytedance.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13 #include "qemu/osdep.h"
14 #include "qemu/cutils.h"
15 #include "exec/ramblock.h"
16 #include "migration.h"
17 #include "multifd.h"
18 #include "options.h"
19 #include "ram.h"
20
multifd_zero_page_enabled(void)21 static bool multifd_zero_page_enabled(void)
22 {
23 return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD;
24 }
25
swap_page_offset(ram_addr_t * pages_offset,int a,int b)26 static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
27 {
28 ram_addr_t temp;
29
30 if (a == b) {
31 return;
32 }
33
34 temp = pages_offset[a];
35 pages_offset[a] = pages_offset[b];
36 pages_offset[b] = temp;
37 }
38
39 /**
40 * multifd_send_zero_page_detect: Perform zero page detection on all pages.
41 *
42 * Sorts normal pages before zero pages in p->pages->offset and updates
43 * p->pages->normal_num.
44 *
45 * @param p A pointer to the send params.
46 */
multifd_send_zero_page_detect(MultiFDSendParams * p)47 void multifd_send_zero_page_detect(MultiFDSendParams *p)
48 {
49 MultiFDPages_t *pages = p->pages;
50 RAMBlock *rb = pages->block;
51 int i = 0;
52 int j = pages->num - 1;
53
54 if (!multifd_zero_page_enabled()) {
55 pages->normal_num = pages->num;
56 return;
57 }
58
59 /*
60 * Sort the page offset array by moving all normal pages to
61 * the left and all zero pages to the right of the array.
62 */
63 while (i <= j) {
64 uint64_t offset = pages->offset[i];
65
66 if (!buffer_is_zero(rb->host + offset, p->page_size)) {
67 i++;
68 continue;
69 }
70
71 swap_page_offset(pages->offset, i, j);
72 ram_release_page(rb->idstr, offset);
73 j--;
74 }
75
76 pages->normal_num = i;
77 }
78
multifd_recv_zero_page_process(MultiFDRecvParams * p)79 void multifd_recv_zero_page_process(MultiFDRecvParams *p)
80 {
81 for (int i = 0; i < p->zero_num; i++) {
82 void *page = p->host + p->zero[i];
83 if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) {
84 memset(page, 0, p->page_size);
85 } else {
86 ramblock_recv_bitmap_set_offset(p->block, p->zero[i]);
87 }
88 }
89 }
90