multifd-zero-page.c 2.3 KB

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