qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Introduce multifd zero page checking.
@ 2024-02-26 19:56 Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection Hao Xiang
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

v3 update:
* Change "zero" to "zero-pages" and use type size for "zero-bytes".
* Fixed ZeroPageDetection interface description.
* Move zero page unit tests to its own path.
* Removed some asserts.
* Added backward compatibility support for migration 9.0 -> 8.2.
* Removed fields "zero" and "normal" page address arrays from v2. Now
multifd_zero_page_check_send sorts normal/zero pages in the "offset" array.

v2 update:
* Implement zero-page-detection switch with enumeration "legacy",
"none" and "multifd".
* Move normal/zero pages from MultiFDSendParams to MultiFDPages_t.
* Add zeros and zero_bytes accounting.

This patchset is based on Juan Quintela's old series here
https://lore.kernel.org/all/20220802063907.18882-1-quintela@redhat.com/

In the multifd live migration model, there is a single migration main
thread scanning the page map, queuing the pages to multiple multifd
sender threads. The migration main thread runs zero page checking on
every page before queuing the page to the sender threads. Zero page
checking is a CPU intensive task and hence having a single thread doing
all that doesn't scale well. This change introduces a new function
to run the zero page checking on the multifd sender threads. This
patchset also lays the ground work for future changes to offload zero
page checking task to accelerator hardwares.

Use two Intel 4th generation Xeon servers for testing.

Architecture:        x86_64
CPU(s):              192
Thread(s) per core:  2
Core(s) per socket:  48
Socket(s):           2
NUMA node(s):        2
Vendor ID:           GenuineIntel
CPU family:          6
Model:               143
Model name:          Intel(R) Xeon(R) Platinum 8457C
Stepping:            8
CPU MHz:             2538.624
CPU max MHz:         3800.0000
CPU min MHz:         800.0000

Perform multifd live migration with below setup:
1. VM has 100GB memory. All pages in the VM are zero pages.
2. Use tcp socket for live migration.
3. Use 4 multifd channels and zero page checking on migration main thread.
4. Use 1/2/4 multifd channels and zero page checking on multifd sender
threads.
5. Record migration total time from sender QEMU console's "info migrate"
command.

+------------------------------------+
|zero-page-checking | total-time(ms) |
+------------------------------------+
|main-thread        | 9629           |
+------------------------------------+
|multifd-1-threads  | 6182           |
+------------------------------------+
|multifd-2-threads  | 4643           |
+------------------------------------+
|multifd-4-threads  | 4143           |
+------------------------------------+

Apply this patchset on top of commit
dd88d696ccecc0f3018568f8e281d3d526041e6f

Hao Xiang (7):
  migration/multifd: Add new migration option zero-page-detection.
  migration/multifd: Implement zero page transmission on the multifd
    thread.
  migration/multifd: Implement ram_save_target_page_multifd to handle
    multifd version of MigrationOps::ram_save_target_page.
  migration/multifd: Enable multifd zero page checking by default.
  migration/multifd: Add new migration test cases for legacy zero page
    checking.
  migration/multifd: Add zero pages and zero bytes counter to migration
    status interface.
  Update maintainer contact for migration multifd zero page checking
    acceleration.

 MAINTAINERS                         |  5 ++
 hw/core/machine.c                   |  4 +-
 hw/core/qdev-properties-system.c    | 10 ++++
 include/hw/qdev-properties-system.h |  4 ++
 migration/meson.build               |  1 +
 migration/migration-hmp-cmds.c      | 13 +++++
 migration/migration.c               |  2 +
 migration/multifd-zero-page.c       | 78 +++++++++++++++++++++++++++
 migration/multifd-zlib.c            | 21 ++++++--
 migration/multifd-zstd.c            | 20 +++++--
 migration/multifd.c                 | 83 ++++++++++++++++++++++++-----
 migration/multifd.h                 | 24 ++++++++-
 migration/options.c                 | 21 ++++++++
 migration/options.h                 |  1 +
 migration/ram.c                     | 40 ++++++++++----
 migration/trace-events              |  8 +--
 qapi/migration.json                 | 48 +++++++++++++++--
 tests/migration/guestperf/engine.py |  2 +
 tests/qtest/migration-test.c        | 52 ++++++++++++++++++
 19 files changed, 393 insertions(+), 44 deletions(-)
 create mode 100644 migration/multifd-zero-page.c

-- 
2.30.2



^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-28  9:43   ` Markus Armbruster
  2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

This new parameter controls where the zero page checking is running.
1. If this parameter is set to 'legacy', zero page checking is
done in the migration main thread.
2. If this parameter is set to 'none', zero page checking is disabled.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 hw/core/qdev-properties-system.c    | 10 ++++++++++
 include/hw/qdev-properties-system.h |  4 ++++
 migration/migration-hmp-cmds.c      |  9 +++++++++
 migration/options.c                 | 21 ++++++++++++++++++++
 migration/options.h                 |  1 +
 migration/ram.c                     |  4 ++++
 qapi/migration.json                 | 30 ++++++++++++++++++++++++++---
 7 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 1a396521d5..228e685f52 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -679,6 +679,16 @@ const PropertyInfo qdev_prop_mig_mode = {
     .set_default_value = qdev_propinfo_set_default_value_enum,
 };
 
+const PropertyInfo qdev_prop_zero_page_detection = {
+    .name = "ZeroPageDetection",
+    .description = "zero_page_detection values, "
+                   "none,legacy",
+    .enum_table = &ZeroPageDetection_lookup,
+    .get = qdev_propinfo_get_enum,
+    .set = qdev_propinfo_set_enum,
+    .set_default_value = qdev_propinfo_set_default_value_enum,
+};
+
 /* --- Reserved Region --- */
 
 /*
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 06c359c190..839b170235 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -8,6 +8,7 @@ extern const PropertyInfo qdev_prop_macaddr;
 extern const PropertyInfo qdev_prop_reserved_region;
 extern const PropertyInfo qdev_prop_multifd_compression;
 extern const PropertyInfo qdev_prop_mig_mode;
+extern const PropertyInfo qdev_prop_zero_page_detection;
 extern const PropertyInfo qdev_prop_losttickpolicy;
 extern const PropertyInfo qdev_prop_blockdev_on_error;
 extern const PropertyInfo qdev_prop_bios_chs_trans;
@@ -47,6 +48,9 @@ extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
 #define DEFINE_PROP_MIG_MODE(_n, _s, _f, _d) \
     DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_mig_mode, \
                        MigMode)
+#define DEFINE_PROP_ZERO_PAGE_DETECTION(_n, _s, _f, _d) \
+    DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_zero_page_detection, \
+                       ZeroPageDetection)
 #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
     DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
                         LostTickPolicy)
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 99b49df5dd..7e96ae6ffd 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -344,6 +344,11 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
         monitor_printf(mon, "%s: %s\n",
             MigrationParameter_str(MIGRATION_PARAMETER_MULTIFD_COMPRESSION),
             MultiFDCompression_str(params->multifd_compression));
+        assert(params->has_zero_page_detection);
+        monitor_printf(mon, "%s: %s\n",
+            MigrationParameter_str(MIGRATION_PARAMETER_ZERO_PAGE_DETECTION),
+            qapi_enum_lookup(&ZeroPageDetection_lookup,
+                params->zero_page_detection));
         monitor_printf(mon, "%s: %" PRIu64 " bytes\n",
             MigrationParameter_str(MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE),
             params->xbzrle_cache_size);
@@ -634,6 +639,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
         p->has_multifd_zstd_level = true;
         visit_type_uint8(v, param, &p->multifd_zstd_level, &err);
         break;
+    case MIGRATION_PARAMETER_ZERO_PAGE_DETECTION:
+        p->has_zero_page_detection = true;
+        visit_type_ZeroPageDetection(v, param, &p->zero_page_detection, &err);
+        break;
     case MIGRATION_PARAMETER_XBZRLE_CACHE_SIZE:
         p->has_xbzrle_cache_size = true;
         if (!visit_type_size(v, param, &cache_size, &err)) {
diff --git a/migration/options.c b/migration/options.c
index 3e3e0b93b4..3c603391b0 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -179,6 +179,9 @@ Property migration_properties[] = {
     DEFINE_PROP_MIG_MODE("mode", MigrationState,
                       parameters.mode,
                       MIG_MODE_NORMAL),
+    DEFINE_PROP_ZERO_PAGE_DETECTION("zero-page-detection", MigrationState,
+                       parameters.zero_page_detection,
+                       ZERO_PAGE_DETECTION_LEGACY),
 
     /* Migration capabilities */
     DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
@@ -903,6 +906,13 @@ uint64_t migrate_xbzrle_cache_size(void)
     return s->parameters.xbzrle_cache_size;
 }
 
+ZeroPageDetection migrate_zero_page_detection(void)
+{
+    MigrationState *s = migrate_get_current();
+
+    return s->parameters.zero_page_detection;
+}
+
 /* parameter setters */
 
 void migrate_set_block_incremental(bool value)
@@ -1013,6 +1023,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
     params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit;
     params->has_mode = true;
     params->mode = s->parameters.mode;
+    params->has_zero_page_detection = true;
+    params->zero_page_detection = s->parameters.zero_page_detection;
 
     return params;
 }
@@ -1049,6 +1061,7 @@ void migrate_params_init(MigrationParameters *params)
     params->has_x_vcpu_dirty_limit_period = true;
     params->has_vcpu_dirty_limit = true;
     params->has_mode = true;
+    params->has_zero_page_detection = true;
 }
 
 /*
@@ -1350,6 +1363,10 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
     if (params->has_mode) {
         dest->mode = params->mode;
     }
+
+    if (params->has_zero_page_detection) {
+        dest->zero_page_detection = params->zero_page_detection;
+    }
 }
 
 static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@@ -1494,6 +1511,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
     if (params->has_mode) {
         s->parameters.mode = params->mode;
     }
+
+    if (params->has_zero_page_detection) {
+        s->parameters.zero_page_detection = params->zero_page_detection;
+    }
 }
 
 void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
diff --git a/migration/options.h b/migration/options.h
index 246c160aee..b7c4fb3861 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -93,6 +93,7 @@ const char *migrate_tls_authz(void);
 const char *migrate_tls_creds(void);
 const char *migrate_tls_hostname(void);
 uint64_t migrate_xbzrle_cache_size(void);
+ZeroPageDetection migrate_zero_page_detection(void);
 
 /* parameters setters */
 
diff --git a/migration/ram.c b/migration/ram.c
index 4649a81204..67035fb4b1 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1123,6 +1123,10 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss,
     QEMUFile *file = pss->pss_channel;
     int len = 0;
 
+    if (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_NONE) {
+        return 0;
+    }
+
     if (!buffer_is_zero(p, TARGET_PAGE_SIZE)) {
         return 0;
     }
diff --git a/qapi/migration.json b/qapi/migration.json
index 5a565d9b8d..1e66272f8f 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -653,6 +653,18 @@
 { 'enum': 'MigMode',
   'data': [ 'normal', 'cpr-reboot' ] }
 
+##
+# @ZeroPageDetection:
+#
+# @none: Do not perform zero page checking.
+#
+# @legacy: Perform zero page checking from main migration thread.
+#
+# Since: 9.0
+##
+{ 'enum': 'ZeroPageDetection',
+  'data': [ 'none', 'legacy' ] }
+
 ##
 # @BitmapMigrationBitmapAliasTransform:
 #
@@ -874,6 +886,9 @@
 # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
 #        (Since 8.2)
 #
+# @zero-page-detection: Whether and how to detect zero pages. More details
+#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -907,7 +922,8 @@
            'block-bitmap-mapping',
            { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
            'vcpu-dirty-limit',
-           'mode'] }
+           'mode',
+           'zero-page-detection'] }
 
 ##
 # @MigrateSetParameters:
@@ -1066,6 +1082,9 @@
 # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
 #        (Since 8.2)
 #
+# @zero-page-detection: Whether and how to detect zero pages. More details
+#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -1119,7 +1138,8 @@
             '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
                                             'features': [ 'unstable' ] },
             '*vcpu-dirty-limit': 'uint64',
-            '*mode': 'MigMode'} }
+            '*mode': 'MigMode',
+            '*zero-page-detection': 'ZeroPageDetection'} }
 
 ##
 # @migrate-set-parameters:
@@ -1294,6 +1314,9 @@
 # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
 #        (Since 8.2)
 #
+# @zero-page-detection: Whether and how to detect zero pages. More details
+#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -1344,7 +1367,8 @@
             '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
                                             'features': [ 'unstable' ] },
             '*vcpu-dirty-limit': 'uint64',
-            '*mode': 'MigMode'} }
+            '*mode': 'MigMode',
+            '*zero-page-detection': 'ZeroPageDetection'} }
 
 ##
 # @query-migrate-parameters:
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-28  9:45   ` Markus Armbruster
                     ` (2 more replies)
  2024-02-26 19:56 ` [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page Hao Xiang
                   ` (5 subsequent siblings)
  7 siblings, 3 replies; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

1. Add zero_pages field in MultiFDPacket_t.
2. Implements the zero page detection and handling on the multifd
threads for non-compression, zlib and zstd compression backends.
3. Added a new value 'multifd' in ZeroPageDetection enumeration.
4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
5. Adds zero page counters and updates multifd send/receive tracing
format to track the newly added counters.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 hw/core/machine.c                |  4 +-
 hw/core/qdev-properties-system.c |  2 +-
 migration/meson.build            |  1 +
 migration/multifd-zero-page.c    | 78 ++++++++++++++++++++++++++++++
 migration/multifd-zlib.c         | 21 ++++++--
 migration/multifd-zstd.c         | 20 ++++++--
 migration/multifd.c              | 83 +++++++++++++++++++++++++++-----
 migration/multifd.h              | 24 ++++++++-
 migration/ram.c                  |  1 -
 migration/trace-events           |  8 +--
 qapi/migration.json              |  5 +-
 11 files changed, 214 insertions(+), 33 deletions(-)
 create mode 100644 migration/multifd-zero-page.c

diff --git a/hw/core/machine.c b/hw/core/machine.c
index fb5afdcae4..746da219a4 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -32,7 +32,9 @@
 #include "hw/virtio/virtio-net.h"
 #include "audio/audio.h"
 
-GlobalProperty hw_compat_8_2[] = {};
+GlobalProperty hw_compat_8_2[] = {
+    { "migration", "zero-page-detection", "legacy"},
+};
 const size_t hw_compat_8_2_len = G_N_ELEMENTS(hw_compat_8_2);
 
 GlobalProperty hw_compat_8_1[] = {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 228e685f52..6e6f68ae1b 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -682,7 +682,7 @@ const PropertyInfo qdev_prop_mig_mode = {
 const PropertyInfo qdev_prop_zero_page_detection = {
     .name = "ZeroPageDetection",
     .description = "zero_page_detection values, "
-                   "none,legacy",
+                   "none,legacy,multifd",
     .enum_table = &ZeroPageDetection_lookup,
     .get = qdev_propinfo_get_enum,
     .set = qdev_propinfo_set_enum,
diff --git a/migration/meson.build b/migration/meson.build
index 92b1cc4297..1eeb915ff6 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -22,6 +22,7 @@ system_ss.add(files(
   'migration.c',
   'multifd.c',
   'multifd-zlib.c',
+  'multifd-zero-page.c',
   'ram-compress.c',
   'options.c',
   'postcopy-ram.c',
diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
new file mode 100644
index 0000000000..1650c41b26
--- /dev/null
+++ b/migration/multifd-zero-page.c
@@ -0,0 +1,78 @@
+/*
+ * Multifd zero page detection implementation.
+ *
+ * Copyright (c) 2024 Bytedance Inc
+ *
+ * Authors:
+ *  Hao Xiang <hao.xiang@bytedance.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "exec/ramblock.h"
+#include "migration.h"
+#include "multifd.h"
+#include "options.h"
+#include "ram.h"
+
+static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
+{
+    ram_addr_t temp;
+
+    if (a == b) {
+        return;
+    }
+
+    temp = pages_offset[a];
+    pages_offset[a] = pages_offset[b];
+    pages_offset[b] = temp;
+}
+
+/**
+ * multifd_zero_page_check_send: Perform zero page detection on all pages.
+ *
+ * Sort the page offset array by moving all normal pages to
+ * the left and all zero pages to the right of the array.
+ *
+ * @param p A pointer to the send params.
+ */
+void multifd_zero_page_check_send(MultiFDSendParams *p)
+{
+    /*
+     * QEMU older than 9.0 don't understand zero page
+     * on multifd channel. This switch is required to
+     * maintain backward compatibility.
+     */
+    bool use_multifd_zero_page =
+        (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD);
+    MultiFDPages_t *pages = p->pages;
+    RAMBlock *rb = pages->block;
+    int index_normal = 0;
+    int index_zero = pages->num - 1;
+
+    while (index_normal <= index_zero) {
+        uint64_t offset = pages->offset[index_normal];
+        if (use_multifd_zero_page &&
+            buffer_is_zero(rb->host + offset, p->page_size)) {
+            swap_page_offset(pages->offset, index_normal, index_zero);
+            index_zero--;
+            ram_release_page(rb->idstr, offset);
+        } else {
+            index_normal++;
+            pages->normal_num++;
+        }
+    }
+}
+
+void multifd_zero_page_check_recv(MultiFDRecvParams *p)
+{
+    for (int i = 0; i < p->zero_num; i++) {
+        void *page = p->host + p->zero[i];
+        if (!buffer_is_zero(page, p->page_size)) {
+            memset(page, 0, p->page_size);
+        }
+    }
+}
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index 012e3bdea1..a8b26bc5e4 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -123,13 +123,15 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
     int ret;
     uint32_t i;
 
-    multifd_send_prepare_header(p);
+    if (!multifd_send_prepare_common(p)) {
+        goto out;
+    }
 
-    for (i = 0; i < pages->num; i++) {
+    for (i = 0; i < pages->normal_num; i++) {
         uint32_t available = z->zbuff_len - out_size;
         int flush = Z_NO_FLUSH;
 
-        if (i == pages->num - 1) {
+        if (i == pages->normal_num - 1) {
             flush = Z_SYNC_FLUSH;
         }
 
@@ -172,10 +174,10 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
     p->iov[p->iovs_num].iov_len = out_size;
     p->iovs_num++;
     p->next_packet_size = out_size;
-    p->flags |= MULTIFD_FLAG_ZLIB;
 
+out:
+    p->flags |= MULTIFD_FLAG_ZLIB;
     multifd_send_fill_packet(p);
-
     return 0;
 }
 
@@ -261,6 +263,14 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
                    p->id, flags, MULTIFD_FLAG_ZLIB);
         return -1;
     }
+
+    multifd_zero_page_check_recv(p);
+
+    if (!p->normal_num) {
+        assert(in_size == 0);
+        return 0;
+    }
+
     ret = qio_channel_read_all(p->c, (void *)z->zbuff, in_size, errp);
 
     if (ret != 0) {
@@ -310,6 +320,7 @@ static int zlib_recv_pages(MultiFDRecvParams *p, Error **errp)
                    p->id, out_size, expected_size);
         return -1;
     }
+
     return 0;
 }
 
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index dc8fe43e94..7768040124 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -118,16 +118,18 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
     int ret;
     uint32_t i;
 
-    multifd_send_prepare_header(p);
+    if (!multifd_send_prepare_common(p)) {
+        goto out;
+    }
 
     z->out.dst = z->zbuff;
     z->out.size = z->zbuff_len;
     z->out.pos = 0;
 
-    for (i = 0; i < pages->num; i++) {
+    for (i = 0; i < pages->normal_num; i++) {
         ZSTD_EndDirective flush = ZSTD_e_continue;
 
-        if (i == pages->num - 1) {
+        if (i == pages->normal_num - 1) {
             flush = ZSTD_e_flush;
         }
         z->in.src = p->pages->block->host + pages->offset[i];
@@ -161,10 +163,10 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
     p->iov[p->iovs_num].iov_len = z->out.pos;
     p->iovs_num++;
     p->next_packet_size = z->out.pos;
-    p->flags |= MULTIFD_FLAG_ZSTD;
 
+out:
+    p->flags |= MULTIFD_FLAG_ZSTD;
     multifd_send_fill_packet(p);
-
     return 0;
 }
 
@@ -257,6 +259,14 @@ static int zstd_recv_pages(MultiFDRecvParams *p, Error **errp)
                    p->id, flags, MULTIFD_FLAG_ZSTD);
         return -1;
     }
+
+    multifd_zero_page_check_recv(p);
+
+    if (!p->normal_num) {
+        assert(in_size == 0);
+        return 0;
+    }
+
     ret = qio_channel_read_all(p->c, (void *)z->zbuff, in_size, errp);
 
     if (ret != 0) {
diff --git a/migration/multifd.c b/migration/multifd.c
index adfe8c9a0a..eace0278af 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -11,6 +11,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/cutils.h"
 #include "qemu/rcu.h"
 #include "exec/target_page.h"
 #include "sysemu/sysemu.h"
@@ -126,6 +127,8 @@ static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
     MultiFDPages_t *pages = p->pages;
     int ret;
 
+    multifd_zero_page_check_send(p);
+
     if (!use_zero_copy_send) {
         /*
          * Only !zerocopy needs the header in IOV; zerocopy will
@@ -134,13 +137,13 @@ static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
         multifd_send_prepare_header(p);
     }
 
-    for (int i = 0; i < pages->num; i++) {
+    for (int i = 0; i < pages->normal_num; i++) {
         p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
         p->iov[p->iovs_num].iov_len = p->page_size;
         p->iovs_num++;
     }
 
-    p->next_packet_size = pages->num * p->page_size;
+    p->next_packet_size = pages->normal_num * p->page_size;
     p->flags |= MULTIFD_FLAG_NOCOMP;
 
     multifd_send_fill_packet(p);
@@ -202,6 +205,13 @@ static int nocomp_recv_pages(MultiFDRecvParams *p, Error **errp)
                    p->id, flags, MULTIFD_FLAG_NOCOMP);
         return -1;
     }
+
+    multifd_zero_page_check_recv(p);
+
+    if (!p->normal_num) {
+        return 0;
+    }
+
     for (int i = 0; i < p->normal_num; i++) {
         p->iov[i].iov_base = p->host + p->normal[i];
         p->iov[i].iov_len = p->page_size;
@@ -236,6 +246,7 @@ static void multifd_pages_reset(MultiFDPages_t *pages)
      * overwritten later when reused.
      */
     pages->num = 0;
+    pages->normal_num = 0;
     pages->block = NULL;
 }
 
@@ -327,11 +338,13 @@ void multifd_send_fill_packet(MultiFDSendParams *p)
     MultiFDPacket_t *packet = p->packet;
     MultiFDPages_t *pages = p->pages;
     uint64_t packet_num;
+    uint32_t zero_num = pages->num - pages->normal_num;
     int i;
 
     packet->flags = cpu_to_be32(p->flags);
     packet->pages_alloc = cpu_to_be32(p->pages->allocated);
-    packet->normal_pages = cpu_to_be32(pages->num);
+    packet->normal_pages = cpu_to_be32(pages->normal_num);
+    packet->zero_pages = cpu_to_be32(zero_num);
     packet->next_packet_size = cpu_to_be32(p->next_packet_size);
 
     packet_num = qatomic_fetch_inc(&multifd_send_state->packet_num);
@@ -349,10 +362,11 @@ void multifd_send_fill_packet(MultiFDSendParams *p)
     }
 
     p->packets_sent++;
-    p->total_normal_pages += pages->num;
+    p->total_normal_pages += pages->normal_num;
+    p->total_zero_pages += zero_num;
 
-    trace_multifd_send(p->id, packet_num, pages->num, p->flags,
-                       p->next_packet_size);
+    trace_multifd_send(p->id, packet_num, pages->normal_num, zero_num,
+                       p->flags, p->next_packet_size);
 }
 
 static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
@@ -393,20 +407,29 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
     p->normal_num = be32_to_cpu(packet->normal_pages);
     if (p->normal_num > packet->pages_alloc) {
         error_setg(errp, "multifd: received packet "
-                   "with %u pages and expected maximum pages are %u",
+                   "with %u normal pages and expected maximum pages are %u",
                    p->normal_num, packet->pages_alloc) ;
         return -1;
     }
 
+    p->zero_num = be32_to_cpu(packet->zero_pages);
+    if (p->zero_num > packet->pages_alloc - p->normal_num) {
+        error_setg(errp, "multifd: received packet "
+                   "with %u zero pages and expected maximum zero pages are %u",
+                   p->zero_num, packet->pages_alloc - p->normal_num) ;
+        return -1;
+    }
+
     p->next_packet_size = be32_to_cpu(packet->next_packet_size);
     p->packet_num = be64_to_cpu(packet->packet_num);
     p->packets_recved++;
     p->total_normal_pages += p->normal_num;
+    p->total_zero_pages += p->zero_num;
 
-    trace_multifd_recv(p->id, p->packet_num, p->normal_num, p->flags,
-                       p->next_packet_size);
+    trace_multifd_recv(p->id, p->packet_num, p->normal_num, p->zero_num,
+                       p->flags, p->next_packet_size);
 
-    if (p->normal_num == 0) {
+    if (p->normal_num == 0 && p->zero_num == 0) {
         return 0;
     }
 
@@ -432,6 +455,18 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
         p->normal[i] = offset;
     }
 
+    for (i = 0; i < p->zero_num; i++) {
+        uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
+
+        if (offset > (p->block->used_length - p->page_size)) {
+            error_setg(errp, "multifd: offset too long %" PRIu64
+                       " (max " RAM_ADDR_FMT ")",
+                       offset, p->block->used_length);
+            return -1;
+        }
+        p->zero[i] = offset;
+    }
+
     return 0;
 }
 
@@ -823,6 +858,8 @@ static void *multifd_send_thread(void *opaque)
 
             stat64_add(&mig_stats.multifd_bytes,
                        p->next_packet_size + p->packet_len);
+            stat64_add(&mig_stats.normal_pages, pages->normal_num);
+            stat64_add(&mig_stats.zero_pages, pages->num - pages->normal_num);
 
             multifd_pages_reset(p->pages);
             p->next_packet_size = 0;
@@ -866,7 +903,8 @@ out:
 
     rcu_unregister_thread();
     migration_threads_remove(thread);
-    trace_multifd_send_thread_end(p->id, p->packets_sent, p->total_normal_pages);
+    trace_multifd_send_thread_end(p->id, p->packets_sent, p->total_normal_pages,
+                                  p->total_zero_pages);
 
     return NULL;
 }
@@ -1132,6 +1170,8 @@ static void multifd_recv_cleanup_channel(MultiFDRecvParams *p)
     p->iov = NULL;
     g_free(p->normal);
     p->normal = NULL;
+    g_free(p->zero);
+    p->zero = NULL;
     multifd_recv_state->ops->recv_cleanup(p);
 }
 
@@ -1232,7 +1272,7 @@ static void *multifd_recv_thread(void *opaque)
         p->flags &= ~MULTIFD_FLAG_SYNC;
         qemu_mutex_unlock(&p->mutex);
 
-        if (p->normal_num) {
+        if (p->normal_num + p->zero_num) {
             ret = multifd_recv_state->ops->recv_pages(p, &local_err);
             if (ret != 0) {
                 break;
@@ -1251,7 +1291,9 @@ static void *multifd_recv_thread(void *opaque)
     }
 
     rcu_unregister_thread();
-    trace_multifd_recv_thread_end(p->id, p->packets_recved, p->total_normal_pages);
+    trace_multifd_recv_thread_end(p->id, p->packets_recved,
+                                  p->total_normal_pages,
+                                  p->total_zero_pages);
 
     return NULL;
 }
@@ -1290,6 +1332,7 @@ int multifd_recv_setup(Error **errp)
         p->name = g_strdup_printf("multifdrecv_%d", i);
         p->iov = g_new0(struct iovec, page_count);
         p->normal = g_new0(ram_addr_t, page_count);
+        p->zero = g_new0(ram_addr_t, page_count);
         p->page_count = page_count;
         p->page_size = qemu_target_page_size();
     }
@@ -1359,3 +1402,17 @@ void multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
                        QEMU_THREAD_JOINABLE);
     qatomic_inc(&multifd_recv_state->count);
 }
+
+bool multifd_send_prepare_common(MultiFDSendParams *p)
+{
+    multifd_zero_page_check_send(p);
+
+    if (!p->pages->normal_num) {
+        p->next_packet_size = 0;
+        return false;
+    }
+
+    multifd_send_prepare_header(p);
+
+    return true;
+}
diff --git a/migration/multifd.h b/migration/multifd.h
index 8a1cad0996..e18ffdf7cc 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -48,14 +48,24 @@ typedef struct {
     /* size of the next packet that contains pages */
     uint32_t next_packet_size;
     uint64_t packet_num;
-    uint64_t unused[4];    /* Reserved for future use */
+    /* zero pages */
+    uint32_t zero_pages;
+    uint32_t unused32[1];    /* Reserved for future use */
+    uint64_t unused64[3];    /* Reserved for future use */
     char ramblock[256];
+    /*
+     * This array contains the pointers to:
+     *  - normal pages (initial normal_pages entries)
+     *  - zero pages (following zero_pages entries)
+     */
     uint64_t offset[];
 } __attribute__((packed)) MultiFDPacket_t;
 
 typedef struct {
     /* number of used pages */
     uint32_t num;
+    /* number of normal pages */
+    uint32_t normal_num;
     /* number of allocated pages */
     uint32_t allocated;
     /* offset of each page */
@@ -124,6 +134,8 @@ typedef struct {
     uint64_t packets_sent;
     /* non zero pages sent through this channel */
     uint64_t total_normal_pages;
+    /* zero pages sent through this channel */
+    uint64_t total_zero_pages;
     /* buffers to send */
     struct iovec *iov;
     /* number of iovs used */
@@ -178,12 +190,18 @@ typedef struct {
     uint8_t *host;
     /* non zero pages recv through this channel */
     uint64_t total_normal_pages;
+    /* zero pages recv through this channel */
+    uint64_t total_zero_pages;
     /* buffers to recv */
     struct iovec *iov;
     /* Pages that are not zero */
     ram_addr_t *normal;
     /* num of non zero pages */
     uint32_t normal_num;
+    /* Pages that are zero */
+    ram_addr_t *zero;
+    /* num of zero pages */
+    uint32_t zero_num;
     /* used for de-compression methods */
     void *data;
 } MultiFDRecvParams;
@@ -205,6 +223,9 @@ typedef struct {
 
 void multifd_register_ops(int method, MultiFDMethods *ops);
 void multifd_send_fill_packet(MultiFDSendParams *p);
+bool multifd_send_prepare_common(MultiFDSendParams *p);
+void multifd_zero_page_check_send(MultiFDSendParams *p);
+void multifd_zero_page_check_recv(MultiFDRecvParams *p);
 
 static inline void multifd_send_prepare_header(MultiFDSendParams *p)
 {
@@ -213,5 +234,4 @@ static inline void multifd_send_prepare_header(MultiFDSendParams *p)
     p->iovs_num++;
 }
 
-
 #endif
diff --git a/migration/ram.c b/migration/ram.c
index 67035fb4b1..414cd0d753 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1259,7 +1259,6 @@ static int ram_save_multifd_page(RAMBlock *block, ram_addr_t offset)
     if (!multifd_queue_page(block, offset)) {
         return -1;
     }
-    stat64_add(&mig_stats.normal_pages, 1);
 
     return 1;
 }
diff --git a/migration/trace-events b/migration/trace-events
index 298ad2b0dd..9f1d7ae71a 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -128,21 +128,21 @@ postcopy_preempt_reset_channel(void) ""
 # multifd.c
 multifd_new_send_channel_async(uint8_t id) "channel %u"
 multifd_new_send_channel_async_error(uint8_t id, void *err) "channel=%u err=%p"
-multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " pages %u flags 0x%x next packet size %u"
+multifd_recv(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t zero, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u zero pages %u flags 0x%x next packet size %u"
 multifd_recv_new_channel(uint8_t id) "channel %u"
 multifd_recv_sync_main(long packet_num) "packet num %ld"
 multifd_recv_sync_main_signal(uint8_t id) "channel %u"
 multifd_recv_sync_main_wait(uint8_t id) "channel %u"
 multifd_recv_terminate_threads(bool error) "error %d"
-multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %u packets %" PRIu64 " pages %" PRIu64
+multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages, uint64_t zero_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64 " zero pages %" PRIu64
 multifd_recv_thread_start(uint8_t id) "%u"
-multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u flags 0x%x next packet size %u"
+multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal_pages, uint32_t zero_pages, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u zero pages %u flags 0x%x next packet size %u"
 multifd_send_error(uint8_t id) "channel %u"
 multifd_send_sync_main(long packet_num) "packet num %ld"
 multifd_send_sync_main_signal(uint8_t id) "channel %u"
 multifd_send_sync_main_wait(uint8_t id) "channel %u"
 multifd_send_terminate_threads(void) ""
-multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages) "channel %u packets %" PRIu64 " normal pages %"  PRIu64
+multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages, uint64_t zero_pages) "channel %u packets %" PRIu64 " normal pages %"  PRIu64 " zero pages %"  PRIu64
 multifd_send_thread_start(uint8_t id) "%u"
 multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s"
 multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s"
diff --git a/qapi/migration.json b/qapi/migration.json
index 1e66272f8f..5a1bb8ad62 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -660,10 +660,13 @@
 #
 # @legacy: Perform zero page checking from main migration thread.
 #
+# @multifd: Perform zero page checking from multifd sender thread.
+#
 # Since: 9.0
+#
 ##
 { 'enum': 'ZeroPageDetection',
-  'data': [ 'none', 'legacy' ] }
+  'data': [ 'none', 'legacy', 'multifd' ] }
 
 ##
 # @BitmapMigrationBitmapAliasTransform:
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-28 19:48   ` Fabiano Rosas
  2024-02-26 19:56 ` [PATCH v3 4/7] migration/multifd: Enable multifd zero page checking by default Hao Xiang
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

1. Add a dedicated handler for MigrationOps::ram_save_target_page in
multifd live migration.
2. Refactor ram_save_target_page_legacy so that the legacy and multifd
handlers don't have internal functions calling into each other.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 migration/ram.c | 43 ++++++++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index 414cd0d753..f60627e11a 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1123,10 +1123,6 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss,
     QEMUFile *file = pss->pss_channel;
     int len = 0;
 
-    if (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_NONE) {
-        return 0;
-    }
-
     if (!buffer_is_zero(p, TARGET_PAGE_SIZE)) {
         return 0;
     }
@@ -2046,7 +2042,6 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss,
  */
 static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss)
 {
-    RAMBlock *block = pss->block;
     ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS;
     int res;
 
@@ -2062,17 +2057,34 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss)
         return 1;
     }
 
+    return ram_save_page(rs, pss);
+}
+
+/**
+ * ram_save_target_page_multifd: send one target page to multifd workers
+ *
+ * Returns 1 if the page was queued, -1 otherwise.
+ *
+ * @rs: current RAM state
+ * @pss: data about the page we want to send
+ */
+static int ram_save_target_page_multifd(RAMState *rs, PageSearchStatus *pss)
+{
+    RAMBlock *block = pss->block;
+    ram_addr_t offset = ((ram_addr_t)pss->page) << TARGET_PAGE_BITS;
+
     /*
-     * Do not use multifd in postcopy as one whole host page should be
-     * placed.  Meanwhile postcopy requires atomic update of pages, so even
-     * if host page size == guest page size the dest guest during run may
-     * still see partially copied pages which is data corruption.
+     * Backward compatibility support. While using multifd live
+     * migration, we still need to handle zero page checking on the
+     * migration main thread.
      */
-    if (migrate_multifd() && !migration_in_postcopy()) {
-        return ram_save_multifd_page(block, offset);
+    if (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_LEGACY) {
+        if (save_zero_page(rs, pss, offset)) {
+            return 1;
+        }
     }
 
-    return ram_save_page(rs, pss);
+    return ram_save_multifd_page(block, offset);
 }
 
 /* Should be called before sending a host page */
@@ -2984,7 +2996,12 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
     }
 
     migration_ops = g_malloc0(sizeof(MigrationOps));
-    migration_ops->ram_save_target_page = ram_save_target_page_legacy;
+
+    if (migrate_multifd()) {
+        migration_ops->ram_save_target_page = ram_save_target_page_multifd;
+    } else {
+        migration_ops->ram_save_target_page = ram_save_target_page_legacy;
+    }
 
     bql_unlock();
     ret = multifd_send_sync_main();
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 4/7] migration/multifd: Enable multifd zero page checking by default.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
                   ` (2 preceding siblings ...)
  2024-02-26 19:56 ` [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 5/7] migration/multifd: Add new migration test cases for legacy zero page checking Hao Xiang
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

Set default "zero-page-detection" option to "multifd". Now zero page
checking can be done in the multifd threads and this becomes the
default configuration. We still provide backward compatibility
where zero page checking is done from the migration main thread.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 migration/options.c | 2 +-
 qapi/migration.json | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/migration/options.c b/migration/options.c
index 3c603391b0..3c79b6ccd4 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -181,7 +181,7 @@ Property migration_properties[] = {
                       MIG_MODE_NORMAL),
     DEFINE_PROP_ZERO_PAGE_DETECTION("zero-page-detection", MigrationState,
                        parameters.zero_page_detection,
-                       ZERO_PAGE_DETECTION_LEGACY),
+                       ZERO_PAGE_DETECTION_MULTIFD),
 
     /* Migration capabilities */
     DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
diff --git a/qapi/migration.json b/qapi/migration.json
index 5a1bb8ad62..a0a85a0312 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -890,7 +890,7 @@
 #        (Since 8.2)
 #
 # @zero-page-detection: Whether and how to detect zero pages. More details
-#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#     see description in @ZeroPageDetection. Default is 'multifd'.  (since 9.0)
 #
 # Features:
 #
@@ -1086,7 +1086,7 @@
 #        (Since 8.2)
 #
 # @zero-page-detection: Whether and how to detect zero pages. More details
-#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#     see description in @ZeroPageDetection. Default is 'multifd'.  (since 9.0)
 #
 # Features:
 #
@@ -1318,7 +1318,7 @@
 #        (Since 8.2)
 #
 # @zero-page-detection: Whether and how to detect zero pages. More details
-#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
+#     see description in @ZeroPageDetection. Default is 'multifd'.  (since 9.0)
 #
 # Features:
 #
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 5/7] migration/multifd: Add new migration test cases for legacy zero page checking.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
                   ` (3 preceding siblings ...)
  2024-02-26 19:56 ` [PATCH v3 4/7] migration/multifd: Enable multifd zero page checking by default Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-26 19:56 ` [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface Hao Xiang
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

Now that zero page checking is done on the multifd sender threads by
default, we still provide an option for backward compatibility. This
change adds a qtest migration test case to set the zero-page-detection
option to "legacy" and run multifd migration with zero page checking on the
migration main thread.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 tests/qtest/migration-test.c | 52 ++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 8a5bb1752e..65b531d871 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -2621,6 +2621,24 @@ test_migrate_precopy_tcp_multifd_start(QTestState *from,
     return test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
 }
 
+static void *
+test_migrate_precopy_tcp_multifd_start_zero_page_legacy(QTestState *from,
+                                                        QTestState *to)
+{
+    test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
+    migrate_set_parameter_str(from, "zero-page-detection", "legacy");
+    return NULL;
+}
+
+static void *
+test_migration_precopy_tcp_multifd_start_no_zero_page(QTestState *from,
+                                                      QTestState *to)
+{
+    test_migrate_precopy_tcp_multifd_start_common(from, to, "none");
+    migrate_set_parameter_str(from, "zero-page-detection", "none");
+    return NULL;
+}
+
 static void *
 test_migrate_precopy_tcp_multifd_zlib_start(QTestState *from,
                                             QTestState *to)
@@ -2652,6 +2670,36 @@ static void test_multifd_tcp_none(void)
     test_precopy_common(&args);
 }
 
+static void test_multifd_tcp_zero_page_legacy(void)
+{
+    MigrateCommon args = {
+        .listen_uri = "defer",
+        .start_hook = test_migrate_precopy_tcp_multifd_start_zero_page_legacy,
+        /*
+         * Multifd is more complicated than most of the features, it
+         * directly takes guest page buffers when sending, make sure
+         * everything will work alright even if guest page is changing.
+         */
+        .live = true,
+    };
+    test_precopy_common(&args);
+}
+
+static void test_multifd_tcp_no_zero_page(void)
+{
+    MigrateCommon args = {
+        .listen_uri = "defer",
+        .start_hook = test_migration_precopy_tcp_multifd_start_no_zero_page,
+        /*
+         * Multifd is more complicated than most of the features, it
+         * directly takes guest page buffers when sending, make sure
+         * everything will work alright even if guest page is changing.
+         */
+        .live = true,
+    };
+    test_precopy_common(&args);
+}
+
 static void test_multifd_tcp_zlib(void)
 {
     MigrateCommon args = {
@@ -3550,6 +3598,10 @@ int main(int argc, char **argv)
     }
     migration_test_add("/migration/multifd/tcp/plain/none",
                        test_multifd_tcp_none);
+    migration_test_add("/migration/multifd/tcp/plain/zero-page/legacy",
+                       test_multifd_tcp_zero_page_legacy);
+    migration_test_add("/migration/multifd/tcp/plain/zero-page/none",
+                       test_multifd_tcp_no_zero_page);
     migration_test_add("/migration/multifd/tcp/plain/cancel",
                        test_multifd_tcp_cancel);
     migration_test_add("/migration/multifd/tcp/plain/zlib",
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
                   ` (4 preceding siblings ...)
  2024-02-26 19:56 ` [PATCH v3 5/7] migration/multifd: Add new migration test cases for legacy zero page checking Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-28  9:52   ` Markus Armbruster
  2024-02-26 19:56 ` [PATCH v3 7/7] Update maintainer contact for migration multifd zero page checking acceleration Hao Xiang
  2024-02-28  9:36 ` [PATCH v3 0/7] Introduce multifd zero page checking Markus Armbruster
  7 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

This change extends the MigrationStatus interface to track zero pages
and zero bytes counter.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 migration/migration-hmp-cmds.c      |  4 ++++
 migration/migration.c               |  2 ++
 qapi/migration.json                 | 15 ++++++++++++++-
 tests/migration/guestperf/engine.py |  2 ++
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 7e96ae6ffd..a38ad0255d 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -111,6 +111,10 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
                        info->ram->normal);
         monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
                        info->ram->normal_bytes >> 10);
+        monitor_printf(mon, "zero pages: %" PRIu64 " pages\n",
+                       info->ram->zero_pages);
+        monitor_printf(mon, "zero bytes: %" PRIu64 " kbytes\n",
+                       info->ram->zero_bytes >> 10);
         monitor_printf(mon, "dirty sync count: %" PRIu64 "\n",
                        info->ram->dirty_sync_count);
         monitor_printf(mon, "page size: %" PRIu64 " kbytes\n",
diff --git a/migration/migration.c b/migration/migration.c
index ab21de2cad..a99f86f273 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1112,6 +1112,8 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
     info->ram->skipped = 0;
     info->ram->normal = stat64_get(&mig_stats.normal_pages);
     info->ram->normal_bytes = info->ram->normal * page_size;
+    info->ram->zero_pages = stat64_get(&mig_stats.zero_pages);
+    info->ram->zero_bytes = info->ram->zero_pages * page_size;
     info->ram->mbps = s->mbps;
     info->ram->dirty_sync_count =
         stat64_get(&mig_stats.dirty_sync_count);
diff --git a/qapi/migration.json b/qapi/migration.json
index a0a85a0312..171734c07e 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -63,6 +63,10 @@
 #     between 0 and @dirty-sync-count * @multifd-channels.  (since
 #     7.1)
 #
+# @zero-pages: number of zero pages (since 9.0)
+#
+# @zero-bytes: number of zero bytes sent (since 9.0)
+#
 # Features:
 #
 # @deprecated: Member @skipped is always zero since 1.5.3
@@ -81,7 +85,8 @@
            'multifd-bytes': 'uint64', 'pages-per-second': 'uint64',
            'precopy-bytes': 'uint64', 'downtime-bytes': 'uint64',
            'postcopy-bytes': 'uint64',
-           'dirty-sync-missed-zero-copy': 'uint64' } }
+           'dirty-sync-missed-zero-copy': 'uint64',
+           'zero-pages': 'int', 'zero-bytes': 'size' } }
 
 ##
 # @XBZRLECacheStats:
@@ -332,6 +337,8 @@
 #           "duplicate":123,
 #           "normal":123,
 #           "normal-bytes":123456,
+#           "zero-pages":123,
+#           "zero-bytes":123456,
 #           "dirty-sync-count":15
 #         }
 #      }
@@ -358,6 +365,8 @@
 #             "duplicate":123,
 #             "normal":123,
 #             "normal-bytes":123456,
+#             "zero-pages":123,
+#             "zero-bytes":123456,
 #             "dirty-sync-count":15
 #          }
 #       }
@@ -379,6 +388,8 @@
 #             "duplicate":123,
 #             "normal":123,
 #             "normal-bytes":123456,
+#             "zero-pages":123,
+#             "zero-bytes":123456,
 #             "dirty-sync-count":15
 #          },
 #          "disk":{
@@ -405,6 +416,8 @@
 #             "duplicate":10,
 #             "normal":3333,
 #             "normal-bytes":3412992,
+#             "zero-pages":3333,
+#             "zero-bytes":3412992,
 #             "dirty-sync-count":15
 #          },
 #          "xbzrle-cache":{
diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py
index 608d7270f6..693e07c227 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -92,6 +92,8 @@ def _migrate_progress(self, vm):
                 info["ram"].get("skipped", 0),
                 info["ram"].get("normal", 0),
                 info["ram"].get("normal-bytes", 0),
+                info["ram"].get("zero-pages", 0);
+                info["ram"].get("zero-bytes", 0);
                 info["ram"].get("dirty-pages-rate", 0),
                 info["ram"].get("mbps", 0),
                 info["ram"].get("dirty-sync-count", 0)
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v3 7/7] Update maintainer contact for migration multifd zero page checking acceleration.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
                   ` (5 preceding siblings ...)
  2024-02-26 19:56 ` [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface Hao Xiang
@ 2024-02-26 19:56 ` Hao Xiang
  2024-02-28  9:36 ` [PATCH v3 0/7] Introduce multifd zero page checking Markus Armbruster
  7 siblings, 0 replies; 26+ messages in thread
From: Hao Xiang @ 2024-02-26 19:56 UTC (permalink / raw)
  To: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

Add myself to maintain multifd zero page checking acceleration function.

Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
---
 MAINTAINERS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 992799171f..4a4f8f24e0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3413,6 +3413,11 @@ F: tests/migration/
 F: util/userfaultfd.c
 X: migration/rdma*
 
+Migration multifd zero page checking acceleration
+M: Hao Xiang <hao.xiang@bytedance.com>
+S: Maintained
+F: migration/multifd-zero-page.c
+
 RDMA Migration
 R: Li Zhijian <lizhijian@fujitsu.com>
 R: Peter Xu <peterx@redhat.com>
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 0/7] Introduce multifd zero page checking.
  2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
                   ` (6 preceding siblings ...)
  2024-02-26 19:56 ` [PATCH v3 7/7] Update maintainer contact for migration multifd zero page checking acceleration Hao Xiang
@ 2024-02-28  9:36 ` Markus Armbruster
  7 siblings, 0 replies; 26+ messages in thread
From: Markus Armbruster @ 2024-02-28  9:36 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Needs a rebase.  But let me have a look at the QAPI schema changes
first.



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection.
  2024-02-26 19:56 ` [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection Hao Xiang
@ 2024-02-28  9:43   ` Markus Armbruster
  2024-02-28 18:30     ` [External] " Hao Xiang
  0 siblings, 1 reply; 26+ messages in thread
From: Markus Armbruster @ 2024-02-28  9:43 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> This new parameter controls where the zero page checking is running.
> 1. If this parameter is set to 'legacy', zero page checking is
> done in the migration main thread.
> 2. If this parameter is set to 'none', zero page checking is disabled.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>

[...]

> diff --git a/qapi/migration.json b/qapi/migration.json
> index 5a565d9b8d..1e66272f8f 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -653,6 +653,18 @@
>  { 'enum': 'MigMode',
>    'data': [ 'normal', 'cpr-reboot' ] }
>  
> +##
> +# @ZeroPageDetection:
> +#
> +# @none: Do not perform zero page checking.
> +#
> +# @legacy: Perform zero page checking from main migration thread.
> +#
> +# Since: 9.0
> +##
> +{ 'enum': 'ZeroPageDetection',
> +  'data': [ 'none', 'legacy' ] }
> +
>  ##
>  # @BitmapMigrationBitmapAliasTransform:
>  #
> @@ -874,6 +886,9 @@
>  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
>  #        (Since 8.2)
>  #
> +# @zero-page-detection: Whether and how to detect zero pages. More details
> +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> +#

I'm not sure we need to point to the member's type.  If we want to, we
better fix the prose: "For additional information, see
@ZeroPageDetection" or similar.

Two spaces between sentences for consistency, please.  Also, limit line
length 70 characters.

Together:

   # @zero-page-detection: Whether and how to detect zero pages.  For
   #     additional information, see @ZeroPageDetection.  Default is
   #     'multifd'.  (since 9.0)

Same for the other two copies.

>  # Features:
>  #
>  # @deprecated: Member @block-incremental is deprecated.  Use
> @@ -907,7 +922,8 @@
>             'block-bitmap-mapping',
>             { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
>             'vcpu-dirty-limit',
> -           'mode'] }
> +           'mode',
> +           'zero-page-detection'] }
>  
>  ##
>  # @MigrateSetParameters:
> @@ -1066,6 +1082,9 @@
>  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
>  #        (Since 8.2)
>  #
> +# @zero-page-detection: Whether and how to detect zero pages. More details
> +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> +#
>  # Features:
>  #
>  # @deprecated: Member @block-incremental is deprecated.  Use
> @@ -1119,7 +1138,8 @@
>              '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
>                                              'features': [ 'unstable' ] },
>              '*vcpu-dirty-limit': 'uint64',
> -            '*mode': 'MigMode'} }
> +            '*mode': 'MigMode',
> +            '*zero-page-detection': 'ZeroPageDetection'} }
>  
>  ##
>  # @migrate-set-parameters:
> @@ -1294,6 +1314,9 @@
>  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
>  #        (Since 8.2)
>  #
> +# @zero-page-detection: Whether and how to detect zero pages. More details
> +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> +#
>  # Features:
>  #
>  # @deprecated: Member @block-incremental is deprecated.  Use
> @@ -1344,7 +1367,8 @@
>              '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
>                                              'features': [ 'unstable' ] },
>              '*vcpu-dirty-limit': 'uint64',
> -            '*mode': 'MigMode'} }
> +            '*mode': 'MigMode',
> +            '*zero-page-detection': 'ZeroPageDetection'} }
>  
>  ##
>  # @query-migrate-parameters:



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
@ 2024-02-28  9:45   ` Markus Armbruster
  2024-02-28  9:50   ` Markus Armbruster
  2024-02-28 19:46   ` Fabiano Rosas
  2 siblings, 0 replies; 26+ messages in thread
From: Markus Armbruster @ 2024-02-28  9:45 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> 1. Add zero_pages field in MultiFDPacket_t.
> 2. Implements the zero page detection and handling on the multifd
> threads for non-compression, zlib and zstd compression backends.
> 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> 5. Adds zero page counters and updates multifd send/receive tracing
> format to track the newly added counters.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>

[...]

> diff --git a/qapi/migration.json b/qapi/migration.json
> index 1e66272f8f..5a1bb8ad62 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -660,10 +660,13 @@
>  #
>  # @legacy: Perform zero page checking from main migration thread.
>  #
> +# @multifd: Perform zero page checking from multifd sender thread.
> +#

Make that "in thread" instead of "from thread".  Both occurences,
i.e. here for @multifd, and in PATCH 1 for @legacy.

>  # Since: 9.0
> +#
>  ##
>  { 'enum': 'ZeroPageDetection',
> -  'data': [ 'none', 'legacy' ] }
> +  'data': [ 'none', 'legacy', 'multifd' ] }
>  
>  ##
>  # @BitmapMigrationBitmapAliasTransform:



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
  2024-02-28  9:45   ` Markus Armbruster
@ 2024-02-28  9:50   ` Markus Armbruster
  2024-02-28 18:45     ` [External] " Hao Xiang
  2024-02-28 19:46   ` Fabiano Rosas
  2 siblings, 1 reply; 26+ messages in thread
From: Markus Armbruster @ 2024-02-28  9:50 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> 1. Add zero_pages field in MultiFDPacket_t.
> 2. Implements the zero page detection and handling on the multifd
> threads for non-compression, zlib and zstd compression backends.
> 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> 5. Adds zero page counters and updates multifd send/receive tracing
> format to track the newly added counters.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>

[...]

> diff --git a/qapi/migration.json b/qapi/migration.json
> index 1e66272f8f..5a1bb8ad62 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -660,10 +660,13 @@
>  #
>  # @legacy: Perform zero page checking from main migration thread.
>  #
> +# @multifd: Perform zero page checking from multifd sender thread.
> +#
>  # Since: 9.0
> +#
>  ##
>  { 'enum': 'ZeroPageDetection',
> -  'data': [ 'none', 'legacy' ] }
> +  'data': [ 'none', 'legacy', 'multifd' ] }
>  
>  ##
>  # @BitmapMigrationBitmapAliasTransform:

What happens when you set "zero-page-detection": "multifd" *without*
enabling multifd migration?



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-02-26 19:56 ` [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface Hao Xiang
@ 2024-02-28  9:52   ` Markus Armbruster
  2024-02-28 18:36     ` [External] " Hao Xiang
  0 siblings, 1 reply; 26+ messages in thread
From: Markus Armbruster @ 2024-02-28  9:52 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> This change extends the MigrationStatus interface to track zero pages
> and zero bytes counter.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>

[...]

> diff --git a/qapi/migration.json b/qapi/migration.json
> index a0a85a0312..171734c07e 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -63,6 +63,10 @@
>  #     between 0 and @dirty-sync-count * @multifd-channels.  (since
>  #     7.1)
>  #
> +# @zero-pages: number of zero pages (since 9.0)
> +#
> +# @zero-bytes: number of zero bytes sent (since 9.0)
> +#

Awfully terse.  How are these two related?

>  # Features:
>  #
>  # @deprecated: Member @skipped is always zero since 1.5.3

[...]



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection.
  2024-02-28  9:43   ` Markus Armbruster
@ 2024-02-28 18:30     ` Hao Xiang
  2024-02-29  5:34       ` Markus Armbruster
  0 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-28 18:30 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Wed, Feb 28, 2024 at 1:43 AM Markus Armbruster <armbru@redhat.com> wrote:
>
> Hao Xiang <hao.xiang@bytedance.com> writes:
>
> > This new parameter controls where the zero page checking is running.
> > 1. If this parameter is set to 'legacy', zero page checking is
> > done in the migration main thread.
> > 2. If this parameter is set to 'none', zero page checking is disabled.
> >
> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>
> [...]
>
> > diff --git a/qapi/migration.json b/qapi/migration.json
> > index 5a565d9b8d..1e66272f8f 100644
> > --- a/qapi/migration.json
> > +++ b/qapi/migration.json
> > @@ -653,6 +653,18 @@
> >  { 'enum': 'MigMode',
> >    'data': [ 'normal', 'cpr-reboot' ] }
> >
> > +##
> > +# @ZeroPageDetection:
> > +#
> > +# @none: Do not perform zero page checking.
> > +#
> > +# @legacy: Perform zero page checking from main migration thread.
> > +#
> > +# Since: 9.0
> > +##
> > +{ 'enum': 'ZeroPageDetection',
> > +  'data': [ 'none', 'legacy' ] }
> > +
> >  ##
> >  # @BitmapMigrationBitmapAliasTransform:
> >  #
> > @@ -874,6 +886,9 @@
> >  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
> >  #        (Since 8.2)
> >  #
> > +# @zero-page-detection: Whether and how to detect zero pages. More details
> > +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> > +#
>
> I'm not sure we need to point to the member's type.  If we want to, we
> better fix the prose: "For additional information, see
> @ZeroPageDetection" or similar.

This is mimicking what was done for the "mode" migration option. There
aren't many enumeration types on the interface I can learn from.

Existing code

#
# @mode: Migration mode. See description in @MigMode. Default is 'normal'.
# (Since 8.2)

>
> Two spaces between sentences for consistency, please.  Also, limit line
> length 70 characters.
>
> Together:
>
>    # @zero-page-detection: Whether and how to detect zero pages.  For
>    #     additional information, see @ZeroPageDetection.  Default is
>    #     'multifd'.  (since 9.0)
>
> Same for the other two copies.

Will change that.

>
> >  # Features:
> >  #
> >  # @deprecated: Member @block-incremental is deprecated.  Use
> > @@ -907,7 +922,8 @@
> >             'block-bitmap-mapping',
> >             { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
> >             'vcpu-dirty-limit',
> > -           'mode'] }
> > +           'mode',
> > +           'zero-page-detection'] }
> >
> >  ##
> >  # @MigrateSetParameters:
> > @@ -1066,6 +1082,9 @@
> >  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
> >  #        (Since 8.2)
> >  #
> > +# @zero-page-detection: Whether and how to detect zero pages. More details
> > +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> > +#
> >  # Features:
> >  #
> >  # @deprecated: Member @block-incremental is deprecated.  Use
> > @@ -1119,7 +1138,8 @@
> >              '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
> >                                              'features': [ 'unstable' ] },
> >              '*vcpu-dirty-limit': 'uint64',
> > -            '*mode': 'MigMode'} }
> > +            '*mode': 'MigMode',
> > +            '*zero-page-detection': 'ZeroPageDetection'} }
> >
> >  ##
> >  # @migrate-set-parameters:
> > @@ -1294,6 +1314,9 @@
> >  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
> >  #        (Since 8.2)
> >  #
> > +# @zero-page-detection: Whether and how to detect zero pages. More details
> > +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
> > +#
> >  # Features:
> >  #
> >  # @deprecated: Member @block-incremental is deprecated.  Use
> > @@ -1344,7 +1367,8 @@
> >              '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
> >                                              'features': [ 'unstable' ] },
> >              '*vcpu-dirty-limit': 'uint64',
> > -            '*mode': 'MigMode'} }
> > +            '*mode': 'MigMode',
> > +            '*zero-page-detection': 'ZeroPageDetection'} }
> >
> >  ##
> >  # @query-migrate-parameters:
>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-02-28  9:52   ` Markus Armbruster
@ 2024-02-28 18:36     ` Hao Xiang
  2024-02-29  6:01       ` Markus Armbruster
  0 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-28 18:36 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Wed, Feb 28, 2024 at 1:52 AM Markus Armbruster <armbru@redhat.com> wrote:
>
> Hao Xiang <hao.xiang@bytedance.com> writes:
>
> > This change extends the MigrationStatus interface to track zero pages
> > and zero bytes counter.
> >
> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>
> [...]
>
> > diff --git a/qapi/migration.json b/qapi/migration.json
> > index a0a85a0312..171734c07e 100644
> > --- a/qapi/migration.json
> > +++ b/qapi/migration.json
> > @@ -63,6 +63,10 @@
> >  #     between 0 and @dirty-sync-count * @multifd-channels.  (since
> >  #     7.1)
> >  #
> > +# @zero-pages: number of zero pages (since 9.0)
> > +#
> > +# @zero-bytes: number of zero bytes sent (since 9.0)
> > +#
>
> Awfully terse.  How are these two related?

Sorry I forgot to address the same feedback from the last version.
zero-pages are the number of pages being detected as all "zero" and
hence the payload isn't sent over the network. zero-bytes is basically
zero-pages * page_size. It's the number of bytes migrated (but not
actually sent through the network) because they are all "zero". These
two are related to the existing interface below. normal and
normal-bytes are the same representation of pages who are not all
"zero" and are actually sent through the network.

# @normal: number of normal pages (since 1.2)
#
# @normal-bytes: number of normal bytes sent (since 1.2)

>
> >  # Features:
> >  #
> >  # @deprecated: Member @skipped is always zero since 1.5.3
>
> [...]
>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-28  9:50   ` Markus Armbruster
@ 2024-02-28 18:45     ` Hao Xiang
  2024-02-29  5:41       ` Markus Armbruster
  0 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-02-28 18:45 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Wed, Feb 28, 2024 at 1:50 AM Markus Armbruster <armbru@redhat.com> wrote:
>
> Hao Xiang <hao.xiang@bytedance.com> writes:
>
> > 1. Add zero_pages field in MultiFDPacket_t.
> > 2. Implements the zero page detection and handling on the multifd
> > threads for non-compression, zlib and zstd compression backends.
> > 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> > 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> > 5. Adds zero page counters and updates multifd send/receive tracing
> > format to track the newly added counters.
> >
> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>
> [...]
>
> > diff --git a/qapi/migration.json b/qapi/migration.json
> > index 1e66272f8f..5a1bb8ad62 100644
> > --- a/qapi/migration.json
> > +++ b/qapi/migration.json
> > @@ -660,10 +660,13 @@
> >  #
> >  # @legacy: Perform zero page checking from main migration thread.
> >  #
> > +# @multifd: Perform zero page checking from multifd sender thread.
> > +#
> >  # Since: 9.0
> > +#
> >  ##
> >  { 'enum': 'ZeroPageDetection',
> > -  'data': [ 'none', 'legacy' ] }
> > +  'data': [ 'none', 'legacy', 'multifd' ] }
> >
> >  ##
> >  # @BitmapMigrationBitmapAliasTransform:
>
> What happens when you set "zero-page-detection": "multifd" *without*
> enabling multifd migration?

Very good question! Right now the behavior is that if "multifd
migration" is not enabled, it goes through the legacy code path and
the "multifd zero page" option is ignored. The legacy path has its own
zero page checking and will run the same way as before. This is for
backward compatibility.
>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
  2024-02-28  9:45   ` Markus Armbruster
  2024-02-28  9:50   ` Markus Armbruster
@ 2024-02-28 19:46   ` Fabiano Rosas
  2024-03-01  1:55     ` [External] " Hao Xiang
  2 siblings, 1 reply; 26+ messages in thread
From: Fabiano Rosas @ 2024-02-28 19:46 UTC (permalink / raw)
  To: Hao Xiang, pbonzini, berrange, eduardo, peterx, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

Hao Xiang <hao.xiang@bytedance.com> writes:

> 1. Add zero_pages field in MultiFDPacket_t.
> 2. Implements the zero page detection and handling on the multifd
> threads for non-compression, zlib and zstd compression backends.
> 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> 5. Adds zero page counters and updates multifd send/receive tracing
> format to track the newly added counters.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
> ---
>  hw/core/machine.c                |  4 +-
>  hw/core/qdev-properties-system.c |  2 +-
>  migration/meson.build            |  1 +
>  migration/multifd-zero-page.c    | 78 ++++++++++++++++++++++++++++++
>  migration/multifd-zlib.c         | 21 ++++++--
>  migration/multifd-zstd.c         | 20 ++++++--
>  migration/multifd.c              | 83 +++++++++++++++++++++++++++-----
>  migration/multifd.h              | 24 ++++++++-
>  migration/ram.c                  |  1 -
>  migration/trace-events           |  8 +--
>  qapi/migration.json              |  5 +-
>  11 files changed, 214 insertions(+), 33 deletions(-)
>  create mode 100644 migration/multifd-zero-page.c
>
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index fb5afdcae4..746da219a4 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -32,7 +32,9 @@
>  #include "hw/virtio/virtio-net.h"
>  #include "audio/audio.h"
>  
> -GlobalProperty hw_compat_8_2[] = {};
> +GlobalProperty hw_compat_8_2[] = {
> +    { "migration", "zero-page-detection", "legacy"},
> +};
>  const size_t hw_compat_8_2_len = G_N_ELEMENTS(hw_compat_8_2);
>  
>  GlobalProperty hw_compat_8_1[] = {
> diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
> index 228e685f52..6e6f68ae1b 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -682,7 +682,7 @@ const PropertyInfo qdev_prop_mig_mode = {
>  const PropertyInfo qdev_prop_zero_page_detection = {
>      .name = "ZeroPageDetection",
>      .description = "zero_page_detection values, "
> -                   "none,legacy",
> +                   "none,legacy,multifd",
>      .enum_table = &ZeroPageDetection_lookup,
>      .get = qdev_propinfo_get_enum,
>      .set = qdev_propinfo_set_enum,
> diff --git a/migration/meson.build b/migration/meson.build
> index 92b1cc4297..1eeb915ff6 100644
> --- a/migration/meson.build
> +++ b/migration/meson.build
> @@ -22,6 +22,7 @@ system_ss.add(files(
>    'migration.c',
>    'multifd.c',
>    'multifd-zlib.c',
> +  'multifd-zero-page.c',
>    'ram-compress.c',
>    'options.c',
>    'postcopy-ram.c',
> diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
> new file mode 100644
> index 0000000000..1650c41b26
> --- /dev/null
> +++ b/migration/multifd-zero-page.c
> @@ -0,0 +1,78 @@
> +/*
> + * Multifd zero page detection implementation.
> + *
> + * Copyright (c) 2024 Bytedance Inc
> + *
> + * Authors:
> + *  Hao Xiang <hao.xiang@bytedance.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> +#include "exec/ramblock.h"
> +#include "migration.h"
> +#include "multifd.h"
> +#include "options.h"
> +#include "ram.h"
> +
> +static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
> +{
> +    ram_addr_t temp;
> +
> +    if (a == b) {
> +        return;
> +    }
> +
> +    temp = pages_offset[a];
> +    pages_offset[a] = pages_offset[b];
> +    pages_offset[b] = temp;
> +}
> +
> +/**
> + * multifd_zero_page_check_send: Perform zero page detection on all pages.
> + *
> + * Sort the page offset array by moving all normal pages to
> + * the left and all zero pages to the right of the array.

Let's move this to the loop as a comment. Here it's better to just
inform about the side effects:

Sorts normal pages before zero pages in p->pages->offset and updates
p->pages->normal_num.

> + *
> + * @param p A pointer to the send params.
> + */
> +void multifd_zero_page_check_send(MultiFDSendParams *p)

Use multifd_send_zero_page_check for consistency with the rest of the code.

> +{
> +    /*
> +     * QEMU older than 9.0 don't understand zero page
> +     * on multifd channel. This switch is required to
> +     * maintain backward compatibility.
> +     */
> +    bool use_multifd_zero_page =
> +        (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD);

Could introduce a helper for this.

static bool multifd_zero_page(void)
{
    return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD;
}

> +    MultiFDPages_t *pages = p->pages;
> +    RAMBlock *rb = pages->block;
> +    int index_normal = 0;
> +    int index_zero = pages->num - 1;

IMHO, i and j are more idiomatic, makes the code easier on the eyes.

> +
> +    while (index_normal <= index_zero) {
> +        uint64_t offset = pages->offset[index_normal];
> +        if (use_multifd_zero_page &&

You don't need to check this at every iteration. Could check at the top
and exit right away.

> +            buffer_is_zero(rb->host + offset, p->page_size)) {
> +            swap_page_offset(pages->offset, index_normal, index_zero);
> +            index_zero--;
> +            ram_release_page(rb->idstr, offset);
> +        } else {
> +            index_normal++;
> +            pages->normal_num++;

Not a fan of changing pages->normal_num like this. Let's make the loop
just sort and update normal_num at the end.

Putting all together:

void multifd_send_zero_page_check(MultiFDSendParams *p)
{
    MultiFDPages_t *pages = p->pages;
    RAMBlock *rb = pages->block;
    int i = 0;
    int j = pages->num - 1;

    if (!multifd_zero_page()) {
        pages->normal_num = pages->num;
        return;
    }

    /*
     * Sort the offsets array by moving all normal pages to the start
     * and all zero pages to the end of the array.
     */
    while (i <= j) {
        uint64_t offset = pages->offset[i];

        if (!buffer_is_zero(rb->host + offset, p->page_size)) {
            i++;
            continue;
        }

        swap_page_offset(pages->offset, i, j);
        ram_release_page(rb->idstr, offset);
        j--;
    }

    pages->normal_num = i;
}

> +        }
> +    }
> +}
> +
> +void multifd_zero_page_check_recv(MultiFDRecvParams *p)
> +{
> +    for (int i = 0; i < p->zero_num; i++) {
> +        void *page = p->host + p->zero[i];
> +        if (!buffer_is_zero(page, p->page_size)) {
> +            memset(page, 0, p->page_size);
> +        }
> +    }
> +}


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page.
  2024-02-26 19:56 ` [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page Hao Xiang
@ 2024-02-28 19:48   ` Fabiano Rosas
  0 siblings, 0 replies; 26+ messages in thread
From: Fabiano Rosas @ 2024-02-28 19:48 UTC (permalink / raw)
  To: Hao Xiang, pbonzini, berrange, eduardo, peterx, eblake, armbru,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel
  Cc: Hao Xiang

Hao Xiang <hao.xiang@bytedance.com> writes:

> 1. Add a dedicated handler for MigrationOps::ram_save_target_page in
> multifd live migration.
> 2. Refactor ram_save_target_page_legacy so that the legacy and multifd
> handlers don't have internal functions calling into each other.
>
> Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>

Reviewed-by: Fabiano Rosas <farosas@suse.de>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection.
  2024-02-28 18:30     ` [External] " Hao Xiang
@ 2024-02-29  5:34       ` Markus Armbruster
  0 siblings, 0 replies; 26+ messages in thread
From: Markus Armbruster @ 2024-02-29  5:34 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> On Wed, Feb 28, 2024 at 1:43 AM Markus Armbruster <armbru@redhat.com> wrote:
>>
>> Hao Xiang <hao.xiang@bytedance.com> writes:
>>
>> > This new parameter controls where the zero page checking is running.
>> > 1. If this parameter is set to 'legacy', zero page checking is
>> > done in the migration main thread.
>> > 2. If this parameter is set to 'none', zero page checking is disabled.
>> >
>> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>>
>> [...]
>>
>> > diff --git a/qapi/migration.json b/qapi/migration.json
>> > index 5a565d9b8d..1e66272f8f 100644
>> > --- a/qapi/migration.json
>> > +++ b/qapi/migration.json
>> > @@ -653,6 +653,18 @@
>> >  { 'enum': 'MigMode',
>> >    'data': [ 'normal', 'cpr-reboot' ] }
>> >
>> > +##
>> > +# @ZeroPageDetection:
>> > +#
>> > +# @none: Do not perform zero page checking.
>> > +#
>> > +# @legacy: Perform zero page checking from main migration thread.
>> > +#
>> > +# Since: 9.0
>> > +##
>> > +{ 'enum': 'ZeroPageDetection',
>> > +  'data': [ 'none', 'legacy' ] }
>> > +
>> >  ##
>> >  # @BitmapMigrationBitmapAliasTransform:
>> >  #
>> > @@ -874,6 +886,9 @@
>> >  # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
>> >  #        (Since 8.2)
>> >  #
>> > +# @zero-page-detection: Whether and how to detect zero pages. More details
>> > +#     see description in @ZeroPageDetection. Default is 'legacy'.  (since 9.0)
>> > +#
>>
>> I'm not sure we need to point to the member's type.  If we want to, we
>> better fix the prose: "For additional information, see
>> @ZeroPageDetection" or similar.
>
> This is mimicking what was done for the "mode" migration option. There
> aren't many enumeration types on the interface I can learn from.
>
> Existing code
>
> #
> # @mode: Migration mode. See description in @MigMode. Default is 'normal'.
> # (Since 8.2)

"More details see description in @TYPE" feels off, "See description in
@TYPE" is better.  Feel free to use it instead of my suggested phrasing.

[...]



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-28 18:45     ` [External] " Hao Xiang
@ 2024-02-29  5:41       ` Markus Armbruster
  2024-02-29 15:46         ` Fabiano Rosas
  0 siblings, 1 reply; 26+ messages in thread
From: Markus Armbruster @ 2024-02-29  5:41 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> On Wed, Feb 28, 2024 at 1:50 AM Markus Armbruster <armbru@redhat.com> wrote:
>>
>> Hao Xiang <hao.xiang@bytedance.com> writes:
>>
>> > 1. Add zero_pages field in MultiFDPacket_t.
>> > 2. Implements the zero page detection and handling on the multifd
>> > threads for non-compression, zlib and zstd compression backends.
>> > 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
>> > 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
>> > 5. Adds zero page counters and updates multifd send/receive tracing
>> > format to track the newly added counters.
>> >
>> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>>
>> [...]
>>
>> > diff --git a/qapi/migration.json b/qapi/migration.json
>> > index 1e66272f8f..5a1bb8ad62 100644
>> > --- a/qapi/migration.json
>> > +++ b/qapi/migration.json
>> > @@ -660,10 +660,13 @@
>> >  #
>> >  # @legacy: Perform zero page checking from main migration thread.
>> >  #
>> > +# @multifd: Perform zero page checking from multifd sender thread.
>> > +#
>> >  # Since: 9.0
>> > +#
>> >  ##
>> >  { 'enum': 'ZeroPageDetection',
>> > -  'data': [ 'none', 'legacy' ] }
>> > +  'data': [ 'none', 'legacy', 'multifd' ] }
>> >
>> >  ##
>> >  # @BitmapMigrationBitmapAliasTransform:
>>
>> What happens when you set "zero-page-detection": "multifd" *without*
>> enabling multifd migration?
>
> Very good question! Right now the behavior is that if "multifd
> migration" is not enabled, it goes through the legacy code path and
> the "multifd zero page" option is ignored. The legacy path has its own
> zero page checking and will run the same way as before. This is for
> backward compatibility.

We need one of two improvements then:

1. Make "zero-page-detection" reject value "multifd" when multifd
   migration is not enabled.  Document this: "Requires migration
   capability @multifd" or similar.

2. Document that "multifd" means multifd only when multifd is enabled,
   else same as "legacy".

I prefer 1., because it's easier to document.  But migration maintainers
may have their own preference.  Peter, Fabiano?



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-02-28 18:36     ` [External] " Hao Xiang
@ 2024-02-29  6:01       ` Markus Armbruster
  2024-03-01  1:18         ` Hao Xiang
  0 siblings, 1 reply; 26+ messages in thread
From: Markus Armbruster @ 2024-02-29  6:01 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> On Wed, Feb 28, 2024 at 1:52 AM Markus Armbruster <armbru@redhat.com> wrote:
>>
>> Hao Xiang <hao.xiang@bytedance.com> writes:
>>
>> > This change extends the MigrationStatus interface to track zero pages
>> > and zero bytes counter.
>> >
>> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>>
>> [...]
>>
>> > diff --git a/qapi/migration.json b/qapi/migration.json
>> > index a0a85a0312..171734c07e 100644
>> > --- a/qapi/migration.json
>> > +++ b/qapi/migration.json
>> > @@ -63,6 +63,10 @@
>> >  #     between 0 and @dirty-sync-count * @multifd-channels.  (since
>> >  #     7.1)
>> >  #
>> > +# @zero-pages: number of zero pages (since 9.0)
>> > +#
>> > +# @zero-bytes: number of zero bytes sent (since 9.0)
>> > +#
>>
>> Awfully terse.  How are these two related?
>
> Sorry I forgot to address the same feedback from the last version.

Happens :)

> zero-pages are the number of pages being detected as all "zero" and
> hence the payload isn't sent over the network. zero-bytes is basically
> zero-pages * page_size. It's the number of bytes migrated (but not
> actually sent through the network) because they are all "zero". These
> two are related to the existing interface below. normal and
> normal-bytes are the same representation of pages who are not all
> "zero" and are actually sent through the network.
>
> # @normal: number of normal pages (since 1.2)
> #
> # @normal-bytes: number of normal bytes sent (since 1.2)

We also have

  # @duplicate: number of duplicate (zero) pages (since 1.2)
  #
  # @skipped: number of skipped zero pages. Always zero, only provided for
  #     compatibility (since 1.5)

Page skipping was introduced in 1.5, and withdrawn in 1.5.3 and 1.6.
@skipped was formally deprecated in 8.1.  It'll soon be gone, no need to
worry about it now.

That leaves three values related to pages sent: @normal (and
@normal-bytes), @duplicate (but no @duplicate-bytes), and @zero-pages
(and @zero-bytes).

I unwittingly created a naming inconsistency between @normal,
@duplicate, and @zero-pages when I asked you to rename @zero to
@zero-pages.

The meaning of the three values is not obvious, and the doc comments
don't explain them.  Can you, or anybody familiar with migration,
explain them to me?

MigrationStats return some values as bytes, some as pages, and some as
both.  I hate that.  Can we standardize on bytes?

>>
>> >  # Features:
>> >  #
>> >  # @deprecated: Member @skipped is always zero since 1.5.3
>>
>> [...]
>>



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-29  5:41       ` Markus Armbruster
@ 2024-02-29 15:46         ` Fabiano Rosas
  2024-03-01  1:27           ` Hao Xiang
  0 siblings, 1 reply; 26+ messages in thread
From: Fabiano Rosas @ 2024-02-29 15:46 UTC (permalink / raw)
  To: Markus Armbruster, Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, eblake, thuth, lvivier,
	jdenemar, marcel.apfelbaum, philmd, wangyanan55, qemu-devel

Markus Armbruster <armbru@redhat.com> writes:

> Hao Xiang <hao.xiang@bytedance.com> writes:
>
>> On Wed, Feb 28, 2024 at 1:50 AM Markus Armbruster <armbru@redhat.com> wrote:
>>>
>>> Hao Xiang <hao.xiang@bytedance.com> writes:
>>>
>>> > 1. Add zero_pages field in MultiFDPacket_t.
>>> > 2. Implements the zero page detection and handling on the multifd
>>> > threads for non-compression, zlib and zstd compression backends.
>>> > 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
>>> > 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
>>> > 5. Adds zero page counters and updates multifd send/receive tracing
>>> > format to track the newly added counters.
>>> >
>>> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>>>
>>> [...]
>>>
>>> > diff --git a/qapi/migration.json b/qapi/migration.json
>>> > index 1e66272f8f..5a1bb8ad62 100644
>>> > --- a/qapi/migration.json
>>> > +++ b/qapi/migration.json
>>> > @@ -660,10 +660,13 @@
>>> >  #
>>> >  # @legacy: Perform zero page checking from main migration thread.
>>> >  #
>>> > +# @multifd: Perform zero page checking from multifd sender thread.
>>> > +#
>>> >  # Since: 9.0
>>> > +#
>>> >  ##
>>> >  { 'enum': 'ZeroPageDetection',
>>> > -  'data': [ 'none', 'legacy' ] }
>>> > +  'data': [ 'none', 'legacy', 'multifd' ] }
>>> >
>>> >  ##
>>> >  # @BitmapMigrationBitmapAliasTransform:
>>>
>>> What happens when you set "zero-page-detection": "multifd" *without*
>>> enabling multifd migration?
>>
>> Very good question! Right now the behavior is that if "multifd
>> migration" is not enabled, it goes through the legacy code path and
>> the "multifd zero page" option is ignored. The legacy path has its own
>> zero page checking and will run the same way as before. This is for
>> backward compatibility.
>
> We need one of two improvements then:
>
> 1. Make "zero-page-detection" reject value "multifd" when multifd
>    migration is not enabled.  Document this: "Requires migration
>    capability @multifd" or similar.
>
> 2. Document that "multifd" means multifd only when multifd is enabled,
>    else same as "legacy".
>
> I prefer 1., because it's easier to document.  But migration maintainers
> may have their own preference.  Peter, Fabiano?

I think we need to go with 2 for consistency with the other multifd_*
parameters. I don't see any validation at options.c.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-02-29  6:01       ` Markus Armbruster
@ 2024-03-01  1:18         ` Hao Xiang
  2024-03-01  5:53           ` Markus Armbruster
  0 siblings, 1 reply; 26+ messages in thread
From: Hao Xiang @ 2024-03-01  1:18 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Wed, Feb 28, 2024 at 10:01 PM Markus Armbruster <armbru@redhat.com> wrote:
>
> Hao Xiang <hao.xiang@bytedance.com> writes:
>
> > On Wed, Feb 28, 2024 at 1:52 AM Markus Armbruster <armbru@redhat.com> wrote:
> >>
> >> Hao Xiang <hao.xiang@bytedance.com> writes:
> >>
> >> > This change extends the MigrationStatus interface to track zero pages
> >> > and zero bytes counter.
> >> >
> >> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
> >>
> >> [...]
> >>
> >> > diff --git a/qapi/migration.json b/qapi/migration.json
> >> > index a0a85a0312..171734c07e 100644
> >> > --- a/qapi/migration.json
> >> > +++ b/qapi/migration.json
> >> > @@ -63,6 +63,10 @@
> >> >  #     between 0 and @dirty-sync-count * @multifd-channels.  (since
> >> >  #     7.1)
> >> >  #
> >> > +# @zero-pages: number of zero pages (since 9.0)
> >> > +#
> >> > +# @zero-bytes: number of zero bytes sent (since 9.0)
> >> > +#
> >>
> >> Awfully terse.  How are these two related?
> >
> > Sorry I forgot to address the same feedback from the last version.
>
> Happens :)
>
> > zero-pages are the number of pages being detected as all "zero" and
> > hence the payload isn't sent over the network. zero-bytes is basically
> > zero-pages * page_size. It's the number of bytes migrated (but not
> > actually sent through the network) because they are all "zero". These
> > two are related to the existing interface below. normal and
> > normal-bytes are the same representation of pages who are not all
> > "zero" and are actually sent through the network.
> >
> > # @normal: number of normal pages (since 1.2)
> > #
> > # @normal-bytes: number of normal bytes sent (since 1.2)
>
> We also have
>
>   # @duplicate: number of duplicate (zero) pages (since 1.2)
>   #
>   # @skipped: number of skipped zero pages. Always zero, only provided for
>   #     compatibility (since 1.5)
>
> Page skipping was introduced in 1.5, and withdrawn in 1.5.3 and 1.6.
> @skipped was formally deprecated in 8.1.  It'll soon be gone, no need to
> worry about it now.
>
> That leaves three values related to pages sent: @normal (and
> @normal-bytes), @duplicate (but no @duplicate-bytes), and @zero-pages
> (and @zero-bytes).
>
> I unwittingly created a naming inconsistency between @normal,
> @duplicate, and @zero-pages when I asked you to rename @zero to
> @zero-pages.
>
> The meaning of the three values is not obvious, and the doc comments
> don't explain them.  Can you, or anybody familiar with migration,
> explain them to me?
>
> MigrationStats return some values as bytes, some as pages, and some as
> both.  I hate that.  Can we standardize on bytes?

I added zero/zero-bytes because I thought they were not there. But it
turns out "duplicate" is for that purpose. "zero/zero-bytes" is really
additional information to "normal/normal-bytes". Peter suggested that
if we add "zero/zero-bytes" we can slowly retire "duplicate" at a
later point.
I don't know the historical reason why pages/bytes are used the way it
is today. The way I understand migration, the granularity of ram
migration is "page". There are only two types of pages 1) normal 2)
zero. Zero pages' playload are not sent through the network because we
already know what it looks like. Only the page offset is sent. Normal
pages are pages that are not zero. The entire page is sent through the
network to the target host. if a user knows the zero/normal count,
they can already calculate the zero-bytes/normal-bytes (zero/normal *
page size) but it's just convenient to see both. During development, I
check on these counters a lot and they are useful.

>
> >>
> >> >  # Features:
> >> >  #
> >> >  # @deprecated: Member @skipped is always zero since 1.5.3
> >>
> >> [...]
> >>
>


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-29 15:46         ` Fabiano Rosas
@ 2024-03-01  1:27           ` Hao Xiang
  0 siblings, 0 replies; 26+ messages in thread
From: Hao Xiang @ 2024-03-01  1:27 UTC (permalink / raw)
  To: Fabiano Rosas
  Cc: Markus Armbruster, pbonzini, berrange, eduardo, peterx, eblake,
	thuth, lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Thu, Feb 29, 2024 at 7:47 AM Fabiano Rosas <farosas@suse.de> wrote:
>
> Markus Armbruster <armbru@redhat.com> writes:
>
> > Hao Xiang <hao.xiang@bytedance.com> writes:
> >
> >> On Wed, Feb 28, 2024 at 1:50 AM Markus Armbruster <armbru@redhat.com> wrote:
> >>>
> >>> Hao Xiang <hao.xiang@bytedance.com> writes:
> >>>
> >>> > 1. Add zero_pages field in MultiFDPacket_t.
> >>> > 2. Implements the zero page detection and handling on the multifd
> >>> > threads for non-compression, zlib and zstd compression backends.
> >>> > 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> >>> > 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> >>> > 5. Adds zero page counters and updates multifd send/receive tracing
> >>> > format to track the newly added counters.
> >>> >
> >>> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
> >>>
> >>> [...]
> >>>
> >>> > diff --git a/qapi/migration.json b/qapi/migration.json
> >>> > index 1e66272f8f..5a1bb8ad62 100644
> >>> > --- a/qapi/migration.json
> >>> > +++ b/qapi/migration.json
> >>> > @@ -660,10 +660,13 @@
> >>> >  #
> >>> >  # @legacy: Perform zero page checking from main migration thread.
> >>> >  #
> >>> > +# @multifd: Perform zero page checking from multifd sender thread.
> >>> > +#
> >>> >  # Since: 9.0
> >>> > +#
> >>> >  ##
> >>> >  { 'enum': 'ZeroPageDetection',
> >>> > -  'data': [ 'none', 'legacy' ] }
> >>> > +  'data': [ 'none', 'legacy', 'multifd' ] }
> >>> >
> >>> >  ##
> >>> >  # @BitmapMigrationBitmapAliasTransform:
> >>>
> >>> What happens when you set "zero-page-detection": "multifd" *without*
> >>> enabling multifd migration?
> >>
> >> Very good question! Right now the behavior is that if "multifd
> >> migration" is not enabled, it goes through the legacy code path and
> >> the "multifd zero page" option is ignored. The legacy path has its own
> >> zero page checking and will run the same way as before. This is for
> >> backward compatibility.
> >
> > We need one of two improvements then:
> >
> > 1. Make "zero-page-detection" reject value "multifd" when multifd
> >    migration is not enabled.  Document this: "Requires migration
> >    capability @multifd" or similar.
> >
> > 2. Document that "multifd" means multifd only when multifd is enabled,
> >    else same as "legacy".
> >
> > I prefer 1., because it's easier to document.  But migration maintainers
> > may have their own preference.  Peter, Fabiano?
>
> I think we need to go with 2 for consistency with the other multifd_*
> parameters. I don't see any validation at options.c.

Yeah, it's hard to do 1. Someone can also set multifd and then disable
multifd migration. This is an existing problem. I will update the
document for "multifd".


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread.
  2024-02-28 19:46   ` Fabiano Rosas
@ 2024-03-01  1:55     ` Hao Xiang
  0 siblings, 0 replies; 26+ messages in thread
From: Hao Xiang @ 2024-03-01  1:55 UTC (permalink / raw)
  To: Fabiano Rosas
  Cc: pbonzini, berrange, eduardo, peterx, eblake, armbru, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

On Wed, Feb 28, 2024 at 11:46 AM Fabiano Rosas <farosas@suse.de> wrote:
>
> Hao Xiang <hao.xiang@bytedance.com> writes:
>
> > 1. Add zero_pages field in MultiFDPacket_t.
> > 2. Implements the zero page detection and handling on the multifd
> > threads for non-compression, zlib and zstd compression backends.
> > 3. Added a new value 'multifd' in ZeroPageDetection enumeration.
> > 4. Handle migration QEMU9.0 -> QEMU8.2 compatibility.
> > 5. Adds zero page counters and updates multifd send/receive tracing
> > format to track the newly added counters.
> >
> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
> > ---
> >  hw/core/machine.c                |  4 +-
> >  hw/core/qdev-properties-system.c |  2 +-
> >  migration/meson.build            |  1 +
> >  migration/multifd-zero-page.c    | 78 ++++++++++++++++++++++++++++++
> >  migration/multifd-zlib.c         | 21 ++++++--
> >  migration/multifd-zstd.c         | 20 ++++++--
> >  migration/multifd.c              | 83 +++++++++++++++++++++++++++-----
> >  migration/multifd.h              | 24 ++++++++-
> >  migration/ram.c                  |  1 -
> >  migration/trace-events           |  8 +--
> >  qapi/migration.json              |  5 +-
> >  11 files changed, 214 insertions(+), 33 deletions(-)
> >  create mode 100644 migration/multifd-zero-page.c
> >
> > diff --git a/hw/core/machine.c b/hw/core/machine.c
> > index fb5afdcae4..746da219a4 100644
> > --- a/hw/core/machine.c
> > +++ b/hw/core/machine.c
> > @@ -32,7 +32,9 @@
> >  #include "hw/virtio/virtio-net.h"
> >  #include "audio/audio.h"
> >
> > -GlobalProperty hw_compat_8_2[] = {};
> > +GlobalProperty hw_compat_8_2[] = {
> > +    { "migration", "zero-page-detection", "legacy"},
> > +};
> >  const size_t hw_compat_8_2_len = G_N_ELEMENTS(hw_compat_8_2);
> >
> >  GlobalProperty hw_compat_8_1[] = {
> > diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
> > index 228e685f52..6e6f68ae1b 100644
> > --- a/hw/core/qdev-properties-system.c
> > +++ b/hw/core/qdev-properties-system.c
> > @@ -682,7 +682,7 @@ const PropertyInfo qdev_prop_mig_mode = {
> >  const PropertyInfo qdev_prop_zero_page_detection = {
> >      .name = "ZeroPageDetection",
> >      .description = "zero_page_detection values, "
> > -                   "none,legacy",
> > +                   "none,legacy,multifd",
> >      .enum_table = &ZeroPageDetection_lookup,
> >      .get = qdev_propinfo_get_enum,
> >      .set = qdev_propinfo_set_enum,
> > diff --git a/migration/meson.build b/migration/meson.build
> > index 92b1cc4297..1eeb915ff6 100644
> > --- a/migration/meson.build
> > +++ b/migration/meson.build
> > @@ -22,6 +22,7 @@ system_ss.add(files(
> >    'migration.c',
> >    'multifd.c',
> >    'multifd-zlib.c',
> > +  'multifd-zero-page.c',
> >    'ram-compress.c',
> >    'options.c',
> >    'postcopy-ram.c',
> > diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
> > new file mode 100644
> > index 0000000000..1650c41b26
> > --- /dev/null
> > +++ b/migration/multifd-zero-page.c
> > @@ -0,0 +1,78 @@
> > +/*
> > + * Multifd zero page detection implementation.
> > + *
> > + * Copyright (c) 2024 Bytedance Inc
> > + *
> > + * Authors:
> > + *  Hao Xiang <hao.xiang@bytedance.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/cutils.h"
> > +#include "exec/ramblock.h"
> > +#include "migration.h"
> > +#include "multifd.h"
> > +#include "options.h"
> > +#include "ram.h"
> > +
> > +static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
> > +{
> > +    ram_addr_t temp;
> > +
> > +    if (a == b) {
> > +        return;
> > +    }
> > +
> > +    temp = pages_offset[a];
> > +    pages_offset[a] = pages_offset[b];
> > +    pages_offset[b] = temp;
> > +}
> > +
> > +/**
> > + * multifd_zero_page_check_send: Perform zero page detection on all pages.
> > + *
> > + * Sort the page offset array by moving all normal pages to
> > + * the left and all zero pages to the right of the array.
>
> Let's move this to the loop as a comment. Here it's better to just
> inform about the side effects:
>
> Sorts normal pages before zero pages in p->pages->offset and updates
> p->pages->normal_num.
>
> > + *
> > + * @param p A pointer to the send params.
> > + */
> > +void multifd_zero_page_check_send(MultiFDSendParams *p)
>
> Use multifd_send_zero_page_check for consistency with the rest of the code.
>
> > +{
> > +    /*
> > +     * QEMU older than 9.0 don't understand zero page
> > +     * on multifd channel. This switch is required to
> > +     * maintain backward compatibility.
> > +     */
> > +    bool use_multifd_zero_page =
> > +        (migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD);
>
> Could introduce a helper for this.
>
> static bool multifd_zero_page(void)
> {
>     return migrate_zero_page_detection() == ZERO_PAGE_DETECTION_MULTIFD;
> }
>
> > +    MultiFDPages_t *pages = p->pages;
> > +    RAMBlock *rb = pages->block;
> > +    int index_normal = 0;
> > +    int index_zero = pages->num - 1;
>
> IMHO, i and j are more idiomatic, makes the code easier on the eyes.
>
> > +
> > +    while (index_normal <= index_zero) {
> > +        uint64_t offset = pages->offset[index_normal];
> > +        if (use_multifd_zero_page &&
>
> You don't need to check this at every iteration. Could check at the top
> and exit right away.
>
> > +            buffer_is_zero(rb->host + offset, p->page_size)) {
> > +            swap_page_offset(pages->offset, index_normal, index_zero);
> > +            index_zero--;
> > +            ram_release_page(rb->idstr, offset);
> > +        } else {
> > +            index_normal++;
> > +            pages->normal_num++;
>
> Not a fan of changing pages->normal_num like this. Let's make the loop
> just sort and update normal_num at the end.
>
> Putting all together:
>
> void multifd_send_zero_page_check(MultiFDSendParams *p)
> {
>     MultiFDPages_t *pages = p->pages;
>     RAMBlock *rb = pages->block;
>     int i = 0;
>     int j = pages->num - 1;
>
>     if (!multifd_zero_page()) {
>         pages->normal_num = pages->num;
>         return;
>     }
>
>     /*
>      * Sort the offsets array by moving all normal pages to the start
>      * and all zero pages to the end of the array.
>      */
>     while (i <= j) {
>         uint64_t offset = pages->offset[i];
>
>         if (!buffer_is_zero(rb->host + offset, p->page_size)) {
>             i++;
>             continue;
>         }
>
>         swap_page_offset(pages->offset, i, j);
>         ram_release_page(rb->idstr, offset);
>         j--;
>     }
>
>     pages->normal_num = i;
> }
>

Sure. Will fix these in the next version.

> > +        }
> > +    }
> > +}
> > +
> > +void multifd_zero_page_check_recv(MultiFDRecvParams *p)
> > +{
> > +    for (int i = 0; i < p->zero_num; i++) {
> > +        void *page = p->host + p->zero[i];
> > +        if (!buffer_is_zero(page, p->page_size)) {
> > +            memset(page, 0, p->page_size);
> > +        }
> > +    }
> > +}


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [External] Re: [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface.
  2024-03-01  1:18         ` Hao Xiang
@ 2024-03-01  5:53           ` Markus Armbruster
  0 siblings, 0 replies; 26+ messages in thread
From: Markus Armbruster @ 2024-03-01  5:53 UTC (permalink / raw)
  To: Hao Xiang
  Cc: pbonzini, berrange, eduardo, peterx, farosas, eblake, thuth,
	lvivier, jdenemar, marcel.apfelbaum, philmd, wangyanan55,
	qemu-devel

Hao Xiang <hao.xiang@bytedance.com> writes:

> On Wed, Feb 28, 2024 at 10:01 PM Markus Armbruster <armbru@redhat.com> wrote:
>>
>> Hao Xiang <hao.xiang@bytedance.com> writes:
>>
>> > On Wed, Feb 28, 2024 at 1:52 AM Markus Armbruster <armbru@redhat.com> wrote:
>> >>
>> >> Hao Xiang <hao.xiang@bytedance.com> writes:
>> >>
>> >> > This change extends the MigrationStatus interface to track zero pages
>> >> > and zero bytes counter.
>> >> >
>> >> > Signed-off-by: Hao Xiang <hao.xiang@bytedance.com>
>> >>
>> >> [...]
>> >>
>> >> > diff --git a/qapi/migration.json b/qapi/migration.json
>> >> > index a0a85a0312..171734c07e 100644
>> >> > --- a/qapi/migration.json
>> >> > +++ b/qapi/migration.json
>> >> > @@ -63,6 +63,10 @@
>> >> >  #     between 0 and @dirty-sync-count * @multifd-channels.  (since
>> >> >  #     7.1)
>> >> >  #
>> >> > +# @zero-pages: number of zero pages (since 9.0)
>> >> > +#
>> >> > +# @zero-bytes: number of zero bytes sent (since 9.0)
>> >> > +#
>> >>
>> >> Awfully terse.  How are these two related?
>> >
>> > Sorry I forgot to address the same feedback from the last version.
>>
>> Happens :)
>>
>> > zero-pages are the number of pages being detected as all "zero" and
>> > hence the payload isn't sent over the network. zero-bytes is basically
>> > zero-pages * page_size. It's the number of bytes migrated (but not
>> > actually sent through the network) because they are all "zero". These
>> > two are related to the existing interface below. normal and
>> > normal-bytes are the same representation of pages who are not all
>> > "zero" and are actually sent through the network.
>> >
>> > # @normal: number of normal pages (since 1.2)
>> > #
>> > # @normal-bytes: number of normal bytes sent (since 1.2)
>>
>> We also have
>>
>>   # @duplicate: number of duplicate (zero) pages (since 1.2)
>>   #
>>   # @skipped: number of skipped zero pages. Always zero, only provided for
>>   #     compatibility (since 1.5)
>>
>> Page skipping was introduced in 1.5, and withdrawn in 1.5.3 and 1.6.
>> @skipped was formally deprecated in 8.1.  It'll soon be gone, no need to
>> worry about it now.
>>
>> That leaves three values related to pages sent: @normal (and
>> @normal-bytes), @duplicate (but no @duplicate-bytes), and @zero-pages
>> (and @zero-bytes).
>>
>> I unwittingly created a naming inconsistency between @normal,
>> @duplicate, and @zero-pages when I asked you to rename @zero to
>> @zero-pages.
>>
>> The meaning of the three values is not obvious, and the doc comments
>> don't explain them.  Can you, or anybody familiar with migration,
>> explain them to me?
>>
>> MigrationStats return some values as bytes, some as pages, and some as
>> both.  I hate that.  Can we standardize on bytes?
>
> I added zero/zero-bytes because I thought they were not there. But it
> turns out "duplicate" is for that purpose. "zero/zero-bytes" is really
> additional information to "normal/normal-bytes". Peter suggested that
> if we add "zero/zero-bytes" we can slowly retire "duplicate" at a
> later point.

"zero" is a better name than "duplicate".  Identical non-zero pages are
possible, and they are duplicates, too.

If you add @zero with the intent to replace @duplicate, you should
immediately deprecate @duplicate.  If you need assistance with that,
just ask.

> I don't know the historical reason why pages/bytes are used the way it
> is today. The way I understand migration, the granularity of ram
> migration is "page". There are only two types of pages 1) normal 2)
> zero. Zero pages' playload are not sent through the network because we
> already know what it looks like. Only the page offset is sent. Normal
> pages are pages that are not zero. The entire page is sent through the
> network to the target host.

This is not at all clear from the documentation of MigrationStats.  I
think the documentation needs improvement there.

>                             if a user knows the zero/normal count,
> they can already calculate the zero-bytes/normal-bytes (zero/normal *
> page size)

Yes, because member @page-size tells them the multiplier.

>            but it's just convenient to see both. During development, I
> check on these counters a lot and they are useful.

QMP is for machines.  Machines don't need or want the same quantity in
two units.  Providing them both bytes and pages is a design mistake.
Whether it's worth correcting now is of course debatable.

Regardless, the fact @normal-bytes = @normal * @page-size needs to be
documented.  We have

    # @page-size: The number of bytes per page for the various page-based
    #     statistics (since 2.10)

The fact that I inquired how zero-pages and zero-bytes are related might
indicate that this isn't quite clear enough.

[...]



^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2024-03-01  5:54 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-26 19:56 [PATCH v3 0/7] Introduce multifd zero page checking Hao Xiang
2024-02-26 19:56 ` [PATCH v3 1/7] migration/multifd: Add new migration option zero-page-detection Hao Xiang
2024-02-28  9:43   ` Markus Armbruster
2024-02-28 18:30     ` [External] " Hao Xiang
2024-02-29  5:34       ` Markus Armbruster
2024-02-26 19:56 ` [PATCH v3 2/7] migration/multifd: Implement zero page transmission on the multifd thread Hao Xiang
2024-02-28  9:45   ` Markus Armbruster
2024-02-28  9:50   ` Markus Armbruster
2024-02-28 18:45     ` [External] " Hao Xiang
2024-02-29  5:41       ` Markus Armbruster
2024-02-29 15:46         ` Fabiano Rosas
2024-03-01  1:27           ` Hao Xiang
2024-02-28 19:46   ` Fabiano Rosas
2024-03-01  1:55     ` [External] " Hao Xiang
2024-02-26 19:56 ` [PATCH v3 3/7] migration/multifd: Implement ram_save_target_page_multifd to handle multifd version of MigrationOps::ram_save_target_page Hao Xiang
2024-02-28 19:48   ` Fabiano Rosas
2024-02-26 19:56 ` [PATCH v3 4/7] migration/multifd: Enable multifd zero page checking by default Hao Xiang
2024-02-26 19:56 ` [PATCH v3 5/7] migration/multifd: Add new migration test cases for legacy zero page checking Hao Xiang
2024-02-26 19:56 ` [PATCH v3 6/7] migration/multifd: Add zero pages and zero bytes counter to migration status interface Hao Xiang
2024-02-28  9:52   ` Markus Armbruster
2024-02-28 18:36     ` [External] " Hao Xiang
2024-02-29  6:01       ` Markus Armbruster
2024-03-01  1:18         ` Hao Xiang
2024-03-01  5:53           ` Markus Armbruster
2024-02-26 19:56 ` [PATCH v3 7/7] Update maintainer contact for migration multifd zero page checking acceleration Hao Xiang
2024-02-28  9:36 ` [PATCH v3 0/7] Introduce multifd zero page checking Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).