All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] support dirtyrate measurement with dirty bitmap
@ 2021-07-12 16:56 huangy81
       [not found] ` <cover.1626108969.git.huangy81@chinatelecom.cn>
  0 siblings, 1 reply; 5+ messages in thread
From: huangy81 @ 2021-07-12 16:56 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Hyman, Dr. David Alan Gilbert,
	Peter Xu, Chuan Zheng, Paolo Bonzini

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>

v2:
- drop the DIRTY_MEMORY_DIRTY_RATE dirty bits

- reuse the DIRTY_MEMORY_MIGRATION dirty bits to stat the dirty
  pages.

- introduce global var DirtyRateIncreasedPages to stat the
  increased dirty pages

- simplify the logic of calculation. skip the 1'round of
  log sync unconditionally

changes of this version are based on Peter's advice,
like the version 1, it is posted for the sake of RFC.
ideally, this patshset may be merged after the commit:
"migration/dirtyrate: implement dirty-ring dirtyrate calculation"

v1:
the dirtyrate measurement implemented by page-sampling originally, it
is not accurate in some scenarios, so we have introduced dirty-ring
based dirtyrate measurement(maybe it will be merged soon), it fix the
accuracy of page-sampling, and more importantly, it is at the
granualrity of vcpu.

dirty-ring method can be used when dirty-ring enable, as supplementary,
we introduce dirty-bitmap method to calculating dirtyrate when dirty log
enable, so that we can also get the accurate dirtyrate if needed in the
absence of dirty-ring.

three things has done to implement the measurement:
- introduce a fresh new dirty bits named DIRTY_MEMORY_DIRTY_RATE, which
  is used to store dirty bitmap after fetching it from kvm. why we do
  not reuse the existing DIRTY_MEMORY_MIGRATION dirty bits is we do not
  want to interfere with migration of and let implementation clear, this 
  is also the reason why dirty_memory be split.

  DIRTY_MEMORY_DIRTY_RATE dirty bits will be filled when
  memory_global_dirty_log_sync executed if GLOBAL_DIRTY_DIRTY_RATE bit
  be set in the global_dirty_tracking flag.

- introduce kvm_get_manual_dirty_log_protect function so that we can
  probe the protect caps of kvm when calculating.

- implement dirtyrate measurement with dirty bitmap with following step:
  1. start the dirty log. 

  2. probe the protect cap, if KVM_DIRTY_LOG_INITIALLY_SET enable, skip
     skip the 1'R and do the reset page protection manually, since kvm
     file bitmap with 1 bits if this cap is enabled. 

  3. clear the DIRTY_MEMORY_DIRTY_RATE dirty bits, prepare to store 
     the dirty bitmap.

  4. start memory_global_dirty_log_sync and fetch dirty bitmap from kvm

  5. reap the DIRTY_MEMORY_DIRTY_RATE dirty bits and do the calculation.

this patchset rebases on the commit 
"migration/dirtyrate: implement dirty-ring dirtyrate calculation",
since the above feature has not been merged, so we post this patch
for the sake of RFC. ideally, this patshset may be merged after it.

Please, review, thanks !

Best Regards !

Hyman Huang(黄勇) (3):
  KVM: introduce kvm_get_manual_dirty_log_protect
  memory: introduce DirtyRateIncreasedPages and util function
  migration/dirtyrate: implement dirty-bitmap dirtyrate calculation

 accel/kvm/kvm-all.c     |   6 +++
 hmp-commands.hx         |   9 ++--
 include/exec/ram_addr.h |  87 ++++++++++++++++++++++++++----
 include/sysemu/kvm.h    |   1 +
 migration/dirtyrate.c   | 138 ++++++++++++++++++++++++++++++++++++++++++++----
 migration/trace-events  |   1 +
 qapi/migration.json     |   6 ++-
 softmmu/physmem.c       |  35 ++++++++++++
 8 files changed, 259 insertions(+), 24 deletions(-)

-- 
1.8.3.1



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

* [PATCH v2 1/3] KVM: introduce kvm_get_manual_dirty_log_protect
       [not found] ` <cover.1626108969.git.huangy81@chinatelecom.cn>
@ 2021-07-12 16:56   ` huangy81
  2021-07-12 16:56   ` [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function huangy81
  2021-07-12 16:56   ` [PATCH v2 3/3] migration/dirtyrate: implement dirty-bitmap dirtyrate calculation huangy81
  2 siblings, 0 replies; 5+ messages in thread
From: huangy81 @ 2021-07-12 16:56 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Hyman, Dr. David Alan Gilbert,
	Peter Xu, Chuan Zheng, Paolo Bonzini

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>

introduce kvm_get_manual_dirty_log_protect for measureing
dirtyrate via dirty bitmap. calculation of dirtyrate need
to sync dirty log and depends on the features of dirty log.

Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
---
 accel/kvm/kvm-all.c  | 6 ++++++
 include/sysemu/kvm.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index e0e88a2..f7d9ae0 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -245,6 +245,12 @@ int kvm_get_max_memslots(void)
     return s->nr_slots;
 }
 
+uint64_t kvm_get_manual_dirty_log_protect(void)
+{
+    KVMState *s = KVM_STATE(current_accel());
+    return s->manual_dirty_log_protect;
+}
+
 /* Called with KVMMemoryListener.slots_lock held */
 static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
 {
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 7b22aeb..b668d49 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -533,6 +533,7 @@ int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source);
 int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target);
 struct ppc_radix_page_info *kvm_get_radix_page_info(void);
 int kvm_get_max_memslots(void);
+uint64_t kvm_get_manual_dirty_log_protect(void);
 
 /* Notify resamplefd for EOI of specific interrupts. */
 void kvm_resample_fd_notify(int gsi);
-- 
1.8.3.1



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

* [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function
       [not found] ` <cover.1626108969.git.huangy81@chinatelecom.cn>
  2021-07-12 16:56   ` [PATCH v2 1/3] KVM: introduce kvm_get_manual_dirty_log_protect huangy81
@ 2021-07-12 16:56   ` huangy81
  2021-07-13 17:49     ` Peter Xu
  2021-07-12 16:56   ` [PATCH v2 3/3] migration/dirtyrate: implement dirty-bitmap dirtyrate calculation huangy81
  2 siblings, 1 reply; 5+ messages in thread
From: huangy81 @ 2021-07-12 16:56 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Hyman, Dr. David Alan Gilbert,
	Peter Xu, Chuan Zheng, Paolo Bonzini

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>

introduce DirtyRateIncreasedPages to stat the increased dirty pages
during the calculation time along with ramblock_sync_dirty_bitmap.

introduce util functions to setup the DIRTY_MEMORY_MIGRATION
dirty bits for the convenience of tracking dirty bitmap when
calculating dirtyrate.

Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
---
 include/exec/ram_addr.h | 87 ++++++++++++++++++++++++++++++++++++++++++++-----
 softmmu/physmem.c       | 35 ++++++++++++++++++++
 2 files changed, 113 insertions(+), 9 deletions(-)

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 45c9132..c47d1a7 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -26,6 +26,8 @@
 #include "exec/ramlist.h"
 #include "exec/ramblock.h"
 
+static uint64_t DirtyRateIncreasedPages = 0;
+
 /**
  * clear_bmap_size: calculate clear bitmap size
  *
@@ -422,6 +424,9 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
                                               ram_addr_t length,
                                               unsigned client);
 
+void cpu_physical_memory_dirtyrate_clear_bit(ram_addr_t start,
+                                             ram_addr_t length);
+
 DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
     (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client);
 
@@ -449,6 +454,8 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
     uint64_t num_dirty = 0;
     unsigned long *dest = rb->bmap;
 
+    assert(global_dirty_tracking);
+
     /* start address and length is aligned at the start of a word? */
     if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
          (start + rb->offset) &&
@@ -466,12 +473,20 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
 
         for (k = page; k < page + nr; k++) {
             if (src[idx][offset]) {
-                unsigned long bits = qatomic_xchg(&src[idx][offset], 0);
-                unsigned long new_dirty;
-                new_dirty = ~dest[k];
-                dest[k] |= bits;
-                new_dirty &= bits;
-                num_dirty += ctpopl(new_dirty);
+                unsigned long bits;
+                if (global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE) {
+                    bits = qatomic_read(&src[idx][offset]);
+                    DirtyRateIncreasedPages += ctpopl(bits);
+                }
+
+                if (global_dirty_tracking & GLOBAL_DIRTY_MIGRATION) {
+                    unsigned long new_dirty;
+                    bits = qatomic_xchg(&src[idx][offset], 0);
+                    new_dirty = ~dest[k];
+                    dest[k] |= bits;
+                    new_dirty &= bits;
+                    num_dirty += ctpopl(new_dirty);
+                }
             }
 
             if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
@@ -500,9 +515,15 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
                         start + addr + offset,
                         TARGET_PAGE_SIZE,
                         DIRTY_MEMORY_MIGRATION)) {
-                long k = (start + addr) >> TARGET_PAGE_BITS;
-                if (!test_and_set_bit(k, dest)) {
-                    num_dirty++;
+                if (global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE) {
+                    DirtyRateIncreasedPages++;
+                }
+
+                if (global_dirty_tracking & GLOBAL_DIRTY_MIGRATION) {
+                    long k = (start + addr) >> TARGET_PAGE_BITS;
+                    if (!test_and_set_bit(k, dest)) {
+                        num_dirty++;
+                    }
                 }
             }
         }
@@ -510,5 +531,53 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
 
     return num_dirty;
 }
+
+static inline
+void cpu_physical_memory_dirtyrate_clear_dirty_bits(RAMBlock *rb)
+{
+    ram_addr_t addr;
+    ram_addr_t length = rb->used_length;
+    unsigned long word = BIT_WORD(rb->offset >> TARGET_PAGE_BITS);
+
+    /* start address and length is aligned at the start of a word? */
+    if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) == rb->offset &&
+        !(length & ((BITS_PER_LONG << TARGET_PAGE_BITS) - 1))) {
+        int k;
+        int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
+        unsigned long * const *src;
+        unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
+        unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
+                                        DIRTY_MEMORY_BLOCK_SIZE);
+
+        src = qatomic_rcu_read(
+                &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks;
+
+        for (k = 0; k < nr; k++) {
+            if (src[idx][offset]) {
+                qatomic_set(&src[idx][offset], 0);
+            }
+            if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
+                offset = 0;
+                idx++;
+            }
+        }
+    } else {
+        ram_addr_t offset = rb->offset;
+
+        for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
+            cpu_physical_memory_dirtyrate_clear_bit(addr + offset,
+                                                    TARGET_PAGE_SIZE);
+        }
+    }
+
+    return;
+}
+
+static inline
+void cpu_physical_memory_dirtyrate_reset_protect(RAMBlock *rb)
+{
+    memory_region_clear_dirty_bitmap(rb->mr, 0, rb->used_length);
+    cpu_physical_memory_dirtyrate_clear_dirty_bits(rb);
+}
 #endif
 #endif
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 3c1912a..67cff31 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -1068,6 +1068,41 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
     return dirty;
 }
 
+void cpu_physical_memory_dirtyrate_clear_bit(ram_addr_t start,
+                                             ram_addr_t length)
+{
+    DirtyMemoryBlocks *blocks;
+    unsigned long end, page;
+    RAMBlock *ramblock;
+
+    if (length == 0) {
+        return;
+    }
+
+    end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+    page = start >> TARGET_PAGE_BITS;
+
+    WITH_RCU_READ_LOCK_GUARD() {
+        blocks =
+            qatomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]);
+        ramblock = qemu_get_ram_block(start);
+        /* Range sanity check on the ramblock */
+        assert(start >= ramblock->offset &&
+               start + length <= ramblock->offset + ramblock->used_length);
+        while (page < end) {
+            unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+            unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+            unsigned long num = MIN(end - page,
+                                    DIRTY_MEMORY_BLOCK_SIZE - offset);
+
+            clear_bit(num, blocks->blocks[idx]);
+            page += num;
+        }
+    }
+
+    return;
+}
+
 DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
     (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client)
 {
-- 
1.8.3.1



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

* [PATCH v2 3/3] migration/dirtyrate: implement dirty-bitmap dirtyrate calculation
       [not found] ` <cover.1626108969.git.huangy81@chinatelecom.cn>
  2021-07-12 16:56   ` [PATCH v2 1/3] KVM: introduce kvm_get_manual_dirty_log_protect huangy81
  2021-07-12 16:56   ` [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function huangy81
@ 2021-07-12 16:56   ` huangy81
  2 siblings, 0 replies; 5+ messages in thread
From: huangy81 @ 2021-07-12 16:56 UTC (permalink / raw)
  To: qemu-devel
  Cc: Eduardo Habkost, Juan Quintela, Hyman, Dr. David Alan Gilbert,
	Peter Xu, Chuan Zheng, Paolo Bonzini

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>

introduce dirty-bitmap mode as the third method of calc-dirty-rate.
implement dirty-bitmap dirtyrate calculation, which can be used
to measuring dirtyrate in the absence of dirty-ring.

introduce "dirty_bitmap:-b" option in hmp calc_dirty_rate to
indicate dirty bitmap method should be used for calculation.

Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
---
 hmp-commands.hx        |   9 ++--
 migration/dirtyrate.c  | 134 +++++++++++++++++++++++++++++++++++++++++++++----
 migration/trace-events |   1 +
 qapi/migration.json    |   6 ++-
 4 files changed, 135 insertions(+), 15 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index f7fc9d7..605973c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1738,9 +1738,10 @@ ERST
 
     {
         .name       = "calc_dirty_rate",
-        .args_type  = "dirty_ring:-r,second:l,sample_pages_per_GB:l?",
-        .params     = "[-r] second [sample_pages_per_GB]",
-        .help       = "start a round of guest dirty rate measurement (using -d to"
-                      "\n\t\t\t specify dirty ring as the method of calculation)",
+        .args_type  = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?",
+        .params     = "[-r] [-b] second [sample_pages_per_GB]",
+        .help       = "start a round of guest dirty rate measurement (using -r to"
+                      "\n\t\t\t specify dirty ring as the method of calculation and"
+                      "\n\t\t\t -b to specify dirty bitmap as method of calculation)",
         .cmd        = hmp_calc_dirty_rate,
     },
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 3c8c5e2..69866ca 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -15,6 +15,7 @@
 #include "qapi/error.h"
 #include "cpu.h"
 #include "exec/ramblock.h"
+#include "exec/ram_addr.h"
 #include "qemu/rcu_queue.h"
 #include "qemu/main-loop.h"
 #include "qapi/qapi-commands-migration.h"
@@ -111,6 +112,10 @@ static struct DirtyRateInfo *query_dirty_rate_info(void)
             }
             info->vcpu_dirty_rate = head;
         }
+
+        if (dirtyrate_mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) {
+            info->sample_pages = 0;
+        }
     }
 
     trace_query_dirty_rate_info(DirtyRateStatus_str(CalculatingState));
@@ -408,6 +413,99 @@ static void dirtyrate_global_dirty_log_stop(void)
     qemu_mutex_unlock_iothread();
 }
 
+static inline void dirtyrate_increasedpages_clear(void)
+{
+    DirtyRateIncreasedPages = 0;
+}
+
+static inline uint64_t dirtyrate_increasedpages_reap(void)
+{
+    RAMBlock *block = NULL;
+
+    WITH_RCU_READ_LOCK_GUARD() {
+        RAMBLOCK_FOREACH_MIGRATABLE(block) {
+            cpu_physical_memory_sync_dirty_bitmap(block, 0, block->used_length);
+        }
+    }
+
+    return DirtyRateIncreasedPages;
+}
+
+static inline void dirtyrate_manual_reset_protect(void)
+{
+    RAMBlock *block = NULL;
+
+    WITH_RCU_READ_LOCK_GUARD() {
+        RAMBLOCK_FOREACH_MIGRATABLE(block) {
+            cpu_physical_memory_dirtyrate_reset_protect(block);
+        }
+    }
+}
+
+static void do_calculate_dirtyrate_bitmap(void)
+{
+    uint64_t memory_size_MB;
+    int64_t time_s;
+    uint64_t increased_dirty_pages = 0;
+    uint64_t dirtyrate = 0;
+
+    increased_dirty_pages = dirtyrate_increasedpages_reap();
+
+    memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20;
+    time_s = DirtyStat.calc_time;
+
+    dirtyrate = memory_size_MB / time_s;
+    DirtyStat.dirty_rate = dirtyrate;
+
+    trace_dirtyrate_do_calculate_bitmap(increased_dirty_pages,
+                                        time_s, dirtyrate);
+}
+
+static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config)
+{
+    int64_t msec = 0;
+    int64_t start_time;
+    uint64_t protect_flags = kvm_get_manual_dirty_log_protect();
+
+    dirtyrate_global_dirty_log_start();
+
+    /*
+     * 1'round of log sync may return all 1 bits with
+     * KVM_DIRTY_LOG_INITIALLY_SET enable
+     * skip it unconditionally and start dirty tracking
+     * from 2'round of log sync
+     */
+    memory_global_dirty_log_sync();
+
+    /*
+     * reset page protect manually and
+     * start dirty tracking from now on
+     */
+    if (protect_flags & KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE) {
+        dirtyrate_manual_reset_protect();
+    }
+
+    dirtyrate_increasedpages_clear();
+
+    start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    DirtyStat.start_time = start_time / 1000;
+
+    msec = config.sample_period_seconds * 1000;
+    msec = set_sample_page_period(msec, start_time);
+    DirtyStat.calc_time = msec / 1000;
+
+    /* fetch dirty bitmap from kvm */
+    memory_global_dirty_log_sync();
+
+    do_calculate_dirtyrate_bitmap();
+
+    if (protect_flags & KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE) {
+        dirtyrate_manual_reset_protect();
+    }
+
+    dirtyrate_global_dirty_log_stop();
+}
+
 static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages)
 {
     uint64_t memory_size_MB;
@@ -506,7 +604,9 @@ out:
 
 static void calculate_dirtyrate(struct DirtyRateConfig config)
 {
-    if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
+    if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) {
+        calculate_dirtyrate_dirty_bitmap(config);
+    } else if (config.mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) {
         calculate_dirtyrate_dirty_ring(config);
     } else {
         calculate_dirtyrate_sample_vm(config);
@@ -589,12 +689,15 @@ void qmp_calc_dirty_rate(int64_t calc_time,
 
     /*
      * dirty ring mode only works when kvm dirty ring is enabled.
+     * on the contrary, dirty bitmap mode is not.
      */
-    if ((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) &&
-        !kvm_dirty_ring_enabled()) {
-        error_setg(errp, "dirty ring is disabled, use sample-pages method "
-                         "or remeasure later.");
-        return;
+    if (((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_RING) &&
+        !kvm_dirty_ring_enabled()) ||
+        ((mode == DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP) &&
+         kvm_dirty_ring_enabled())) {
+        error_setg(errp, "mode %s is not enabled, use other method instead.",
+                         DirtyRateMeasureMode_str(mode));
+         return;
     }
 
     /*
@@ -670,9 +773,8 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
     int64_t sample_pages = qdict_get_try_int(qdict, "sample_pages_per_GB", -1);
     bool has_sample_pages = (sample_pages != -1);
     bool dirty_ring = qdict_get_try_bool(qdict, "dirty_ring", false);
-    DirtyRateMeasureMode mode =
-        (dirty_ring ? DIRTY_RATE_MEASURE_MODE_DIRTY_RING :
-         DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING);
+    bool dirty_bitmap = qdict_get_try_bool(qdict, "dirty_bitmap", false);
+    DirtyRateMeasureMode mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
     Error *err = NULL;
 
     if (!sec) {
@@ -680,6 +782,20 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
         return;
     }
 
+    if (dirty_ring && dirty_bitmap) {
+        monitor_printf(mon, "Either dirty ring or dirty bitmap "
+                       "can be specified!\n");
+        return;
+    }
+
+    if (dirty_bitmap) {
+        mode = DIRTY_RATE_MEASURE_MODE_DIRTY_BITMAP;
+    }
+
+    if (dirty_ring) {
+        mode = DIRTY_RATE_MEASURE_MODE_DIRTY_RING;
+    }
+
     qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true,
                         mode, &err);
     if (err) {
diff --git a/migration/trace-events b/migration/trace-events
index ce0b5e6..921f7a7 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -333,6 +333,7 @@ skip_sample_ramblock(const char *idstr, uint64_t ramblock_size) "ramblock name:
 find_page_matched(const char *idstr) "ramblock %s addr or size changed"
 dirtyrate_calculate(int64_t dirtyrate) "dirty rate: %" PRIi64 " MB/s"
 dirtyrate_do_calculate_vcpu(int idx, uint64_t rate) "vcpu[%d]: %"PRIu64 " MB/s"
+dirtyrate_do_calculate_bitmap(uint64_t pages, int64_t time, uint64_t rate) "%"PRIu64 " pages has increased in %"PRIi64 " s, rate %"PRIu64 "MB/s"
 
 # block.c
 migration_block_init_shared(const char *blk_device_name) "Start migration for %s with shared base image"
diff --git a/qapi/migration.json b/qapi/migration.json
index de35528..0b00976 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1747,13 +1747,15 @@
 #
 # @page-sampling: calculate dirtyrate by sampling pages.
 #
-# @dirty-ring: calculate dirtyrate by via dirty ring.
+# @dirty-ring: calculate dirtyrate by dirty ring.
+#
+# @dirty-bitmap: calculate dirtyrate by dirty bitmap.
 #
 # Since: 6.1
 #
 ##
 { 'enum': 'DirtyRateMeasureMode',
-  'data': ['page-sampling', 'dirty-ring'] }
+  'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] }
 
 ##
 # @DirtyRateInfo:
-- 
1.8.3.1



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

* Re: [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function
  2021-07-12 16:56   ` [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function huangy81
@ 2021-07-13 17:49     ` Peter Xu
  0 siblings, 0 replies; 5+ messages in thread
From: Peter Xu @ 2021-07-13 17:49 UTC (permalink / raw)
  To: huangy81
  Cc: Eduardo Habkost, Juan Quintela, qemu-devel,
	Dr. David Alan Gilbert, Chuan Zheng, Paolo Bonzini

On Tue, Jul 13, 2021 at 12:56:51AM +0800, huangy81@chinatelecom.cn wrote:
> From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
> 
> introduce DirtyRateIncreasedPages to stat the increased dirty pages
> during the calculation time along with ramblock_sync_dirty_bitmap.
> 
> introduce util functions to setup the DIRTY_MEMORY_MIGRATION
> dirty bits for the convenience of tracking dirty bitmap when
> calculating dirtyrate.
> 
> Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn>
> ---
>  include/exec/ram_addr.h | 87 ++++++++++++++++++++++++++++++++++++++++++++-----
>  softmmu/physmem.c       | 35 ++++++++++++++++++++
>  2 files changed, 113 insertions(+), 9 deletions(-)
> 
> diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
> index 45c9132..c47d1a7 100644
> --- a/include/exec/ram_addr.h
> +++ b/include/exec/ram_addr.h
> @@ -26,6 +26,8 @@
>  #include "exec/ramlist.h"
>  #include "exec/ramblock.h"
>  
> +static uint64_t DirtyRateIncreasedPages = 0;

This looks odd already itself; per my understanding defining a static in a
header file will define one variable for each .c file including it.  This could
lead to each .c file increase its own variable and other .c files read zeros, iiuc.

If we need a global we should define it in a .c file and here we define with
"extern" to reference it in other .c files.

> +
>  /**
>   * clear_bmap_size: calculate clear bitmap size
>   *
> @@ -422,6 +424,9 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
>                                                ram_addr_t length,
>                                                unsigned client);
>  
> +void cpu_physical_memory_dirtyrate_clear_bit(ram_addr_t start,
> +                                             ram_addr_t length);
> +
>  DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
>      (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client);
>  
> @@ -449,6 +454,8 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
>      uint64_t num_dirty = 0;
>      unsigned long *dest = rb->bmap;
>  
> +    assert(global_dirty_tracking);
> +
>      /* start address and length is aligned at the start of a word? */
>      if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
>           (start + rb->offset) &&
> @@ -466,12 +473,20 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
>  
>          for (k = page; k < page + nr; k++) {
>              if (src[idx][offset]) {
> -                unsigned long bits = qatomic_xchg(&src[idx][offset], 0);
> -                unsigned long new_dirty;
> -                new_dirty = ~dest[k];
> -                dest[k] |= bits;
> -                new_dirty &= bits;
> -                num_dirty += ctpopl(new_dirty);
> +                unsigned long bits;
> +                if (global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE) {
> +                    bits = qatomic_read(&src[idx][offset]);
> +                    DirtyRateIncreasedPages += ctpopl(bits);
> +                }
> +
> +                if (global_dirty_tracking & GLOBAL_DIRTY_MIGRATION) {
> +                    unsigned long new_dirty;
> +                    bits = qatomic_xchg(&src[idx][offset], 0);
> +                    new_dirty = ~dest[k];
> +                    dest[k] |= bits;
> +                    new_dirty &= bits;
> +                    num_dirty += ctpopl(new_dirty);
> +                }
>              }
>  
>              if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {

Please see my other reply in previous version's cover letter.

IMHO cpu_physical_memory_sync_dirty_bitmap() should be kept untouched.  Then
below functions are not needed either.

Thanks,

> @@ -500,9 +515,15 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
>                          start + addr + offset,
>                          TARGET_PAGE_SIZE,
>                          DIRTY_MEMORY_MIGRATION)) {
> -                long k = (start + addr) >> TARGET_PAGE_BITS;
> -                if (!test_and_set_bit(k, dest)) {
> -                    num_dirty++;
> +                if (global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE) {
> +                    DirtyRateIncreasedPages++;
> +                }
> +
> +                if (global_dirty_tracking & GLOBAL_DIRTY_MIGRATION) {
> +                    long k = (start + addr) >> TARGET_PAGE_BITS;
> +                    if (!test_and_set_bit(k, dest)) {
> +                        num_dirty++;
> +                    }
>                  }
>              }
>          }
> @@ -510,5 +531,53 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
>  
>      return num_dirty;
>  }
> +
> +static inline
> +void cpu_physical_memory_dirtyrate_clear_dirty_bits(RAMBlock *rb)
> +{
> +    ram_addr_t addr;
> +    ram_addr_t length = rb->used_length;
> +    unsigned long word = BIT_WORD(rb->offset >> TARGET_PAGE_BITS);
> +
> +    /* start address and length is aligned at the start of a word? */
> +    if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) == rb->offset &&
> +        !(length & ((BITS_PER_LONG << TARGET_PAGE_BITS) - 1))) {
> +        int k;
> +        int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
> +        unsigned long * const *src;
> +        unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
> +        unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
> +                                        DIRTY_MEMORY_BLOCK_SIZE);
> +
> +        src = qatomic_rcu_read(
> +                &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks;
> +
> +        for (k = 0; k < nr; k++) {
> +            if (src[idx][offset]) {
> +                qatomic_set(&src[idx][offset], 0);
> +            }
> +            if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
> +                offset = 0;
> +                idx++;
> +            }
> +        }
> +    } else {
> +        ram_addr_t offset = rb->offset;
> +
> +        for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
> +            cpu_physical_memory_dirtyrate_clear_bit(addr + offset,
> +                                                    TARGET_PAGE_SIZE);
> +        }
> +    }
> +
> +    return;
> +}
> +
> +static inline
> +void cpu_physical_memory_dirtyrate_reset_protect(RAMBlock *rb)
> +{
> +    memory_region_clear_dirty_bitmap(rb->mr, 0, rb->used_length);
> +    cpu_physical_memory_dirtyrate_clear_dirty_bits(rb);
> +}
>  #endif
>  #endif
> diff --git a/softmmu/physmem.c b/softmmu/physmem.c
> index 3c1912a..67cff31 100644
> --- a/softmmu/physmem.c
> +++ b/softmmu/physmem.c
> @@ -1068,6 +1068,41 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
>      return dirty;
>  }
>  
> +void cpu_physical_memory_dirtyrate_clear_bit(ram_addr_t start,
> +                                             ram_addr_t length)
> +{
> +    DirtyMemoryBlocks *blocks;
> +    unsigned long end, page;
> +    RAMBlock *ramblock;
> +
> +    if (length == 0) {
> +        return;
> +    }
> +
> +    end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
> +    page = start >> TARGET_PAGE_BITS;
> +
> +    WITH_RCU_READ_LOCK_GUARD() {
> +        blocks =
> +            qatomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]);
> +        ramblock = qemu_get_ram_block(start);
> +        /* Range sanity check on the ramblock */
> +        assert(start >= ramblock->offset &&
> +               start + length <= ramblock->offset + ramblock->used_length);
> +        while (page < end) {
> +            unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
> +            unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
> +            unsigned long num = MIN(end - page,
> +                                    DIRTY_MEMORY_BLOCK_SIZE - offset);
> +
> +            clear_bit(num, blocks->blocks[idx]);
> +            page += num;
> +        }
> +    }
> +
> +    return;
> +}
> +
>  DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
>      (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client)
>  {
> -- 
> 1.8.3.1
> 

-- 
Peter Xu



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

end of thread, other threads:[~2021-07-13 17:50 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-12 16:56 [PATCH v2 0/3] support dirtyrate measurement with dirty bitmap huangy81
     [not found] ` <cover.1626108969.git.huangy81@chinatelecom.cn>
2021-07-12 16:56   ` [PATCH v2 1/3] KVM: introduce kvm_get_manual_dirty_log_protect huangy81
2021-07-12 16:56   ` [PATCH v2 2/3] memory: introduce DirtyRateIncreasedPages and util function huangy81
2021-07-13 17:49     ` Peter Xu
2021-07-12 16:56   ` [PATCH v2 3/3] migration/dirtyrate: implement dirty-bitmap dirtyrate calculation huangy81

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.