[PATCH v2 01/16] KVM: selftests: Clear dirty logs in user defined chunks sizes in dirty_log_perf_test

From: Vipin Sharma
Date: Fri Jun 02 2023 - 12:09:30 EST


In dirty_log_perf_test, provide a new option 'k' to specify the size of
the chunks and clear dirty memory in chunks in each iteration. If option
is not provided then fallback to the old way of clearing whole memslot
in one call in each iteration.

In production environment whole memslot is rarely cleared in a single
call, instead clearing operation is split across multiple calls to
reduce time between clearing and sending memory to a remote host. This
change mimics the production usecases and allows to get performance
numbers based on that.

Signed-off-by: Vipin Sharma <vipinsh@xxxxxxxxxx>
---
.../selftests/kvm/dirty_log_perf_test.c | 42 +++++++++++++++----
1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index e9d6d1aecf89..119ddfc7306e 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -134,6 +134,7 @@ struct test_params {
uint32_t write_percent;
uint32_t random_seed;
bool random_access;
+ uint64_t clear_chunk_size;
};

static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable)
@@ -169,16 +170,28 @@ static void get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots
}
}

-static void clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[],
- int slots, uint64_t pages_per_slot)
+static void clear_dirty_log_in_chunks(struct kvm_vm *vm,
+ unsigned long *bitmaps[], int slots,
+ uint64_t pages_per_slot,
+ uint64_t pages_per_clear)
{
- int i;
+ uint64_t from, clear_pages_count;
+ int i, slot;

for (i = 0; i < slots; i++) {
- int slot = MEMSTRESS_MEM_SLOT_INDEX + i;
-
- kvm_vm_clear_dirty_log(vm, slot, bitmaps[i], 0, pages_per_slot);
+ slot = MEMSTRESS_MEM_SLOT_INDEX + i;
+ from = 0;
+ clear_pages_count = pages_per_clear;
+
+ while (from < pages_per_slot) {
+ if (from + clear_pages_count > pages_per_slot)
+ clear_pages_count = pages_per_slot - from;
+ kvm_vm_clear_dirty_log(vm, slot, bitmaps[i], from,
+ clear_pages_count);
+ from += clear_pages_count;
+ }
}
+
}

static unsigned long **alloc_bitmaps(int slots, uint64_t pages_per_slot)
@@ -215,6 +228,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
uint64_t guest_num_pages;
uint64_t host_num_pages;
uint64_t pages_per_slot;
+ uint64_t pages_per_clear;
struct timespec start;
struct timespec ts_diff;
struct timespec get_dirty_log_total = (struct timespec){0};
@@ -235,6 +249,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
host_num_pages = vm_num_host_pages(mode, guest_num_pages);
pages_per_slot = host_num_pages / p->slots;
+ pages_per_clear = p->clear_chunk_size / getpagesize();

bitmaps = alloc_bitmaps(p->slots, pages_per_slot);

@@ -315,7 +330,9 @@ static void run_test(enum vm_guest_mode mode, void *arg)

if (dirty_log_manual_caps) {
clock_gettime(CLOCK_MONOTONIC, &start);
- clear_dirty_log(vm, bitmaps, p->slots, pages_per_slot);
+ clear_dirty_log_in_chunks(vm, bitmaps, p->slots,
+ pages_per_slot,
+ pages_per_clear);
ts_diff = timespec_elapsed(start);
clear_dirty_log_total = timespec_add(clear_dirty_log_total,
ts_diff);
@@ -413,6 +430,11 @@ static void help(char *name)
" To leave the application task unpinned, drop the final entry:\n\n"
" ./dirty_log_perf_test -v 3 -c 22,23,24\n\n"
" (default: no pinning)\n");
+ printf(" -k: Specify the chunk size in which dirty memory gets cleared\n"
+ " in memslots in each iteration. If the size is bigger than\n"
+ " the memslot size then whole memslot is cleared in one call.\n"
+ " Size must be aligned to the host page size. e.g. 10M or 3G\n"
+ " (default: UINT64_MAX, clears whole memslot in one call)\n");
puts("");
exit(0);
}
@@ -428,6 +450,7 @@ int main(int argc, char *argv[])
.slots = 1,
.random_seed = 1,
.write_percent = 100,
+ .clear_chunk_size = UINT64_MAX,
};
int opt;

@@ -438,7 +461,7 @@ int main(int argc, char *argv[])

guest_modes_append_default();

- while ((opt = getopt(argc, argv, "ab:c:eghi:m:nop:r:s:v:x:w:")) != -1) {
+ while ((opt = getopt(argc, argv, "ab:c:eghi:k:m:nop:r:s:v:x:w:")) != -1) {
switch (opt) {
case 'a':
p.random_access = true;
@@ -462,6 +485,9 @@ int main(int argc, char *argv[])
case 'i':
p.iterations = atoi_positive("Number of iterations", optarg);
break;
+ case 'k':
+ p.clear_chunk_size = parse_size(optarg);
+ break;
case 'm':
guest_modes_cmdline(optarg);
break;
--
2.41.0.rc0.172.g3f132b7071-goog