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 "migration-stats.h" 18 #include "multifd.h" 19 #include "options.h" 20 #include "ram.h" 21 22 static bool multifd_zero_page_enabled(void) 23 { 24 return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD; 25 } 26 27 static void swap_page_offset(ram_addr_t *pages_offset, int a, int b) 28 { 29 ram_addr_t temp; 30 31 if (a == b) { 32 return; 33 } 34 35 temp = pages_offset[a]; 36 pages_offset[a] = pages_offset[b]; 37 pages_offset[b] = temp; 38 } 39 40 /** 41 * multifd_send_zero_page_detect: Perform zero page detection on all pages. 42 * 43 * Sorts normal pages before zero pages in p->pages->offset and updates 44 * p->pages->normal_num. 45 * 46 * @param p A pointer to the send params. 47 */ 48 void multifd_send_zero_page_detect(MultiFDSendParams *p) 49 { 50 MultiFDPages_t *pages = &p->data->u.ram; 51 RAMBlock *rb = pages->block; 52 int i = 0; 53 int j = pages->num - 1; 54 55 if (!multifd_zero_page_enabled()) { 56 pages->normal_num = pages->num; 57 goto out; 58 } 59 60 /* 61 * Sort the page offset array by moving all normal pages to 62 * the left and all zero pages to the right of the array. 63 */ 64 while (i <= j) { 65 uint64_t offset = pages->offset[i]; 66 67 if (!buffer_is_zero(rb->host + offset, multifd_ram_page_size())) { 68 i++; 69 continue; 70 } 71 72 swap_page_offset(pages->offset, i, j); 73 ram_release_page(rb->idstr, offset); 74 j--; 75 } 76 77 pages->normal_num = i; 78 79 out: 80 stat64_add(&mig_stats.normal_pages, pages->normal_num); 81 stat64_add(&mig_stats.zero_pages, pages->num - pages->normal_num); 82 } 83 84 void multifd_recv_zero_page_process(MultiFDRecvParams *p) 85 { 86 for (int i = 0; i < p->zero_num; i++) { 87 void *page = p->host + p->zero[i]; 88 if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) { 89 memset(page, 0, multifd_ram_page_size()); 90 } else { 91 ramblock_recv_bitmap_set_offset(p->block, p->zero[i]); 92 } 93 } 94 } 95