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