All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/10] *** A Method for evaluating dirty page rate ***
@ 2020-08-14  9:32 Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 01/10] migration/dirtyrate: Add get_dirtyrate_thread() function Chuan Zheng
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

v1 -> v2:
    use g_rand_new() to generate rand_buf
    move RAMBLOCK_FOREACH_MIGRATABLE into migration/ram.h
    add skip_sample_ramblock to filter sampled ramblock
    fix multi-numa vm coredump when query dirtyrate
    rename qapi interface and rename some structures and functions
    succeed to compile by appling each patch
    add test for migrating vm

Sometimes it is neccessary to evaluate dirty page rate before migration.
Users could decide whether to proceed migration based on the evaluation
in case of vm performance loss due to heavy workload.
Unlikey simulating dirtylog sync which could do harm on runnning vm,
we provide a sample-hash method to compare hash results for samping page.
In this way, it would have hardly no impact on vm performance.

Evaluate the dirtypage rate both on running and migration vm.
The VM specifications for migration are as follows:
- VM use 4-K page;
- the number of VCPU is 32;
- the total memory is 32Gigabit;
- use 'mempress' tool to pressurize VM(mempress 4096 1024);
- migration bandwidth is 1GB/s

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|                      |  running  |                  migrating                    |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| no mempress          |   4MB/s   |          8MB/s      (migrated success)        |
------------------------------------------------------------------------------------
| mempress 4096 1024   |  1188MB/s |   536MB/s ~ 1044MB/s (cpu throttle triggered) |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| mempress 4096 4096   |  4152MB/s |     608MB/s ~ 4125MB/s (migation failed)      |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Test dirtyrate by qmp command like this:
1.  virsh qemu-monitor-command [vmname] '{"execute":"calc-dirty-rate", "arguments": {"calc-time": [sleep-time]}}'; 
2.  sleep specific time which is a bit larger than sleep-time
3.  virsh qemu-monitor-command [vmname] '{"execute":"query-dirty-rate"}'

Further test dirtyrate by libvirt api like this:
virsh getdirtyrate [vmname] [sleep-time]

Zheng Chuan (10):
  migration/dirtyrate: Add get_dirtyrate_thread() function
  migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info
  migration/dirtyrate: Add dirtyrate statistics series functions
  migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h
  migration/dirtyrate: Record hash results for each sampled page
  migration/dirtyrate: Compare page hash results for recorded sampled
    page
  migration/dirtyrate: skip sampling ramblock with size below
    MIN_RAMBLOCK_SIZE
  migration/dirtyrate: Implement get_sample_page_period() and
    block_sample_page_period()
  migration/dirtyrate: Implement calculate_dirtyrate() function
  migration/dirtyrate: Implement
    qmp_cal_dirty_rate()/qmp_get_dirty_rate() function

 migration/Makefile.objs |   1 +
 migration/dirtyrate.c   | 448 ++++++++++++++++++++++++++++++++++++++++++++++++
 migration/dirtyrate.h   |  86 ++++++++++
 migration/ram.c         |  11 +-
 migration/ram.h         |  10 ++
 qapi/migration.json     |  42 +++++
 6 files changed, 588 insertions(+), 10 deletions(-)
 create mode 100644 migration/dirtyrate.c
 create mode 100644 migration/dirtyrate.h

-- 
1.8.3.1



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

* [PATCH v2 01/10] migration/dirtyrate: Add get_dirtyrate_thread() function
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info Chuan Zheng
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Add get_dirtyrate_thread() functions

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
Signed-off-by: YanYing Zhuang <ann.zhuangyanying@huawei.com>
---
 migration/Makefile.objs |  1 +
 migration/dirtyrate.c   | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
 migration/dirtyrate.h   | 44 ++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+)
 create mode 100644 migration/dirtyrate.c
 create mode 100644 migration/dirtyrate.h

diff --git a/migration/Makefile.objs b/migration/Makefile.objs
index 0fc619e..12ae98c 100644
--- a/migration/Makefile.objs
+++ b/migration/Makefile.objs
@@ -6,6 +6,7 @@ common-obj-y += qemu-file.o global_state.o
 common-obj-y += qemu-file-channel.o
 common-obj-y += xbzrle.o postcopy-ram.o
 common-obj-y += qjson.o
+common-obj-y += dirtyrate.o
 common-obj-y += block-dirty-bitmap.o
 common-obj-y += multifd.o
 common-obj-y += multifd-zlib.o
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
new file mode 100644
index 0000000..bb0ebe9
--- /dev/null
+++ b/migration/dirtyrate.c
@@ -0,0 +1,64 @@
+/*
+ * Dirtyrate implement code
+ *
+ * Copyright (c) 2017-2020 HUAWEI TECHNOLOGIES CO.,LTD.
+ *
+ * Authors:
+ *  Chuan Zheng <zhengchuan@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "crypto/hash.h"
+#include "crypto/random.h"
+#include "qemu/config-file.h"
+#include "exec/memory.h"
+#include "exec/ramblock.h"
+#include "exec/target_page.h"
+#include "qemu/rcu_queue.h"
+#include "qapi/qapi-commands-migration.h"
+#include "migration.h"
+#include "dirtyrate.h"
+
+CalculatingDirtyRateState CalculatingState = CAL_DIRTY_RATE_INIT;
+
+static int dirty_rate_set_state(int new_state)
+{
+    int old_state = CalculatingState;
+
+    if (new_state == old_state) {
+        return -1;
+    }
+
+    if (atomic_cmpxchg(&CalculatingState, old_state, new_state) != old_state) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static void calculate_dirtyrate(struct DirtyRateConfig config)
+{
+    /* todo */
+    return;
+}
+
+void *get_dirtyrate_thread(void *arg)
+{
+    struct DirtyRateConfig config = *(struct DirtyRateConfig *)arg;
+    int ret;
+
+    ret = dirty_rate_set_state(CAL_DIRTY_RATE_ACTIVE);
+    if (ret == -1) {
+        return NULL;
+    }
+
+    calculate_dirtyrate(config);
+
+    ret = dirty_rate_set_state(CAL_DIRTY_RATE_END);
+
+    return NULL;
+}
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
new file mode 100644
index 0000000..914c363
--- /dev/null
+++ b/migration/dirtyrate.h
@@ -0,0 +1,44 @@
+/*
+ *  Dirtyrate common functions
+ *
+ *  Copyright (c) 2020 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ *  Authors:
+ *  Chuan Zheng <zhengchuan@huawei.com>
+ *
+ *  This work is licensed under the terms of the GNU GPL, version 2 or later.
+ *  See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_MIGRATION_DIRTYRATE_H
+#define QEMU_MIGRATION_DIRTYRATE_H
+
+/*
+ * Sample 256 pages per GB as default.
+ * TODO: Make it configurable.
+ */
+#define DIRTYRATE_DEFAULT_SAMPLE_PAGES            256
+
+/* Take 1s as default for calculation duration */
+#define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
+
+struct DirtyRateConfig {
+    uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
+    int64_t sample_period_seconds; /* time duration between two sampling */
+};
+
+/*
+ *  To record calculate dirty_rate status:
+ *  0: initial status, calculating thread is not be created here.
+ *  1: calculating thread is created.
+ *  2: calculating thread is end, we can get result.
+ */
+typedef enum {
+    CAL_DIRTY_RATE_INIT = 0,
+    CAL_DIRTY_RATE_ACTIVE,
+    CAL_DIRTY_RATE_END,
+} CalculatingDirtyRateState;
+
+void *get_dirtyrate_thread(void *arg);
+#endif
+
-- 
1.8.3.1



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

* [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 01/10] migration/dirtyrate: Add get_dirtyrate_thread() function Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 03/10] migration/dirtyrate: Add dirtyrate statistics series functions Chuan Zheng
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Add RamlockDirtyInfo to store sampled page info of each ramblock.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
---
 migration/dirtyrate.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 914c363..9650566 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -19,6 +19,11 @@
  */
 #define DIRTYRATE_DEFAULT_SAMPLE_PAGES            256
 
+/*
+ * Record ramblock idstr
+ */
+#define RAMBLOCK_INFO_MAX_LEN                     256
+
 /* Take 1s as default for calculation duration */
 #define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
 
@@ -39,6 +44,19 @@ typedef enum {
     CAL_DIRTY_RATE_END,
 } CalculatingDirtyRateState;
 
+/*
+ * Store dirtypage info for each ramblock.
+ */
+struct RamblockDirtyInfo {
+    char idstr[RAMBLOCK_INFO_MAX_LEN]; /* idstr for each ramblock */
+    uint8_t *ramblock_addr; /* base address of ramblock we measure */
+    size_t ramblock_pages; /* sum of dividation by 4K pages for ramblock */
+    size_t *sample_page_vfn; /* relative offset address for sampled page */
+    unsigned int sample_pages_count; /* sum of sampled pages */
+    unsigned int sample_dirty_count; /* sum of dirty pages we measure */
+    uint8_t *hash_result; /* array of hash result for sampled pages */
+};
+
 void *get_dirtyrate_thread(void *arg);
 #endif
 
-- 
1.8.3.1



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

* [PATCH v2 03/10] migration/dirtyrate: Add dirtyrate statistics series functions
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 01/10] migration/dirtyrate: Add get_dirtyrate_thread() function Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 04/10] migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h Chuan Zheng
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Add dirtyrate statistics to record/update dirtyrate info.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
---
 migration/dirtyrate.c | 30 ++++++++++++++++++++++++++++++
 migration/dirtyrate.h | 10 ++++++++++
 2 files changed, 40 insertions(+)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index bb0ebe9..8708090 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -24,6 +24,7 @@
 #include "dirtyrate.h"
 
 CalculatingDirtyRateState CalculatingState = CAL_DIRTY_RATE_INIT;
+static struct DirtyRateStat dirty_stat;
 
 static int dirty_rate_set_state(int new_state)
 {
@@ -40,6 +41,35 @@ static int dirty_rate_set_state(int new_state)
     return 0;
 }
 
+static void reset_dirtyrate_stat(void)
+{
+    dirty_stat.total_dirty_samples = 0;
+    dirty_stat.total_sample_count = 0;
+    dirty_stat.total_block_mem_MB = 0;
+    dirty_stat.dirty_rate = 0;
+}
+
+static void update_dirtyrate_stat(struct RamblockDirtyInfo *info)
+{
+    dirty_stat.total_dirty_samples += info->sample_dirty_count;
+    dirty_stat.total_sample_count += info->sample_pages_count;
+    /* size of 4K pages in MB */
+    dirty_stat.total_block_mem_MB += info->ramblock_pages / 256;
+}
+
+static void update_dirtyrate(uint64_t msec)
+{
+    uint64_t dirty_rate;
+    unsigned int total_dirty_samples = dirty_stat.total_dirty_samples;
+    unsigned int total_sample_count = dirty_stat.total_sample_count;
+    size_t total_block_mem_MB = dirty_stat.total_block_mem_MB;
+
+    dirty_rate = total_dirty_samples * total_block_mem_MB *
+                 1000 / (total_sample_count * msec);
+
+    dirty_stat.dirty_rate = dirty_rate;
+}
+
 static void calculate_dirtyrate(struct DirtyRateConfig config)
 {
     /* todo */
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 9650566..af57c80 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -57,6 +57,16 @@ struct RamblockDirtyInfo {
     uint8_t *hash_result; /* array of hash result for sampled pages */
 };
 
+/*
+ * Store calculate statistics for each measure.
+ */
+struct DirtyRateStat {
+    unsigned int total_dirty_samples; /* total dirty pages for this measure */
+    unsigned int total_sample_count; /* total sampled pages for this measure */
+    size_t total_block_mem_MB; /* size of sampled pages in MB */
+    int64_t dirty_rate; /* dirty rate for this measure */
+};
+
 void *get_dirtyrate_thread(void *arg);
 #endif
 
-- 
1.8.3.1



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

* [PATCH v2 04/10] migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (2 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 03/10] migration/dirtyrate: Add dirtyrate statistics series functions Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 05/10] migration/dirtyrate: Record hash results for each sampled page Chuan Zheng
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

RAMBLOCK_FOREACH_MIGRATABLE is need in dirtyrate measure,
move the existing definition up into migration/ram.h

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
---
 migration/dirtyrate.c |  1 +
 migration/ram.c       | 11 +----------
 migration/ram.h       | 10 ++++++++++
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 8708090..c4304ef 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -21,6 +21,7 @@
 #include "qemu/rcu_queue.h"
 #include "qapi/qapi-commands-migration.h"
 #include "migration.h"
+#include "ram.h"
 #include "dirtyrate.h"
 
 CalculatingDirtyRateState CalculatingState = CAL_DIRTY_RATE_INIT;
diff --git a/migration/ram.c b/migration/ram.c
index 76d4fee..37ef0da 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -158,21 +158,12 @@ out:
     return ret;
 }
 
-static bool ramblock_is_ignored(RAMBlock *block)
+bool ramblock_is_ignored(RAMBlock *block)
 {
     return !qemu_ram_is_migratable(block) ||
            (migrate_ignore_shared() && qemu_ram_is_shared(block));
 }
 
-/* Should be holding either ram_list.mutex, or the RCU lock. */
-#define RAMBLOCK_FOREACH_NOT_IGNORED(block)            \
-    INTERNAL_RAMBLOCK_FOREACH(block)                   \
-        if (ramblock_is_ignored(block)) {} else
-
-#define RAMBLOCK_FOREACH_MIGRATABLE(block)             \
-    INTERNAL_RAMBLOCK_FOREACH(block)                   \
-        if (!qemu_ram_is_migratable(block)) {} else
-
 #undef RAMBLOCK_FOREACH
 
 int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque)
diff --git a/migration/ram.h b/migration/ram.h
index 2eeaacf..011e854 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -37,6 +37,16 @@ extern MigrationStats ram_counters;
 extern XBZRLECacheStats xbzrle_counters;
 extern CompressionStats compression_counters;
 
+bool ramblock_is_ignored(RAMBlock *block);
+/* Should be holding either ram_list.mutex, or the RCU lock. */
+#define RAMBLOCK_FOREACH_NOT_IGNORED(block)            \
+    INTERNAL_RAMBLOCK_FOREACH(block)                   \
+        if (ramblock_is_ignored(block)) {} else
+
+#define RAMBLOCK_FOREACH_MIGRATABLE(block)             \
+    INTERNAL_RAMBLOCK_FOREACH(block)                   \
+        if (!qemu_ram_is_migratable(block)) {} else
+
 int xbzrle_cache_resize(int64_t new_size, Error **errp);
 uint64_t ram_bytes_remaining(void);
 uint64_t ram_bytes_total(void);
-- 
1.8.3.1



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

* [PATCH v2 05/10] migration/dirtyrate: Record hash results for each sampled page
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (3 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 04/10] migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 06/10] migration/dirtyrate: Compare page hash results for recorded " Chuan Zheng
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Record hash results for each sampled page.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
Signed-off-by: YanYing Zhuang <ann.zhuangyanying@huawei.com>
---
 migration/dirtyrate.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++
 migration/dirtyrate.h |   7 +++
 2 files changed, 142 insertions(+)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index c4304ef..11c0051 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -25,6 +25,7 @@
 #include "dirtyrate.h"
 
 CalculatingDirtyRateState CalculatingState = CAL_DIRTY_RATE_INIT;
+static unsigned long int qcrypto_hash_len = QCRYPTO_HASH_LEN;
 static struct DirtyRateStat dirty_stat;
 
 static int dirty_rate_set_state(int new_state)
@@ -71,6 +72,140 @@ static void update_dirtyrate(uint64_t msec)
     dirty_stat.dirty_rate = dirty_rate;
 }
 
+/*
+ * get hash result for the sampled memory with length of 4K byte in ramblock,
+ * which starts from ramblock base address.
+ */
+static int get_ramblock_vfn_hash(struct RamblockDirtyInfo *info, unsigned long vfn,
+                                 uint8_t **md)
+{
+    struct iovec iov_array;
+    int ret = 0;
+    int nkey = 1;
+
+    iov_array.iov_base = info->ramblock_addr +
+                         vfn * DIRTYRATE_SAMPLE_PAGE_SIZE;
+    iov_array.iov_len = DIRTYRATE_SAMPLE_PAGE_SIZE;
+
+    if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_MD5,
+                            &iov_array, nkey,
+                            md, &qcrypto_hash_len, NULL) < 0) {
+        ret = -1;
+    }
+
+    return ret;
+}
+
+static int save_ramblock_hash(struct RamblockDirtyInfo *info)
+{
+    unsigned int sample_pages_count;
+    uint8_t *md = NULL;
+    int i;
+    int ret = -1;
+    GRand* rand = g_rand_new();
+
+    sample_pages_count = info->sample_pages_count;
+
+    /* ramblock size less than one page, return success to skip this ramblock */
+    if (unlikely(info->ramblock_pages == 0 || sample_pages_count == 0)) {
+        ret = 0;
+        goto out;
+    }
+
+    info->hash_result = g_try_malloc0_n(sample_pages_count, sizeof(uint8_t) * qcrypto_hash_len);
+    if (!info->hash_result) {
+        ret = -1;
+        goto out;
+    }
+
+    info->sample_page_vfn = g_try_malloc0_n(sample_pages_count, sizeof(unsigned long));
+    if (!info->sample_page_vfn) {
+        g_free(info->hash_result);
+        ret = -1;
+        goto out;
+    }
+
+    for (i = 0; i < sample_pages_count; i++) {
+        md = info->hash_result + i * qcrypto_hash_len;
+        info->sample_page_vfn[i] = g_rand_int_range(rand, 0, info->ramblock_pages - 1);
+        ret = get_ramblock_vfn_hash(info, info->sample_page_vfn[i], &md);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+    ret = 0;
+
+out:
+    g_rand_free(rand);
+    return ret;
+}
+
+static void get_ramblock_dirty_info(RAMBlock *block, struct RamblockDirtyInfo *info,
+                                    struct DirtyRateConfig *config)
+{
+    uint64_t sample_pages_per_gigabytes = config->sample_pages_per_gigabytes;
+
+    /* Right shift 30 bits to calc block size in GB */
+    info->sample_pages_count = (qemu_ram_get_used_length(block) * sample_pages_per_gigabytes) >> 30;
+
+    /* Right shift 12 bits to calc page count in 4KB */
+    info->ramblock_pages = qemu_ram_get_used_length(block) >> 12;
+    info->ramblock_addr = qemu_ram_get_host_addr(block);
+    strcpy(info->idstr, qemu_ram_get_idstr(block));
+}
+
+static struct RamblockDirtyInfo *
+alloc_ramblock_dirty_info(int *block_index,
+                          struct RamblockDirtyInfo *block_dinfo)
+{
+    struct RamblockDirtyInfo *info = NULL;
+    int index = *block_index;
+
+    if (!block_dinfo) {
+        block_dinfo = g_try_new(struct RamblockDirtyInfo, 1);
+        index = 0;
+    } else {
+        index++;
+        block_dinfo = g_try_realloc(block_dinfo, (index + 1) *
+                                    sizeof(struct RamblockDirtyInfo));
+    }
+    if (!block_dinfo)
+        return NULL;
+
+    info = &block_dinfo[index];
+    memset(info, 0, sizeof(struct RamblockDirtyInfo));
+
+    *block_index = index;
+    return block_dinfo;
+}
+
+static int record_ramblock_hash_info(struct DirtyRateConfig config,
+                                     struct RamblockDirtyInfo **block_dinfo, int *block_index)
+{
+    struct RamblockDirtyInfo *info = NULL;
+    struct RamblockDirtyInfo *dinfo = NULL;
+    RAMBlock *block = NULL;
+    int index = 0;
+
+    RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        dinfo = alloc_ramblock_dirty_info(&index, dinfo);
+        if (dinfo == NULL)
+            return -1;
+        info = &dinfo[index];
+        get_ramblock_dirty_info(block, info, &config);
+        if (save_ramblock_hash(info) < 0) {
+            *block_dinfo = dinfo;
+            *block_index = index;
+            return -1;
+        }
+    }
+
+    *block_dinfo = dinfo;
+    *block_index = index;
+
+    return 0;
+}
+
 static void calculate_dirtyrate(struct DirtyRateConfig config)
 {
     /* todo */
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index af57c80..0812b16 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -20,10 +20,17 @@
 #define DIRTYRATE_DEFAULT_SAMPLE_PAGES            256
 
 /*
+ * Sample page size 4K as default.
+ */
+#define DIRTYRATE_SAMPLE_PAGE_SIZE                4096
+
+/*
  * Record ramblock idstr
  */
 #define RAMBLOCK_INFO_MAX_LEN                     256
 
+#define QCRYPTO_HASH_LEN                          16
+
 /* Take 1s as default for calculation duration */
 #define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
 
-- 
1.8.3.1



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

* [PATCH v2 06/10] migration/dirtyrate: Compare page hash results for recorded sampled page
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (4 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 05/10] migration/dirtyrate: Record hash results for each sampled page Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 07/10] migration/dirtyrate: skip sampling ramblock with size below MIN_RAMBLOCK_SIZE Chuan Zheng
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Compare page hash results for recorded sampled page.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
Signed-off-by: YanYing Zhuang <ann.zhuangyanying@huawei.com>
---
 migration/dirtyrate.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 11c0051..f136067 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -206,6 +206,79 @@ static int record_ramblock_hash_info(struct DirtyRateConfig config,
     return 0;
 }
 
+static int calc_page_dirty_rate(struct RamblockDirtyInfo *info)
+{
+    uint8_t *md = NULL;
+    int i;
+    int ret = 0;
+
+    md = g_try_new0(uint8_t, qcrypto_hash_len);
+    if (!md)
+        return -1;
+
+    for (i = 0; i < info->sample_pages_count; i++) {
+        ret = get_ramblock_vfn_hash(info, info->sample_page_vfn[i], &md);
+        if (ret < 0) {
+            goto out;
+        }
+
+        if (memcmp(md, info->hash_result + i * qcrypto_hash_len, qcrypto_hash_len) != 0) {
+            info->sample_dirty_count++;
+        }
+    }
+
+out:
+    g_free(md);
+    return ret;
+}
+
+static bool find_page_matched(RAMBlock *block, struct RamblockDirtyInfo *infos,
+                               int count, struct RamblockDirtyInfo **matched)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (!strcmp(infos[i].idstr, qemu_ram_get_idstr(block))) {
+            break;
+        }
+    }
+
+    if (i == count) {
+        return false;
+    }
+
+    if (infos[i].ramblock_addr != qemu_ram_get_host_addr(block) ||
+        infos[i].ramblock_pages !=
+            (qemu_ram_get_used_length(block) >> 12)) {
+        return false;
+    }
+
+    *matched = &infos[i];
+    return true;
+}
+
+static int compare_page_hash_info(struct RamblockDirtyInfo *info, int block_index)
+{
+    struct RamblockDirtyInfo *block_dinfo = NULL;
+    RAMBlock *block = NULL;
+
+    RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        block_dinfo = NULL;
+        if (!find_page_matched(block, info, block_index + 1, &block_dinfo)) {
+            continue;
+        }
+        if (calc_page_dirty_rate(block_dinfo) < 0) {
+            return -1;
+        }
+        update_dirtyrate_stat(block_dinfo);
+    }
+    if (!dirty_stat.total_sample_count) {
+        return -1;
+    }
+
+    return 0;
+}
+
 static void calculate_dirtyrate(struct DirtyRateConfig config)
 {
     /* todo */
-- 
1.8.3.1



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

* [PATCH v2 07/10] migration/dirtyrate: skip sampling ramblock with size below MIN_RAMBLOCK_SIZE
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (5 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 06/10] migration/dirtyrate: Compare page hash results for recorded " Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 08/10] migration/dirtyrate: Implement get_sample_page_period() and block_sample_page_period() Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 09/10] migration/dirtyrate: Implement calculate_dirtyrate() function Chuan Zheng
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

In order to sample real RAM, skip ramblock with size below
MIN_RAMBLOCK_SIZE which is 128M as default.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
---
 migration/dirtyrate.c | 24 ++++++++++++++++++++++++
 migration/dirtyrate.h |  5 +++++
 2 files changed, 29 insertions(+)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index f136067..3dc9feb 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -179,6 +179,24 @@ alloc_ramblock_dirty_info(int *block_index,
     return block_dinfo;
 }
 
+static int skip_sample_ramblock(RAMBlock *block)
+{
+    int64_t ramblock_size;
+
+    /* ramblock size in MB */
+    ramblock_size = qemu_ram_get_used_length(block) >> 20;
+
+    /*
+     * Consider ramblock with size larger than 128M is what we
+     * want to sample.
+     */
+    if (ramblock_size < MIN_RAMBLOCK_SIZE) {
+        return -1;
+    }
+
+    return 0;
+}
+
 static int record_ramblock_hash_info(struct DirtyRateConfig config,
                                      struct RamblockDirtyInfo **block_dinfo, int *block_index)
 {
@@ -188,6 +206,9 @@ static int record_ramblock_hash_info(struct DirtyRateConfig config,
     int index = 0;
 
     RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        if (skip_sample_ramblock(block) < 0) {
+            continue;
+        }
         dinfo = alloc_ramblock_dirty_info(&index, dinfo);
         if (dinfo == NULL)
             return -1;
@@ -263,6 +284,9 @@ static int compare_page_hash_info(struct RamblockDirtyInfo *info, int block_inde
     RAMBlock *block = NULL;
 
     RAMBLOCK_FOREACH_MIGRATABLE(block) {
+        if (skip_sample_ramblock(block) < 0) {
+            continue;
+        }
         block_dinfo = NULL;
         if (!find_page_matched(block, info, block_index + 1, &block_dinfo)) {
             continue;
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 0812b16..fce2e3b 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -31,6 +31,11 @@
 
 #define QCRYPTO_HASH_LEN                          16
 
+/*
+ * minimum ramblock size to sampled
+ */
+#define MIN_RAMBLOCK_SIZE                        128
+
 /* Take 1s as default for calculation duration */
 #define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
 
-- 
1.8.3.1



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

* [PATCH v2 08/10] migration/dirtyrate: Implement get_sample_page_period() and block_sample_page_period()
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (6 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 07/10] migration/dirtyrate: skip sampling ramblock with size below MIN_RAMBLOCK_SIZE Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  2020-08-14  9:32 ` [PATCH v2 09/10] migration/dirtyrate: Implement calculate_dirtyrate() function Chuan Zheng
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Implement get_sample_page_period() and set_sample_page_period() to
sleep specific time between sample actions.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
Signed-off-by: YanYing Zhuang <ann.zhuangyanying@huawei.com>
---
 migration/dirtyrate.c | 23 +++++++++++++++++++++++
 migration/dirtyrate.h |  2 ++
 2 files changed, 25 insertions(+)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 3dc9feb..54b832a 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -28,6 +28,29 @@ CalculatingDirtyRateState CalculatingState = CAL_DIRTY_RATE_INIT;
 static unsigned long int qcrypto_hash_len = QCRYPTO_HASH_LEN;
 static struct DirtyRateStat dirty_stat;
 
+static int64_t set_sample_page_period(int64_t msec, int64_t initial_time)
+{
+    int64_t current_time;
+
+    current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    if ((current_time - initial_time) >= msec) {
+        msec = current_time - initial_time;
+    } else {
+        g_usleep((msec + initial_time - current_time) * 1000);
+    }
+
+    return msec;
+}
+
+static int64_t get_sample_page_period(int64_t sec)
+{
+    if (sec <= MIN_FETCH_DIRTYRATE_TIME_SEC || sec > MAX_FETCH_DIRTYRATE_TIME_SEC) {
+        sec = DEFAULT_FETCH_DIRTYRATE_TIME_SEC;
+    }
+
+    return sec;
+}
+
 static int dirty_rate_set_state(int new_state)
 {
     int old_state = CalculatingState;
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index fce2e3b..86d8fa0 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -38,6 +38,8 @@
 
 /* Take 1s as default for calculation duration */
 #define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
+#define MIN_FETCH_DIRTYRATE_TIME_SEC              0
+#define MAX_FETCH_DIRTYRATE_TIME_SEC              60
 
 struct DirtyRateConfig {
     uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
-- 
1.8.3.1



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

* [PATCH v2 09/10] migration/dirtyrate: Implement calculate_dirtyrate() function
  2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
                   ` (7 preceding siblings ...)
  2020-08-14  9:32 ` [PATCH v2 08/10] migration/dirtyrate: Implement get_sample_page_period() and block_sample_page_period() Chuan Zheng
@ 2020-08-14  9:32 ` Chuan Zheng
  8 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-14  9:32 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Implement calculate_dirtyrate() function.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
Signed-off-by: YanYing Zhuang <ann.zhuangyanying@huawei.com>
---
 migration/dirtyrate.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 54b832a..d487030 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -177,6 +177,21 @@ static void get_ramblock_dirty_info(RAMBlock *block, struct RamblockDirtyInfo *i
     strcpy(info->idstr, qemu_ram_get_idstr(block));
 }
 
+static void free_ramblock_dirty_info(struct RamblockDirtyInfo *infos, int count)
+{
+    int i;
+
+    if (!infos) {
+        return;
+    }
+
+    for (i = 0; i < count; i++) {
+        g_free(infos[i].sample_page_vfn);
+        g_free(infos[i].hash_result);
+    }
+    g_free(infos);
+}
+
 static struct RamblockDirtyInfo *
 alloc_ramblock_dirty_info(int *block_index,
                           struct RamblockDirtyInfo *block_dinfo)
@@ -328,8 +343,35 @@ static int compare_page_hash_info(struct RamblockDirtyInfo *info, int block_inde
 
 static void calculate_dirtyrate(struct DirtyRateConfig config)
 {
-    /* todo */
-    return;
+    struct RamblockDirtyInfo *block_dinfo = NULL;
+    int block_index = 0;
+    int64_t msec = 0;
+    int64_t initial_time;
+
+    rcu_register_thread();
+    reset_dirtyrate_stat();
+    initial_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    rcu_read_lock();
+    if (record_ramblock_hash_info(config, &block_dinfo, &block_index) < 0) {
+        goto out;
+    }
+    rcu_read_unlock();
+
+    msec = config.sample_period_seconds * 1000;
+    msec = set_sample_page_period(msec, initial_time);
+
+    rcu_read_lock();
+    if (compare_page_hash_info(block_dinfo, block_index) < 0) {
+        goto out;
+    }
+
+    update_dirtyrate(msec);
+
+out:
+    rcu_read_unlock();
+    free_ramblock_dirty_info(block_dinfo, block_index + 1);
+    rcu_unregister_thread();
+
 }
 
 void *get_dirtyrate_thread(void *arg)
-- 
1.8.3.1



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

* [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info
  2020-08-15  2:22 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
@ 2020-08-15  2:22 ` Chuan Zheng
  0 siblings, 0 replies; 11+ messages in thread
From: Chuan Zheng @ 2020-08-15  2:22 UTC (permalink / raw)
  To: quintela, eblake, dgilbert
  Cc: zhang.zhanghailiang, linyilu, qemu-devel, alex.chen,
	ann.zhuangyanying, fangying1

From: Zheng Chuan <zhengchuan@huawei.com>

Add RamlockDirtyInfo to store sampled page info of each ramblock.

Signed-off-by: Zheng Chuan <zhengchuan@huawei.com>
---
 migration/dirtyrate.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 914c363..9650566 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -19,6 +19,11 @@
  */
 #define DIRTYRATE_DEFAULT_SAMPLE_PAGES            256
 
+/*
+ * Record ramblock idstr
+ */
+#define RAMBLOCK_INFO_MAX_LEN                     256
+
 /* Take 1s as default for calculation duration */
 #define DEFAULT_FETCH_DIRTYRATE_TIME_SEC          1
 
@@ -39,6 +44,19 @@ typedef enum {
     CAL_DIRTY_RATE_END,
 } CalculatingDirtyRateState;
 
+/*
+ * Store dirtypage info for each ramblock.
+ */
+struct RamblockDirtyInfo {
+    char idstr[RAMBLOCK_INFO_MAX_LEN]; /* idstr for each ramblock */
+    uint8_t *ramblock_addr; /* base address of ramblock we measure */
+    size_t ramblock_pages; /* sum of dividation by 4K pages for ramblock */
+    size_t *sample_page_vfn; /* relative offset address for sampled page */
+    unsigned int sample_pages_count; /* sum of sampled pages */
+    unsigned int sample_dirty_count; /* sum of dirty pages we measure */
+    uint8_t *hash_result; /* array of hash result for sampled pages */
+};
+
 void *get_dirtyrate_thread(void *arg);
 #endif
 
-- 
1.8.3.1



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

end of thread, other threads:[~2020-08-15 18:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-14  9:32 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 01/10] migration/dirtyrate: Add get_dirtyrate_thread() function Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 03/10] migration/dirtyrate: Add dirtyrate statistics series functions Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 04/10] migration/dirtyrate: move RAMBLOCK_FOREACH_MIGRATABLE into ram.h Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 05/10] migration/dirtyrate: Record hash results for each sampled page Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 06/10] migration/dirtyrate: Compare page hash results for recorded " Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 07/10] migration/dirtyrate: skip sampling ramblock with size below MIN_RAMBLOCK_SIZE Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 08/10] migration/dirtyrate: Implement get_sample_page_period() and block_sample_page_period() Chuan Zheng
2020-08-14  9:32 ` [PATCH v2 09/10] migration/dirtyrate: Implement calculate_dirtyrate() function Chuan Zheng
2020-08-15  2:22 [PATCH v2 00/10] *** A Method for evaluating dirty page rate *** Chuan Zheng
2020-08-15  2:22 ` [PATCH v2 02/10] migration/dirtyrate: Add RamlockDirtyInfo to store sampled page info Chuan Zheng

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.