All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/11] Multifd zero page support
@ 2023-01-30  8:09 Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 01/11] migration: Update atomic stats out of the mutex Juan Quintela
                   ` (10 more replies)
  0 siblings, 11 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Based on top of my next branch.
- Rebased on top of latest upstream
- Redo a lot of the packet accounting
  still not completely perfect, but much better than what is upstream

Still working continuing on that.

Please review.

[v2]
- rebased on top of latest upstream
- lots of minor fixes
- start support for atomic counters
  * we need to move ram_limit_used/max to migration.c
  * that means fixing rdma.c
  * and test-vmstate.

So I am donig that right now.

Juan Quintela (11):
  migration: Update atomic stats out of the mutex
  migration: Make multifd_bytes atomic
  multifd: We already account for this packet on the multifd thread
  multifd: Count the number of bytes sent correctly
  migration: Make ram_save_target_page() a pointer
  multifd: Make flags field thread local
  multifd: Prepare to send a packet without the mutex held
  multifd: Add capability to enable/disable zero_page
  multifd: Support for zero pages transmission
  multifd: Zero pages transmission
  So we use multifd to transmit zero pages.

 qapi/migration.json    |   8 ++-
 migration/migration.h  |   1 +
 migration/multifd.h    |  36 ++++++++++--
 migration/ram.h        |   1 +
 hw/core/machine.c      |   1 +
 migration/migration.c  |  16 +++++-
 migration/multifd.c    | 123 +++++++++++++++++++++++++++++++----------
 migration/ram.c        |  51 +++++++++++++++--
 migration/trace-events |   8 +--
 9 files changed, 197 insertions(+), 48 deletions(-)

-- 
2.39.1



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

* [PATCH v2 01/11] migration: Update atomic stats out of the mutex
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 02/11] migration: Make multifd_bytes atomic Juan Quintela
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/multifd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/migration/multifd.c b/migration/multifd.c
index 000ca4d4ec..20a81cd7f2 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -432,8 +432,8 @@ static int multifd_send_pages(QEMUFile *f)
     transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
     qemu_file_acct_rate_limit(f, transferred);
     ram_counters.multifd_bytes += transferred;
+    qemu_mutex_unlock(&p->mutex);
     stat64_add(&ram_atomic_counters.transferred, transferred);
-    qemu_mutex_unlock(&p->mutex);
     qemu_sem_post(&p->sem);
 
     return 1;
@@ -624,8 +624,8 @@ int multifd_send_sync_main(QEMUFile *f)
         p->pending_job++;
         qemu_file_acct_rate_limit(f, p->packet_len);
         ram_counters.multifd_bytes += p->packet_len;
+        qemu_mutex_unlock(&p->mutex);
         stat64_add(&ram_atomic_counters.transferred, p->packet_len);
-        qemu_mutex_unlock(&p->mutex);
         qemu_sem_post(&p->sem);
 
         if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) {
-- 
2.39.1



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

* [PATCH v2 02/11] migration: Make multifd_bytes atomic
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 01/11] migration: Update atomic stats out of the mutex Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 03/11] multifd: We already account for this packet on the multifd thread Juan Quintela
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

In the spirit of:

commit 394d323bc3451e4d07f13341cb8817fac8dfbadd
Author: Peter Xu <peterx@redhat.com>
Date:   Tue Oct 11 17:55:51 2022 -0400

    migration: Use atomic ops properly for page accountings

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/ram.h       | 1 +
 migration/migration.c | 4 ++--
 migration/multifd.c   | 4 ++--
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/migration/ram.h b/migration/ram.h
index 81cbb0947c..3c1de6aedf 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -50,6 +50,7 @@ typedef struct {
     Stat64 duplicate;
     Stat64 normal;
     Stat64 postcopy_bytes;
+    Stat64 multifd_bytes;
 } MigrationAtomicStats;
 
 extern MigrationAtomicStats ram_atomic_counters;
diff --git a/migration/migration.c b/migration/migration.c
index 644c61e91d..d261c7d16d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1058,7 +1058,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
             ram_counters.dirty_sync_missed_zero_copy;
     info->ram->postcopy_requests = ram_counters.postcopy_requests;
     info->ram->page_size = page_size;
-    info->ram->multifd_bytes = ram_counters.multifd_bytes;
+    info->ram->multifd_bytes = stat64_get(&ram_atomic_counters.multifd_bytes);
     info->ram->pages_per_second = s->pages_per_second;
     info->ram->precopy_bytes = ram_counters.precopy_bytes;
     info->ram->downtime_bytes = ram_counters.downtime_bytes;
@@ -3659,7 +3659,7 @@ static MigThrError migration_detect_error(MigrationState *s)
 static uint64_t migration_total_bytes(MigrationState *s)
 {
     return qemu_file_total_transferred(s->to_dst_file) +
-        ram_counters.multifd_bytes;
+        stat64_get(&ram_atomic_counters.multifd_bytes);
 }
 
 static void migration_calculate_complete(MigrationState *s)
diff --git a/migration/multifd.c b/migration/multifd.c
index 20a81cd7f2..49fa76e5e1 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -431,8 +431,8 @@ static int multifd_send_pages(QEMUFile *f)
     p->pages = pages;
     transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
     qemu_file_acct_rate_limit(f, transferred);
-    ram_counters.multifd_bytes += transferred;
     qemu_mutex_unlock(&p->mutex);
+    stat64_add(&ram_atomic_counters.multifd_bytes, transferred);
     stat64_add(&ram_atomic_counters.transferred, transferred);
     qemu_sem_post(&p->sem);
 
@@ -623,8 +623,8 @@ int multifd_send_sync_main(QEMUFile *f)
         p->flags |= MULTIFD_FLAG_SYNC;
         p->pending_job++;
         qemu_file_acct_rate_limit(f, p->packet_len);
-        ram_counters.multifd_bytes += p->packet_len;
         qemu_mutex_unlock(&p->mutex);
+        stat64_add(&ram_atomic_counters.multifd_bytes, p->packet_len);
         stat64_add(&ram_atomic_counters.transferred, p->packet_len);
         qemu_sem_post(&p->sem);
 
-- 
2.39.1



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

* [PATCH v2 03/11] multifd: We already account for this packet on the multifd thread
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 01/11] migration: Update atomic stats out of the mutex Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 02/11] migration: Make multifd_bytes atomic Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 04/11] multifd: Count the number of bytes sent correctly Juan Quintela
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/multifd.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/migration/multifd.c b/migration/multifd.c
index 49fa76e5e1..61cafe4c76 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -622,10 +622,7 @@ int multifd_send_sync_main(QEMUFile *f)
         p->packet_num = multifd_send_state->packet_num++;
         p->flags |= MULTIFD_FLAG_SYNC;
         p->pending_job++;
-        qemu_file_acct_rate_limit(f, p->packet_len);
         qemu_mutex_unlock(&p->mutex);
-        stat64_add(&ram_atomic_counters.multifd_bytes, p->packet_len);
-        stat64_add(&ram_atomic_counters.transferred, p->packet_len);
         qemu_sem_post(&p->sem);
 
         if (flush_zero_copy && p->c && (multifd_zero_copy_flush(p->c) < 0)) {
-- 
2.39.1



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

* [PATCH v2 04/11] multifd: Count the number of bytes sent correctly
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (2 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 03/11] multifd: We already account for this packet on the multifd thread Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-06-16  8:53   ` Chuang Xu
  2023-01-30  8:09 ` [PATCH v2 05/11] migration: Make ram_save_target_page() a pointer Juan Quintela
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Current code asumes that all pages are whole.  That is not true for
example for compression already.  Fix it for creating a new field
->sent_bytes that includes it.

All ram_counters are used only from the migration thread, so we have
two options:
- put a mutex and fill everything when we sent it (not only
  ram_counters, also qemu_file->xfer_bytes).
- Create a local variable that implements how much has been sent
  through each channel.  And when we push another packet, we "add" the
  previous stats.

I choose two due to less changes overall.  On the previous code we
increase transferred and then we sent.  Current code goes the other
way around.  It sents the data, and after the fact, it updates the
counters.  Notice that each channel can have a maximum of half a
megabyte of data without counting, so it is not very important.

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/multifd.h | 2 ++
 migration/multifd.c | 6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/migration/multifd.h b/migration/multifd.h
index e2802a9ce2..36f899c56f 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -102,6 +102,8 @@ typedef struct {
     uint32_t flags;
     /* global number of generated multifd packets */
     uint64_t packet_num;
+    /* How many bytes have we sent on the last packet */
+    uint64_t sent_bytes;
     /* thread has work to do */
     int pending_job;
     /* array of pages to sent.
diff --git a/migration/multifd.c b/migration/multifd.c
index 61cafe4c76..cd26b2fda9 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -394,7 +394,6 @@ static int multifd_send_pages(QEMUFile *f)
     static int next_channel;
     MultiFDSendParams *p = NULL; /* make happy gcc */
     MultiFDPages_t *pages = multifd_send_state->pages;
-    uint64_t transferred;
 
     if (qatomic_read(&multifd_send_state->exiting)) {
         return -1;
@@ -429,7 +428,8 @@ static int multifd_send_pages(QEMUFile *f)
     p->packet_num = multifd_send_state->packet_num++;
     multifd_send_state->pages = p->pages;
     p->pages = pages;
-    transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
+    uint64_t transferred = p->sent_bytes;
+    p->sent_bytes = 0;
     qemu_file_acct_rate_limit(f, transferred);
     qemu_mutex_unlock(&p->mutex);
     stat64_add(&ram_atomic_counters.multifd_bytes, transferred);
@@ -719,6 +719,8 @@ static void *multifd_send_thread(void *opaque)
             }
 
             qemu_mutex_lock(&p->mutex);
+            p->sent_bytes += p->packet_len;
+            p->sent_bytes += p->next_packet_size;
             p->pending_job--;
             qemu_mutex_unlock(&p->mutex);
 
-- 
2.39.1



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

* [PATCH v2 05/11] migration: Make ram_save_target_page() a pointer
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (3 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 04/11] multifd: Count the number of bytes sent correctly Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 06/11] multifd: Make flags field thread local Juan Quintela
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

We are going to create a new function for multifd latest in the series.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
---
 migration/ram.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index 885d7dbf23..04e1093cdc 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -450,6 +450,13 @@ void dirty_sync_missed_zero_copy(void)
     ram_counters.dirty_sync_missed_zero_copy++;
 }
 
+struct MigrationOps {
+    int (*ram_save_target_page)(RAMState *rs, PageSearchStatus *pss);
+};
+typedef struct MigrationOps MigrationOps;
+
+MigrationOps *migration_ops;
+
 CompressionStats compression_counters;
 
 struct CompressParam {
@@ -2265,14 +2272,14 @@ static bool save_compress_page(RAMState *rs, PageSearchStatus *pss,
 }
 
 /**
- * ram_save_target_page: save one target page
+ * ram_save_target_page_legacy: save one target page
  *
  * Returns the number of pages written
  *
  * @rs: current RAM state
  * @pss: data about the page we want to send
  */
-static int ram_save_target_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;
@@ -2398,7 +2405,7 @@ static int ram_save_host_page_urgent(PageSearchStatus *pss)
 
         if (page_dirty) {
             /* Be strict to return code; it must be 1, or what else? */
-            if (ram_save_target_page(rs, pss) != 1) {
+            if (migration_ops->ram_save_target_page(rs, pss) != 1) {
                 error_report_once("%s: ram_save_target_page failed", __func__);
                 ret = -1;
                 goto out;
@@ -2467,7 +2474,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss)
             if (preempt_active) {
                 qemu_mutex_unlock(&rs->bitmap_mutex);
             }
-            tmppages = ram_save_target_page(rs, pss);
+            tmppages = migration_ops->ram_save_target_page(rs, pss);
             if (tmppages >= 0) {
                 pages += tmppages;
                 /*
@@ -2662,6 +2669,8 @@ static void ram_save_cleanup(void *opaque)
     xbzrle_cleanup();
     compress_threads_save_cleanup();
     ram_state_cleanup(rsp);
+    g_free(migration_ops);
+    migration_ops = NULL;
 }
 
 static void ram_state_reset(RAMState *rs)
@@ -3215,6 +3224,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
     ram_control_before_iterate(f, RAM_CONTROL_SETUP);
     ram_control_after_iterate(f, RAM_CONTROL_SETUP);
 
+    migration_ops = g_malloc0(sizeof(MigrationOps));
+    migration_ops->ram_save_target_page = ram_save_target_page_legacy;
     ret =  multifd_send_sync_main(f);
     if (ret < 0) {
         return ret;
-- 
2.39.1



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

* [PATCH v2 06/11] multifd: Make flags field thread local
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (4 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 05/11] migration: Make ram_save_target_page() a pointer Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 07/11] multifd: Prepare to send a packet without the mutex held Juan Quintela
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Use of flags with respect to locking was incensistant.  For the
sending side:
- it was set to 0 with mutex held on the multifd channel.
- MULTIFD_FLAG_SYNC was set with mutex held on the migration thread.
- Everything else was done without the mutex held on the multifd channel.

On the reception side, it is not used on the migration thread, only on
the multifd channels threads.

So we move it to the multifd channels thread only variables, and we
introduce a new bool sync_needed on the send side to pass that information.

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/multifd.h | 10 ++++++----
 migration/multifd.c | 23 +++++++++++++----------
 2 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/migration/multifd.h b/migration/multifd.h
index 36f899c56f..a67cefc0a2 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -98,12 +98,12 @@ typedef struct {
     bool running;
     /* should this thread finish */
     bool quit;
-    /* multifd flags for each packet */
-    uint32_t flags;
     /* global number of generated multifd packets */
     uint64_t packet_num;
     /* How many bytes have we sent on the last packet */
     uint64_t sent_bytes;
+    /* Do we need to do an iteration sync */
+    bool sync_needed;
     /* thread has work to do */
     int pending_job;
     /* array of pages to sent.
@@ -117,6 +117,8 @@ typedef struct {
 
     /* pointer to the packet */
     MultiFDPacket_t *packet;
+    /* multifd flags for each packet */
+    uint32_t flags;
     /* size of the next packet that contains pages */
     uint32_t next_packet_size;
     /* packets sent through this channel */
@@ -163,8 +165,6 @@ typedef struct {
     bool running;
     /* should this thread finish */
     bool quit;
-    /* multifd flags for each packet */
-    uint32_t flags;
     /* global number of generated multifd packets */
     uint64_t packet_num;
 
@@ -172,6 +172,8 @@ typedef struct {
 
     /* pointer to the packet */
     MultiFDPacket_t *packet;
+    /* multifd flags for each packet */
+    uint32_t flags;
     /* size of the next packet that contains pages */
     uint32_t next_packet_size;
     /* packets sent through this channel */
diff --git a/migration/multifd.c b/migration/multifd.c
index cd26b2fda9..77196a55b4 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -620,7 +620,7 @@ int multifd_send_sync_main(QEMUFile *f)
         }
 
         p->packet_num = multifd_send_state->packet_num++;
-        p->flags |= MULTIFD_FLAG_SYNC;
+        p->sync_needed = true;
         p->pending_job++;
         qemu_mutex_unlock(&p->mutex);
         qemu_sem_post(&p->sem);
@@ -667,7 +667,11 @@ static void *multifd_send_thread(void *opaque)
 
         if (p->pending_job) {
             uint64_t packet_num = p->packet_num;
-            uint32_t flags = p->flags;
+            p->flags = 0;
+            if (p->sync_needed) {
+                p->flags |= MULTIFD_FLAG_SYNC;
+                p->sync_needed = false;
+            }
             p->normal_num = 0;
 
             if (use_zero_copy_send) {
@@ -689,14 +693,13 @@ static void *multifd_send_thread(void *opaque)
                 }
             }
             multifd_send_fill_packet(p);
-            p->flags = 0;
             p->num_packets++;
             p->total_normal_pages += p->normal_num;
             p->pages->num = 0;
             p->pages->block = NULL;
             qemu_mutex_unlock(&p->mutex);
 
-            trace_multifd_send(p->id, packet_num, p->normal_num, flags,
+            trace_multifd_send(p->id, packet_num, p->normal_num, p->flags,
                                p->next_packet_size);
 
             if (use_zero_copy_send) {
@@ -724,7 +727,7 @@ static void *multifd_send_thread(void *opaque)
             p->pending_job--;
             qemu_mutex_unlock(&p->mutex);
 
-            if (flags & MULTIFD_FLAG_SYNC) {
+            if (p->flags & MULTIFD_FLAG_SYNC) {
                 qemu_sem_post(&p->sem_sync);
             }
             qemu_sem_post(&multifd_send_state->channels_ready);
@@ -1099,7 +1102,7 @@ static void *multifd_recv_thread(void *opaque)
     rcu_register_thread();
 
     while (true) {
-        uint32_t flags;
+        bool sync_needed = false;
 
         if (p->quit) {
             break;
@@ -1121,11 +1124,11 @@ static void *multifd_recv_thread(void *opaque)
             break;
         }
 
-        flags = p->flags;
+        trace_multifd_recv(p->id, p->packet_num, p->normal_num, p->flags,
+                           p->next_packet_size);
+        sync_needed = p->flags & MULTIFD_FLAG_SYNC;
         /* recv methods don't know how to handle the SYNC flag */
         p->flags &= ~MULTIFD_FLAG_SYNC;
-        trace_multifd_recv(p->id, p->packet_num, p->normal_num, flags,
-                           p->next_packet_size);
         p->num_packets++;
         p->total_normal_pages += p->normal_num;
         qemu_mutex_unlock(&p->mutex);
@@ -1137,7 +1140,7 @@ static void *multifd_recv_thread(void *opaque)
             }
         }
 
-        if (flags & MULTIFD_FLAG_SYNC) {
+        if (sync_needed) {
             qemu_sem_post(&multifd_recv_state->sem_sync);
             qemu_sem_wait(&p->sem_sync);
         }
-- 
2.39.1



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

* [PATCH v2 07/11] multifd: Prepare to send a packet without the mutex held
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (5 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 06/11] multifd: Make flags field thread local Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page Juan Quintela
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

We do the send_prepare() and the fill of the head packet without the
mutex held.  It will help a lot for compression and later in the
series for zero pages.

Notice that we can use p->pages without holding p->mutex because
p->pending_job == 1.

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 migration/multifd.h |  2 ++
 migration/multifd.c | 12 ++++++------
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/migration/multifd.h b/migration/multifd.h
index a67cefc0a2..cd389d18d2 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -109,7 +109,9 @@ typedef struct {
     /* array of pages to sent.
      * The owner of 'pages' depends of 'pending_job' value:
      * pending_job == 0 -> migration_thread can use it.
+     *                     No need for mutex lock.
      * pending_job != 0 -> multifd_channel can use it.
+     *                     No need for mutex lock.
      */
     MultiFDPages_t *pages;
 
diff --git a/migration/multifd.c b/migration/multifd.c
index 77196a55b4..7ebaca6e55 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -672,6 +672,8 @@ static void *multifd_send_thread(void *opaque)
                 p->flags |= MULTIFD_FLAG_SYNC;
                 p->sync_needed = false;
             }
+            qemu_mutex_unlock(&p->mutex);
+
             p->normal_num = 0;
 
             if (use_zero_copy_send) {
@@ -688,16 +690,10 @@ static void *multifd_send_thread(void *opaque)
             if (p->normal_num) {
                 ret = multifd_send_state->ops->send_prepare(p, &local_err);
                 if (ret != 0) {
-                    qemu_mutex_unlock(&p->mutex);
                     break;
                 }
             }
             multifd_send_fill_packet(p);
-            p->num_packets++;
-            p->total_normal_pages += p->normal_num;
-            p->pages->num = 0;
-            p->pages->block = NULL;
-            qemu_mutex_unlock(&p->mutex);
 
             trace_multifd_send(p->id, packet_num, p->normal_num, p->flags,
                                p->next_packet_size);
@@ -722,6 +718,10 @@ static void *multifd_send_thread(void *opaque)
             }
 
             qemu_mutex_lock(&p->mutex);
+            p->num_packets++;
+            p->total_normal_pages += p->normal_num;
+            p->pages->num = 0;
+            p->pages->block = NULL;
             p->sent_bytes += p->packet_len;
             p->sent_bytes += p->next_packet_size;
             p->pending_job--;
-- 
2.39.1



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

* [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (6 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 07/11] multifd: Prepare to send a packet without the mutex held Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  9:37   ` Markus Armbruster
  2023-01-30  8:09 ` [PATCH v2 09/11] multifd: Support for zero pages transmission Juan Quintela
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

We have to enable it by default until we introduce the new code.

Signed-off-by: Juan Quintela <quintela@redhat.com>

---

Change it to a capability.  As capabilities are off by default, have
to change MULTIFD_ZERO_PAGE to MAIN_ZERO_PAGE, so it is false for
default, and true for older versions.
---
 qapi/migration.json   |  8 +++++++-
 migration/migration.h |  1 +
 hw/core/machine.c     |  1 +
 migration/migration.c | 13 ++++++++++++-
 4 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index 88ecf86ac8..ac5bc071a9 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -472,12 +472,18 @@
 #                  Requires that QEMU be permitted to use locked memory
 #                  for guest RAM pages.
 #                  (since 7.1)
+#
 # @postcopy-preempt: If enabled, the migration process will allow postcopy
 #                    requests to preempt precopy stream, so postcopy requests
 #                    will be handled faster.  This is a performance feature and
 #                    should not affect the correctness of postcopy migration.
 #                    (since 7.1)
 #
+# @main-zero-page: If enabled, the detection of zero pages will be
+#                  done on the main thread.  Otherwise it is done on
+#                  the multifd threads.
+#                  (since 8.0)
+#
 # Features:
 # @unstable: Members @x-colo and @x-ignore-shared are experimental.
 #
@@ -492,7 +498,7 @@
            'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
            { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
            'validate-uuid', 'background-snapshot',
-           'zero-copy-send', 'postcopy-preempt'] }
+           'zero-copy-send', 'postcopy-preempt', 'main-zero-page'] }
 
 ##
 # @MigrationCapabilityStatus:
diff --git a/migration/migration.h b/migration/migration.h
index ae4ffd3454..c38a0baf10 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -408,6 +408,7 @@ int migrate_multifd_channels(void);
 MultiFDCompression migrate_multifd_compression(void);
 int migrate_multifd_zlib_level(void);
 int migrate_multifd_zstd_level(void);
+bool migrate_use_main_zero_page(void);
 
 #ifdef CONFIG_LINUX
 bool migrate_use_zero_copy_send(void);
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 616f3a207c..97149e2de3 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -52,6 +52,7 @@ const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1);
 GlobalProperty hw_compat_7_0[] = {
     { "arm-gicv3-common", "force-8-bit-prio", "on" },
     { "nvme-ns", "eui64-default", "on"},
+    { "migration", "main-zero-page", "true" },
 };
 const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
 
diff --git a/migration/migration.c b/migration/migration.c
index d261c7d16d..ab86c6601d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -164,7 +164,8 @@ INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
     MIGRATION_CAPABILITY_XBZRLE,
     MIGRATION_CAPABILITY_X_COLO,
     MIGRATION_CAPABILITY_VALIDATE_UUID,
-    MIGRATION_CAPABILITY_ZERO_COPY_SEND);
+    MIGRATION_CAPABILITY_ZERO_COPY_SEND,
+    MIGRATION_CAPABILITY_MAIN_ZERO_PAGE);
 
 /* When we add fault tolerance, we could have several
    migrations at once.  For now we don't need to add
@@ -2603,6 +2604,14 @@ bool migrate_use_multifd(void)
     return s->enabled_capabilities[MIGRATION_CAPABILITY_MULTIFD];
 }
 
+bool migrate_use_main_zero_page(void)
+{
+    MigrationState *s = migrate_get_current();
+
+    /* We will enable this when we add the right code. */
+    return true || s->enabled_capabilities[MIGRATION_CAPABILITY_MAIN_ZERO_PAGE];
+}
+
 bool migrate_pause_before_switchover(void)
 {
     MigrationState *s;
@@ -4425,6 +4434,8 @@ static Property migration_properties[] = {
     DEFINE_PROP_MIG_CAP("x-zero-copy-send",
             MIGRATION_CAPABILITY_ZERO_COPY_SEND),
 #endif
+    DEFINE_PROP_MIG_CAP("main-zero-page",
+            MIGRATION_CAPABILITY_MAIN_ZERO_PAGE),
 
     DEFINE_PROP_END_OF_LIST(),
 };
-- 
2.39.1



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

* [PATCH v2 09/11] multifd: Support for zero pages transmission
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (7 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 10/11] multifd: Zero " Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 11/11] So we use multifd to transmit zero pages Juan Quintela
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

This patch adds counters and similar.  Logic will be added on the
following patch.

Signed-off-by: Juan Quintela <quintela@redhat.com>

---

Added counters for duplicated/non duplicated pages.
Removed reviewed by from David.
Add total_zero_pages
---
 migration/multifd.h    | 17 ++++++++++++++++-
 migration/multifd.c    | 36 +++++++++++++++++++++++++++++-------
 migration/ram.c        |  2 --
 migration/trace-events |  8 ++++----
 4 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/migration/multifd.h b/migration/multifd.h
index cd389d18d2..a1b852200d 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -47,7 +47,10 @@ 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];
     uint64_t offset[];
 } __attribute__((packed)) MultiFDPacket_t;
@@ -127,6 +130,8 @@ typedef struct {
     uint64_t num_packets;
     /* 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 */
@@ -135,6 +140,10 @@ typedef struct {
     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 compression methods */
     void *data;
 }  MultiFDSendParams;
@@ -184,12 +193,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;
diff --git a/migration/multifd.c b/migration/multifd.c
index 7ebaca6e55..30cc206190 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -263,6 +263,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
     packet->normal_pages = cpu_to_be32(p->normal_num);
     packet->next_packet_size = cpu_to_be32(p->next_packet_size);
     packet->packet_num = cpu_to_be64(p->packet_num);
+    packet->zero_pages = cpu_to_be32(p->zero_num);
 
     if (p->pages->block) {
         strncpy(packet->ramblock, p->pages->block->idstr, 256);
@@ -323,7 +324,15 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
     p->next_packet_size = be32_to_cpu(packet->next_packet_size);
     p->packet_num = be64_to_cpu(packet->packet_num);
 
-    if (p->normal_num == 0) {
+    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 pages are %u",
+                   p->zero_num, packet->pages_alloc - p->normal_num) ;
+        return -1;
+    }
+
+    if (p->normal_num == 0 && p->zero_num == 0) {
         return 0;
     }
 
@@ -428,6 +437,8 @@ static int multifd_send_pages(QEMUFile *f)
     p->packet_num = multifd_send_state->packet_num++;
     multifd_send_state->pages = p->pages;
     p->pages = pages;
+    stat64_add(&ram_atomic_counters.normal, p->normal_num);
+    stat64_add(&ram_atomic_counters.duplicate, p->zero_num);
     uint64_t transferred = p->sent_bytes;
     p->sent_bytes = 0;
     qemu_file_acct_rate_limit(f, transferred);
@@ -546,6 +557,8 @@ void multifd_save_cleanup(void)
         p->iov = NULL;
         g_free(p->normal);
         p->normal = NULL;
+        g_free(p->zero);
+        p->zero = NULL;
         multifd_send_state->ops->send_cleanup(p, &local_err);
         if (local_err) {
             migrate_set_error(migrate_get_current(), local_err);
@@ -675,6 +688,7 @@ static void *multifd_send_thread(void *opaque)
             qemu_mutex_unlock(&p->mutex);
 
             p->normal_num = 0;
+            p->zero_num = 0;
 
             if (use_zero_copy_send) {
                 p->iovs_num = 0;
@@ -695,8 +709,8 @@ static void *multifd_send_thread(void *opaque)
             }
             multifd_send_fill_packet(p);
 
-            trace_multifd_send(p->id, packet_num, p->normal_num, p->flags,
-                               p->next_packet_size);
+            trace_multifd_send(p->id, packet_num, p->normal_num, p->zero_num,
+                               p->flags, p->next_packet_size);
 
             if (use_zero_copy_send) {
                 /* Send header first, without zerocopy */
@@ -720,6 +734,7 @@ static void *multifd_send_thread(void *opaque)
             qemu_mutex_lock(&p->mutex);
             p->num_packets++;
             p->total_normal_pages += p->normal_num;
+            p->total_zero_pages += p->zero_num;
             p->pages->num = 0;
             p->pages->block = NULL;
             p->sent_bytes += p->packet_len;
@@ -761,7 +776,8 @@ out:
     qemu_mutex_unlock(&p->mutex);
 
     rcu_unregister_thread();
-    trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages);
+    trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages,
+                                  p->total_zero_pages);
 
     return NULL;
 }
@@ -946,6 +962,7 @@ int multifd_save_setup(Error **errp)
         p->normal = g_new0(ram_addr_t, page_count);
         p->page_size = qemu_target_page_size();
         p->page_count = page_count;
+        p->zero = g_new0(ram_addr_t, page_count);
 
         if (migrate_use_zero_copy_send()) {
             p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
@@ -1054,6 +1071,8 @@ int multifd_load_cleanup(Error **errp)
         p->iov = NULL;
         g_free(p->normal);
         p->normal = NULL;
+        g_free(p->zero);
+        p->zero = NULL;
         multifd_recv_state->ops->recv_cleanup(p);
     }
     qemu_sem_destroy(&multifd_recv_state->sem_sync);
@@ -1124,13 +1143,14 @@ static void *multifd_recv_thread(void *opaque)
             break;
         }
 
-        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);
         sync_needed = p->flags & MULTIFD_FLAG_SYNC;
         /* recv methods don't know how to handle the SYNC flag */
         p->flags &= ~MULTIFD_FLAG_SYNC;
         p->num_packets++;
         p->total_normal_pages += p->normal_num;
+        p->total_normal_pages += p->zero_num;
         qemu_mutex_unlock(&p->mutex);
 
         if (p->normal_num) {
@@ -1155,7 +1175,8 @@ static void *multifd_recv_thread(void *opaque)
     qemu_mutex_unlock(&p->mutex);
 
     rcu_unregister_thread();
-    trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages);
+    trace_multifd_recv_thread_end(p->id, p->num_packets, p->total_normal_pages,
+                                  p->total_zero_pages);
 
     return NULL;
 }
@@ -1195,6 +1216,7 @@ int multifd_load_setup(Error **errp)
         p->normal = g_new0(ram_addr_t, page_count);
         p->page_count = page_count;
         p->page_size = qemu_target_page_size();
+        p->zero = g_new0(ram_addr_t, page_count);
     }
 
     for (i = 0; i < thread_count; i++) {
diff --git a/migration/ram.c b/migration/ram.c
index 04e1093cdc..c70cc25169 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1426,8 +1426,6 @@ static int ram_save_multifd_page(QEMUFile *file, RAMBlock *block,
     if (multifd_queue_page(file, block, offset) < 0) {
         return -1;
     }
-    stat64_add(&ram_atomic_counters.normal, 1);
-
     return 1;
 }
 
diff --git a/migration/trace-events b/migration/trace-events
index 67b65a70ff..3e85354dd1 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -121,21 +121,21 @@ postcopy_preempt_reset_channel(void) ""
 
 # multifd.c
 multifd_new_send_channel_async(uint8_t id) "channel %u"
-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 normalpages, 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(bool error) "error %d"
-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"
-- 
2.39.1



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

* [PATCH v2 10/11] multifd: Zero pages transmission
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (8 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 09/11] multifd: Support for zero pages transmission Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  2023-01-30  8:09 ` [PATCH v2 11/11] So we use multifd to transmit zero pages Juan Quintela
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

This implements the zero page dection and handling.

Signed-off-by: Juan Quintela <quintela@redhat.com>

---

Add comment for offset (dave)
Use local variables for offset/block to have shorter lines
---
 migration/multifd.h |  5 +++++
 migration/multifd.c | 45 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/migration/multifd.h b/migration/multifd.h
index a1b852200d..5931de6f86 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -52,6 +52,11 @@ typedef struct {
     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;
 
diff --git a/migration/multifd.c b/migration/multifd.c
index 30cc206190..d3f82dad8a 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"
@@ -275,6 +276,12 @@ static void multifd_send_fill_packet(MultiFDSendParams *p)
 
         packet->offset[i] = cpu_to_be64(temp);
     }
+    for (i = 0; i < p->zero_num; i++) {
+        /* there are architectures where ram_addr_t is 32 bit */
+        uint64_t temp = p->zero[i];
+
+        packet->offset[p->normal_num + i] = cpu_to_be64(temp);
+    }
 }
 
 static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
@@ -358,6 +365,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 > (block->used_length - p->page_size)) {
+            error_setg(errp, "multifd: offset too long %" PRIu64
+                       " (max " RAM_ADDR_FMT ")",
+                       offset, block->used_length);
+            return -1;
+        }
+        p->zero[i] = offset;
+    }
+
     return 0;
 }
 
@@ -657,6 +676,12 @@ static void *multifd_send_thread(void *opaque)
 {
     MultiFDSendParams *p = opaque;
     Error *local_err = NULL;
+    /*
+     * older qemu don't understand zero page on multifd channel.  To
+     * have capabilities "false" by default, we need to name it this
+     * way.
+     */
+    bool use_multifd_zero_page = !migrate_use_main_zero_page();
     int ret = 0;
     bool use_zero_copy_send = migrate_use_zero_copy_send();
 
@@ -679,6 +704,7 @@ static void *multifd_send_thread(void *opaque)
         qemu_mutex_lock(&p->mutex);
 
         if (p->pending_job) {
+            RAMBlock *rb = p->pages->block;
             uint64_t packet_num = p->packet_num;
             p->flags = 0;
             if (p->sync_needed) {
@@ -697,8 +723,16 @@ static void *multifd_send_thread(void *opaque)
             }
 
             for (int i = 0; i < p->pages->num; i++) {
-                p->normal[p->normal_num] = p->pages->offset[i];
-                p->normal_num++;
+                uint64_t offset = p->pages->offset[i];
+                if (use_multifd_zero_page &&
+                    buffer_is_zero(rb->host + offset, p->page_size)) {
+                    p->zero[p->zero_num] = offset;
+                    p->zero_num++;
+                    ram_release_page(rb->idstr, offset);
+                } else {
+                    p->normal[p->normal_num] = offset;
+                    p->normal_num++;
+                }
             }
 
             if (p->normal_num) {
@@ -1160,6 +1194,13 @@ static void *multifd_recv_thread(void *opaque)
             }
         }
 
+        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);
+            }
+        }
+
         if (sync_needed) {
             qemu_sem_post(&multifd_recv_state->sem_sync);
             qemu_sem_wait(&p->sem_sync);
-- 
2.39.1



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

* [PATCH v2 11/11] So we use multifd to transmit zero pages.
  2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
                   ` (9 preceding siblings ...)
  2023-01-30  8:09 ` [PATCH v2 10/11] multifd: Zero " Juan Quintela
@ 2023-01-30  8:09 ` Juan Quintela
  10 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30  8:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Juan Quintela, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Signed-off-by: Juan Quintela <quintela@redhat.com>

---

- Check zero_page property before using new code (Dave)
---
 migration/migration.c |  3 +--
 migration/ram.c       | 32 +++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index ab86c6601d..6293dee983 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2608,8 +2608,7 @@ bool migrate_use_main_zero_page(void)
 {
     MigrationState *s = migrate_get_current();
 
-    /* We will enable this when we add the right code. */
-    return true || s->enabled_capabilities[MIGRATION_CAPABILITY_MAIN_ZERO_PAGE];
+    return s->enabled_capabilities[MIGRATION_CAPABILITY_MAIN_ZERO_PAGE];
 }
 
 bool migrate_pause_before_switchover(void)
diff --git a/migration/ram.c b/migration/ram.c
index c70cc25169..d375f2ccde 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2421,6 +2421,31 @@ out:
     return ret;
 }
 
+/**
+ * ram_save_target_page_multifd: save one target page
+ *
+ * Returns the number of pages written
+ *
+ * @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;
+
+    if (!migration_in_postcopy()) {
+        return ram_save_multifd_page(pss->pss_channel, block, offset);
+    }
+
+    int res = save_zero_page(pss, block, offset);
+    if (res > 0) {
+        return res;
+    }
+
+    return ram_save_page(rs, pss);
+}
+
 /**
  * ram_save_host_page: save a whole host page
  *
@@ -3223,7 +3248,12 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
     ram_control_after_iterate(f, RAM_CONTROL_SETUP);
 
     migration_ops = g_malloc0(sizeof(MigrationOps));
-    migration_ops->ram_save_target_page = ram_save_target_page_legacy;
+    if (migrate_use_multifd() && !migrate_use_main_zero_page()) {
+        migration_ops->ram_save_target_page = ram_save_target_page_multifd;
+    } else {
+        migration_ops->ram_save_target_page = ram_save_target_page_legacy;
+    }
+
     ret =  multifd_send_sync_main(f);
     if (ret < 0) {
         return ret;
-- 
2.39.1



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

* Re: [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page
  2023-01-30  8:09 ` [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page Juan Quintela
@ 2023-01-30  9:37   ` Markus Armbruster
  2023-01-30 14:06     ` Juan Quintela
  2023-01-30 14:06     ` Juan Quintela
  0 siblings, 2 replies; 17+ messages in thread
From: Markus Armbruster @ 2023-01-30  9:37 UTC (permalink / raw)
  To: Juan Quintela
  Cc: qemu-devel, Marcel Apfelbaum, Yanan Wang,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Juan Quintela <quintela@redhat.com> writes:

> We have to enable it by default until we introduce the new code.
>
> Signed-off-by: Juan Quintela <quintela@redhat.com>

The subject doesn't quite match the patch to the QAPI schema.  It claims
"capability to enable/disable zero_page", but ...

> ---
>
> Change it to a capability.  As capabilities are off by default, have
> to change MULTIFD_ZERO_PAGE to MAIN_ZERO_PAGE, so it is false for
> default, and true for older versions.
> ---
>  qapi/migration.json   |  8 +++++++-
>  migration/migration.h |  1 +
>  hw/core/machine.c     |  1 +
>  migration/migration.c | 13 ++++++++++++-
>  4 files changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 88ecf86ac8..ac5bc071a9 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -472,12 +472,18 @@
>  #                  Requires that QEMU be permitted to use locked memory
>  #                  for guest RAM pages.
>  #                  (since 7.1)
> +#
>  # @postcopy-preempt: If enabled, the migration process will allow postcopy
>  #                    requests to preempt precopy stream, so postcopy requests
>  #                    will be handled faster.  This is a performance feature and
>  #                    should not affect the correctness of postcopy migration.
>  #                    (since 7.1)
>  #
> +# @main-zero-page: If enabled, the detection of zero pages will be
> +#                  done on the main thread.  Otherwise it is done on
> +#                  the multifd threads.

... here, we add a capability to shift certain work to another thread.
No "enable/disable" as far as I can tell.  Which one is right?

What's the default?

Not this patch's fault, but needs fixing: we neglect to document the
default for several other parameters.

Wordsmithing nitpick: suggest "done by the thread" or maybe "done in the
thread".

@main-zero-page suggests this is about a special zero page.  Perhaps I
can think of a clearer name, but first I need to be sure what the thing
is about.

> +#                  (since 8.0)
> +#
>  # Features:
>  # @unstable: Members @x-colo and @x-ignore-shared are experimental.
>  #
> @@ -492,7 +498,7 @@
>             'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
>             { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
>             'validate-uuid', 'background-snapshot',
> -           'zero-copy-send', 'postcopy-preempt'] }
> +           'zero-copy-send', 'postcopy-preempt', 'main-zero-page'] }
>  
>  ##
>  # @MigrationCapabilityStatus:



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

* Re: [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page
  2023-01-30  9:37   ` Markus Armbruster
@ 2023-01-30 14:06     ` Juan Quintela
  2023-01-30 14:06     ` Juan Quintela
  1 sibling, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30 14:06 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, Marcel Apfelbaum, Yanan Wang,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Markus Armbruster <armbru@redhat.com> wrote:
> Juan Quintela <quintela@redhat.com> writes:
>
>> We have to enable it by default until we introduce the new code.
>>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>
> The subject doesn't quite match the patch to the QAPI schema.  It claims
> "capability to enable/disable zero_page", but ...


And here I am, making a full of myself (again).

Will change the documentation/commit informatioon, what is right is the
code.

Thanks a lot.

Later, Juan.

>
>> ---
>>
>> Change it to a capability.  As capabilities are off by default, have
>> to change MULTIFD_ZERO_PAGE to MAIN_ZERO_PAGE, so it is false for
>> default, and true for older versions.
>> ---
>>  qapi/migration.json   |  8 +++++++-
>>  migration/migration.h |  1 +
>>  hw/core/machine.c     |  1 +
>>  migration/migration.c | 13 ++++++++++++-
>>  4 files changed, 21 insertions(+), 2 deletions(-)
>>
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 88ecf86ac8..ac5bc071a9 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -472,12 +472,18 @@
>>  #                  Requires that QEMU be permitted to use locked memory
>>  #                  for guest RAM pages.
>>  #                  (since 7.1)
>> +#
>>  # @postcopy-preempt: If enabled, the migration process will allow postcopy
>>  #                    requests to preempt precopy stream, so postcopy requests
>>  #                    will be handled faster.  This is a performance feature and
>>  #                    should not affect the correctness of postcopy migration.
>>  #                    (since 7.1)
>>  #
>> +# @main-zero-page: If enabled, the detection of zero pages will be
>> +#                  done on the main thread.  Otherwise it is done on
>> +#                  the multifd threads.
>
> ... here, we add a capability to shift certain work to another thread.
> No "enable/disable" as far as I can tell.  Which one is right?
>
> What's the default?
>
> Not this patch's fault, but needs fixing: we neglect to document the
> default for several other parameters.
>
> Wordsmithing nitpick: suggest "done by the thread" or maybe "done in the
> thread".
>
> @main-zero-page suggests this is about a special zero page.  Perhaps I
> can think of a clearer name, but first I need to be sure what the thing
> is about.
>
>> +#                  (since 8.0)
>> +#
>>  # Features:
>>  # @unstable: Members @x-colo and @x-ignore-shared are experimental.
>>  #
>> @@ -492,7 +498,7 @@
>>             'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
>>             { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
>>             'validate-uuid', 'background-snapshot',
>> -           'zero-copy-send', 'postcopy-preempt'] }
>> +           'zero-copy-send', 'postcopy-preempt', 'main-zero-page'] }
>>  
>>  ##
>>  # @MigrationCapabilityStatus:



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

* Re: [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page
  2023-01-30  9:37   ` Markus Armbruster
  2023-01-30 14:06     ` Juan Quintela
@ 2023-01-30 14:06     ` Juan Quintela
  1 sibling, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-01-30 14:06 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, Marcel Apfelbaum, Yanan Wang,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Markus Armbruster <armbru@redhat.com> wrote:
> Juan Quintela <quintela@redhat.com> writes:
>
>> We have to enable it by default until we introduce the new code.
>>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>
> The subject doesn't quite match the patch to the QAPI schema.  It claims
> "capability to enable/disable zero_page", but ...


And here I am, making a full of myself (again).

Will change the documentation/commit information, what is right is the
code.

Thanks a lot.

Later, Juan.

>
>> ---
>>
>> Change it to a capability.  As capabilities are off by default, have
>> to change MULTIFD_ZERO_PAGE to MAIN_ZERO_PAGE, so it is false for
>> default, and true for older versions.
>> ---
>>  qapi/migration.json   |  8 +++++++-
>>  migration/migration.h |  1 +
>>  hw/core/machine.c     |  1 +
>>  migration/migration.c | 13 ++++++++++++-
>>  4 files changed, 21 insertions(+), 2 deletions(-)
>>
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 88ecf86ac8..ac5bc071a9 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -472,12 +472,18 @@
>>  #                  Requires that QEMU be permitted to use locked memory
>>  #                  for guest RAM pages.
>>  #                  (since 7.1)
>> +#
>>  # @postcopy-preempt: If enabled, the migration process will allow postcopy
>>  #                    requests to preempt precopy stream, so postcopy requests
>>  #                    will be handled faster.  This is a performance feature and
>>  #                    should not affect the correctness of postcopy migration.
>>  #                    (since 7.1)
>>  #
>> +# @main-zero-page: If enabled, the detection of zero pages will be
>> +#                  done on the main thread.  Otherwise it is done on
>> +#                  the multifd threads.
>
> ... here, we add a capability to shift certain work to another thread.
> No "enable/disable" as far as I can tell.  Which one is right?
>
> What's the default?
>
> Not this patch's fault, but needs fixing: we neglect to document the
> default for several other parameters.
>
> Wordsmithing nitpick: suggest "done by the thread" or maybe "done in the
> thread".
>
> @main-zero-page suggests this is about a special zero page.  Perhaps I
> can think of a clearer name, but first I need to be sure what the thing
> is about.
>
>> +#                  (since 8.0)
>> +#
>>  # Features:
>>  # @unstable: Members @x-colo and @x-ignore-shared are experimental.
>>  #
>> @@ -492,7 +498,7 @@
>>             'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
>>             { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
>>             'validate-uuid', 'background-snapshot',
>> -           'zero-copy-send', 'postcopy-preempt'] }
>> +           'zero-copy-send', 'postcopy-preempt', 'main-zero-page'] }
>>  
>>  ##
>>  # @MigrationCapabilityStatus:



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

* Re: [PATCH v2 04/11] multifd: Count the number of bytes sent correctly
  2023-01-30  8:09 ` [PATCH v2 04/11] multifd: Count the number of bytes sent correctly Juan Quintela
@ 2023-06-16  8:53   ` Chuang Xu
  2023-06-21 19:49     ` Juan Quintela
  0 siblings, 1 reply; 17+ messages in thread
From: Chuang Xu @ 2023-06-16  8:53 UTC (permalink / raw)
  To: Juan Quintela
  Cc: qemu-devel, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Hi,Juan,

On 2023/1/30 下午4:09, Juan Quintela wrote:
> Current code asumes that all pages are whole.  That is not true for
> example for compression already.  Fix it for creating a new field
> ->sent_bytes that includes it.
>
> All ram_counters are used only from the migration thread, so we have
> two options:
> - put a mutex and fill everything when we sent it (not only
>    ram_counters, also qemu_file->xfer_bytes).
> - Create a local variable that implements how much has been sent
>    through each channel.  And when we push another packet, we "add" the
>    previous stats.
>
> I choose two due to less changes overall.  On the previous code we
> increase transferred and then we sent.  Current code goes the other
> way around.  It sents the data, and after the fact, it updates the
> counters.  Notice that each channel can have a maximum of half a
> megabyte of data without counting, so it is not very important.
>
> Signed-off-by: Juan Quintela <quintela@redhat.com>
> ---
>   migration/multifd.h | 2 ++
>   migration/multifd.c | 6 ++++--
>   2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/migration/multifd.h b/migration/multifd.h
> index e2802a9ce2..36f899c56f 100644
> --- a/migration/multifd.h
> +++ b/migration/multifd.h
> @@ -102,6 +102,8 @@ typedef struct {
>       uint32_t flags;
>       /* global number of generated multifd packets */
>       uint64_t packet_num;
> +    /* How many bytes have we sent on the last packet */
> +    uint64_t sent_bytes;
>       /* thread has work to do */
>       int pending_job;
>       /* array of pages to sent.
> diff --git a/migration/multifd.c b/migration/multifd.c
> index 61cafe4c76..cd26b2fda9 100644
> --- a/migration/multifd.c
> +++ b/migration/multifd.c
> @@ -394,7 +394,6 @@ static int multifd_send_pages(QEMUFile *f)
>       static int next_channel;
>       MultiFDSendParams *p = NULL; /* make happy gcc */
>       MultiFDPages_t *pages = multifd_send_state->pages;
> -    uint64_t transferred;
>
>       if (qatomic_read(&multifd_send_state->exiting)) {
>           return -1;
> @@ -429,7 +428,8 @@ static int multifd_send_pages(QEMUFile *f)
>       p->packet_num = multifd_send_state->packet_num++;
>       multifd_send_state->pages = p->pages;
>       p->pages = pages;
> -    transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
> +    uint64_t transferred = p->sent_bytes;
> +    p->sent_bytes = 0;
>       qemu_file_acct_rate_limit(f, transferred);
>       qemu_mutex_unlock(&p->mutex);
>       stat64_add(&ram_atomic_counters.multifd_bytes, transferred);
> @@ -719,6 +719,8 @@ static void *multifd_send_thread(void *opaque)
>               }
>
>               qemu_mutex_lock(&p->mutex);
> +            p->sent_bytes += p->packet_len;
> +            p->sent_bytes += p->next_packet_size;

Consider a scenario where some normal pages are transmitted in the first round,
followed by several consecutive rounds of zero pages. When zero pages
are transmitted,
next_packet_size of first round is still incorrectly added to
sent_bytes. If we set a rate
limiting for dirty page transmission, the transmission performance of
multi zero check
will degrade.

Maybe we should set next_packet_size to 0 in multifd_send_pages()?

>               p->pending_job--;
>               qemu_mutex_unlock(&p->mutex);
>


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

* Re: [PATCH v2 04/11] multifd: Count the number of bytes sent correctly
  2023-06-16  8:53   ` Chuang Xu
@ 2023-06-21 19:49     ` Juan Quintela
  0 siblings, 0 replies; 17+ messages in thread
From: Juan Quintela @ 2023-06-21 19:49 UTC (permalink / raw)
  To: Chuang Xu
  Cc: qemu-devel, Marcel Apfelbaum, Yanan Wang, Markus Armbruster,
	Philippe Mathieu-Daudé,
	Dr. David Alan Gilbert, Eduardo Habkost, Eric Blake

Chuang Xu <xuchuangxclwt@bytedance.com> wrote:
> Hi,Juan,
>
> On 2023/1/30 下午4:09, Juan Quintela wrote:
>> Current code asumes that all pages are whole.  That is not true for
>> example for compression already.  Fix it for creating a new field
>> ->sent_bytes that includes it.
>>
>> All ram_counters are used only from the migration thread, so we have
>> two options:
>> - put a mutex and fill everything when we sent it (not only
>>    ram_counters, also qemu_file->xfer_bytes).
>> - Create a local variable that implements how much has been sent
>>    through each channel.  And when we push another packet, we "add" the
>>    previous stats.
>>
>> I choose two due to less changes overall.  On the previous code we
>> increase transferred and then we sent.  Current code goes the other
>> way around.  It sents the data, and after the fact, it updates the
>> counters.  Notice that each channel can have a maximum of half a
>> megabyte of data without counting, so it is not very important.
>>
>> Signed-off-by: Juan Quintela <quintela@redhat.com>
>> ---
>>   migration/multifd.h | 2 ++
>>   migration/multifd.c | 6 ++++--
>>   2 files changed, 6 insertions(+), 2 deletions(-)
>>
>> diff --git a/migration/multifd.h b/migration/multifd.h
>> index e2802a9ce2..36f899c56f 100644
>> --- a/migration/multifd.h
>> +++ b/migration/multifd.h
>> @@ -102,6 +102,8 @@ typedef struct {
>>       uint32_t flags;
>>       /* global number of generated multifd packets */
>>       uint64_t packet_num;
>> +    /* How many bytes have we sent on the last packet */
>> +    uint64_t sent_bytes;
>>       /* thread has work to do */
>>       int pending_job;
>>       /* array of pages to sent.
>> diff --git a/migration/multifd.c b/migration/multifd.c
>> index 61cafe4c76..cd26b2fda9 100644
>> --- a/migration/multifd.c
>> +++ b/migration/multifd.c
>> @@ -394,7 +394,6 @@ static int multifd_send_pages(QEMUFile *f)
>>       static int next_channel;
>>       MultiFDSendParams *p = NULL; /* make happy gcc */
>>       MultiFDPages_t *pages = multifd_send_state->pages;
>> -    uint64_t transferred;
>>
>>       if (qatomic_read(&multifd_send_state->exiting)) {
>>           return -1;
>> @@ -429,7 +428,8 @@ static int multifd_send_pages(QEMUFile *f)
>>       p->packet_num = multifd_send_state->packet_num++;
>>       multifd_send_state->pages = p->pages;
>>       p->pages = pages;
>> -    transferred = ((uint64_t) pages->num) * p->page_size + p->packet_len;
>> +    uint64_t transferred = p->sent_bytes;
>> +    p->sent_bytes = 0;
>>       qemu_file_acct_rate_limit(f, transferred);
>>       qemu_mutex_unlock(&p->mutex);
>>       stat64_add(&ram_atomic_counters.multifd_bytes, transferred);
>> @@ -719,6 +719,8 @@ static void *multifd_send_thread(void *opaque)
>>               }
>>
>>               qemu_mutex_lock(&p->mutex);
>> +            p->sent_bytes += p->packet_len;
>> +            p->sent_bytes += p->next_packet_size;
>
> Consider a scenario where some normal pages are transmitted in the first round,
> followed by several consecutive rounds of zero pages. When zero pages
> are transmitted,
> next_packet_size of first round is still incorrectly added to
> sent_bytes. If we set a rate
> limiting for dirty page transmission, the transmission performance of
> multi zero check
> will degrade.
>
> Maybe we should set next_packet_size to 0 in multifd_send_pages()?

See my series of migration atomic counters O:-)

You are right with your comments, that is the reason why it took me so
many patches to fix it properly.

After the last serie on the list that set_bytes variable don't exist
anymore and I just do (with atomic operations):

multifd_bytes += size_of_write_just_done;

And no more sheanigans.

Thanks, Juan.



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

end of thread, other threads:[~2023-06-21 19:50 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-30  8:09 [PATCH v2 00/11] Multifd zero page support Juan Quintela
2023-01-30  8:09 ` [PATCH v2 01/11] migration: Update atomic stats out of the mutex Juan Quintela
2023-01-30  8:09 ` [PATCH v2 02/11] migration: Make multifd_bytes atomic Juan Quintela
2023-01-30  8:09 ` [PATCH v2 03/11] multifd: We already account for this packet on the multifd thread Juan Quintela
2023-01-30  8:09 ` [PATCH v2 04/11] multifd: Count the number of bytes sent correctly Juan Quintela
2023-06-16  8:53   ` Chuang Xu
2023-06-21 19:49     ` Juan Quintela
2023-01-30  8:09 ` [PATCH v2 05/11] migration: Make ram_save_target_page() a pointer Juan Quintela
2023-01-30  8:09 ` [PATCH v2 06/11] multifd: Make flags field thread local Juan Quintela
2023-01-30  8:09 ` [PATCH v2 07/11] multifd: Prepare to send a packet without the mutex held Juan Quintela
2023-01-30  8:09 ` [PATCH v2 08/11] multifd: Add capability to enable/disable zero_page Juan Quintela
2023-01-30  9:37   ` Markus Armbruster
2023-01-30 14:06     ` Juan Quintela
2023-01-30 14:06     ` Juan Quintela
2023-01-30  8:09 ` [PATCH v2 09/11] multifd: Support for zero pages transmission Juan Quintela
2023-01-30  8:09 ` [PATCH v2 10/11] multifd: Zero " Juan Quintela
2023-01-30  8:09 ` [PATCH v2 11/11] So we use multifd to transmit zero pages Juan Quintela

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.