2022-10-20 07:35:55

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v3 0/6] KVM: selftests: memslot_perf_test: aarch64 cleanup/fixes

kvm/selftests/memslots_perf_test doesn't work with 64KB-page-size-host
and 4KB-page-size-guest on aarch64. In the implementation, the host and
guest page size have been hardcoded to 4KB. It's ovbiously not working
on aarch64 which supports 4KB, 16KB, 64KB individually on host and guest.

This series tries to fix it. After the series is applied, the test runs
successfully with 64KB-page-size-host and 4KB-page-size-guest.

# ./memslots_perf_tests -v -s 512

Since we're here, the code is cleaned up a bit as PATCH[1-3] do. The
other patches are fixes to handle the mismatched host/guest page
sized.

v1: https://lore.kernel.org/kvmarm/[email protected]/T/#t
v2: https://lore.kernel.org/kvmarm/[email protected]/T/#t

Changelog
=========
v3:
* Improved comments about MEM_TEST_MOVE_SIZE, which is set
to 64KB in PATCH[v3 4/6] and finally fixed to 192KB in
PATCH[v3 5/6]. (Maciej)
* Use size instead of pages to do the comparison in
test_memslot_move_prepare() (Maciej)
* Use tools/include/linux/sizes.h instead of inventing
our own macros. (Oliver)
v2:
* Pick the smaller value between the ones specified by
user or probed from KVM_CAP_NR_MEMSLOTS in PATCH[v2 3/6] (Maciej)
* Improved comments about MEM_TEST_MOVE_SIZE in
PATCH[v2 4/6] (Maciej)
* Avoid mismatched guest page size after VM is started in
prepare_vm() in PATCH[v2 4/6] (Maciej)
* Fix condition to check MEM_TEST_{UNMAP, UNMAP_CHUNK}_SIZE
in check_memory_size() in PATCH[v2 4/6] (Maciej)
* Define base and huge page size in kvm_util_base.h in
PATCH[v2 5/6] (Sean)
* Add checks on host/guest page size in check_memory_size()
and fail early if any of them exceeds 64KB in PATCH[v2 5/6] (Maciej)


Gavin Shan (6):
KVM: selftests: memslot_perf_test: Use data->nslots in prepare_vm()
KVM: selftests: memslot_perf_test: Consolidate loop conditions in
prepare_vm()
KVM: selftests: memslot_perf_test: Probe memory slots for once
KVM: selftests: memslot_perf_test: Support variable guest page size
KVM: selftests: memslot_perf_test: Consolidate memory
KVM: selftests: memslot_perf_test: Report optimal memory slots

.../testing/selftests/kvm/memslot_perf_test.c | 317 ++++++++++++------
1 file changed, 208 insertions(+), 109 deletions(-)

--
2.23.0


2022-10-20 07:53:40

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v3 5/6] KVM: selftests: memslot_perf_test: Consolidate memory

The addresses and sizes passed to vm_userspace_mem_region_add() and
madvise() should be aligned to host page size, which can be 64KB on
aarch64. So it's wrong by passing additional fixed 4KB memory area
to various tests.

Fix it by passing additional fixed 64KB memory area to various tests.
We also add checks to ensure that none of host/guest page size exceeds
64KB. MEM_TEST_MOVE_SIZE is fixed up to 192KB either.

With this, the following command works fine on 64KB-page-size-host and
4KB-page-size-guest.

# ./memslot_perf_test -v -s 512

Signed-off-by: Gavin Shan <[email protected]>
---
.../testing/selftests/kvm/memslot_perf_test.c | 43 +++++++++++--------
1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index 9af61ca8ad0a..daebc264de5a 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -20,17 +20,20 @@
#include <unistd.h>

#include <linux/compiler.h>
+#include <linux/sizes.h>

#include <test_util.h>
#include <kvm_util.h>
#include <processor.h>

-#define MEM_SIZE ((512U << 20) + 4096)
-#define MEM_GPA 0x10000000UL
+#define MEM_EXTRA_SIZE SZ_64K
+
+#define MEM_SIZE (SZ_512M + MEM_EXTRA_SIZE)
+#define MEM_GPA SZ_256M
#define MEM_AUX_GPA MEM_GPA
#define MEM_SYNC_GPA MEM_AUX_GPA
-#define MEM_TEST_GPA (MEM_AUX_GPA + 4096)
-#define MEM_TEST_SIZE (MEM_SIZE - 4096)
+#define MEM_TEST_GPA (MEM_AUX_GPA + MEM_EXTRA_SIZE)
+#define MEM_TEST_SIZE (MEM_SIZE - MEM_EXTRA_SIZE)

/*
* 32 MiB is max size that gets well over 100 iterations on 509 slots.
@@ -38,8 +41,8 @@
* 8194 slots in use can then be tested (although with slightly
* limited resolution).
*/
-#define MEM_SIZE_MAP ((32U << 20) + 4096)
-#define MEM_TEST_MAP_SIZE (MEM_SIZE_MAP - 4096)
+#define MEM_SIZE_MAP (SZ_32M + MEM_EXTRA_SIZE)
+#define MEM_TEST_MAP_SIZE (MEM_SIZE_MAP - MEM_EXTRA_SIZE)

/*
* 128 MiB is min size that fills 32k slots with at least one page in each
@@ -47,8 +50,8 @@
*
* 2 MiB chunk size like a typical huge page
*/
-#define MEM_TEST_UNMAP_SIZE (128U << 20)
-#define MEM_TEST_UNMAP_CHUNK_SIZE (2U << 20)
+#define MEM_TEST_UNMAP_SIZE SZ_128M
+#define MEM_TEST_UNMAP_CHUNK_SIZE SZ_2M

/*
* For the move active test the middle of the test area is placed on
@@ -64,12 +67,12 @@
*
* architecture slots memory-per-slot memory-on-last-slot
* --------------------------------------------------------------
- * x86-4KB 32763 16KB 100KB
- * arm64-4KB 32766 16KB 52KB
- * arm64-16KB 32766 16KB 48KB
- * arm64-64KB 8192 64KB 64KB
+ * x86-4KB 32763 16KB 160KB
+ * arm64-4KB 32766 16KB 112KB
+ * arm64-16KB 32766 16KB 112KB
+ * arm64-64KB 8192 64KB 128KB
*/
-#define MEM_TEST_MOVE_SIZE 0x10000
+#define MEM_TEST_MOVE_SIZE (3 * SZ_64K)
#define MEM_TEST_MOVE_GPA_DEST (MEM_GPA + MEM_SIZE)
static_assert(MEM_TEST_MOVE_SIZE <= MEM_TEST_SIZE,
"invalid move test region size");
@@ -533,7 +536,6 @@ static bool test_memslot_move_prepare(struct vm_data *data,
uint64_t *maxslots, bool isactive)
{
uint32_t guest_page_size = data->vm->page_size;
- uint64_t move_pages = MEM_TEST_MOVE_SIZE / guest_page_size;
uint64_t movesrcgpa, movetestgpa;

movesrcgpa = vm_slot2gpa(data, data->nslots - 1);
@@ -542,7 +544,7 @@ static bool test_memslot_move_prepare(struct vm_data *data,
uint64_t lastpages;

vm_gpa2hva(data, movesrcgpa, &lastpages);
- if (lastpages < move_pages / 2) {
+ if (lastpages * guest_page_size < MEM_TEST_MOVE_SIZE / 2) {
*maxslots = 0;
return false;
}
@@ -808,13 +810,13 @@ static const struct test_data tests[] = {
},
{
.name = "unmap",
- .mem_size = MEM_TEST_UNMAP_SIZE + 4096,
+ .mem_size = MEM_TEST_UNMAP_SIZE + MEM_EXTRA_SIZE,
.guest_code = guest_code_test_memslot_unmap,
.loop = test_memslot_unmap_loop,
},
{
.name = "unmap chunked",
- .mem_size = MEM_TEST_UNMAP_SIZE + 4096,
+ .mem_size = MEM_TEST_UNMAP_SIZE + MEM_EXTRA_SIZE,
.guest_code = guest_code_test_memslot_unmap,
.loop = test_memslot_unmap_loop_chunked,
},
@@ -874,8 +876,15 @@ static void help(char *name, struct test_args *targs)

static bool check_memory_sizes(void)
{
+ uint32_t host_page_size = getpagesize();
uint32_t guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size;

+ if (host_page_size > SZ_64K || guest_page_size > SZ_64K) {
+ pr_info("Unsupported page size on host (0x%x) or guest (0x%x)\n",
+ host_page_size, guest_page_size);
+ return false;
+ }
+
if (MEM_SIZE % guest_page_size ||
MEM_TEST_SIZE % guest_page_size) {
pr_info("invalid MEM_SIZE or MEM_TEST_SIZE\n");
--
2.23.0

2022-10-20 07:59:42

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v3 4/6] KVM: selftests: memslot_perf_test: Support variable guest page size

The test case is obviously broken on aarch64 because non-4KB guest
page size is supported. The guest page size on aarch64 could be 4KB,
16KB or 64KB.

This supports variable guest page size, mostly for aarch64.

- The host determines the guest page size when virtual machine is
created. The value is also passed to guest through the synchronization
area.

- The number of guest pages are unknown until the virtual machine
is to be created. So all the related macros are dropped. Instead,
their values are dynamically calculated based on the guest page
size.

- The static checks on memory sizes and pages becomes dependent
on guest page size, which is unknown until the virtual machine
is about to be created. So all the static checks are converted
to dynamic checks, done in check_memory_sizes().

- As the address passed to madvise() should be aligned to host page,
the size of page chunk is automatically selected, other than one
page.

- MEM_TEST_MOVE_SIZE has fixed and non-working 64KB. It will be
consolidated in next patch. However, the comments about how
it's calculated has been correct.

- All other changes included in this patch are almost mechanical
replacing '4096' with 'guest_page_size'.

Signed-off-by: Gavin Shan <[email protected]>
---
.../testing/selftests/kvm/memslot_perf_test.c | 210 +++++++++++-------
1 file changed, 129 insertions(+), 81 deletions(-)

diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index f0ea3f75b6e1..9af61ca8ad0a 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -26,14 +26,11 @@
#include <processor.h>

#define MEM_SIZE ((512U << 20) + 4096)
-#define MEM_SIZE_PAGES (MEM_SIZE / 4096)
#define MEM_GPA 0x10000000UL
#define MEM_AUX_GPA MEM_GPA
#define MEM_SYNC_GPA MEM_AUX_GPA
#define MEM_TEST_GPA (MEM_AUX_GPA + 4096)
#define MEM_TEST_SIZE (MEM_SIZE - 4096)
-static_assert(MEM_SIZE % 4096 == 0, "invalid mem size");
-static_assert(MEM_TEST_SIZE % 4096 == 0, "invalid mem test size");

/*
* 32 MiB is max size that gets well over 100 iterations on 509 slots.
@@ -42,43 +39,37 @@ static_assert(MEM_TEST_SIZE % 4096 == 0, "invalid mem test size");
* limited resolution).
*/
#define MEM_SIZE_MAP ((32U << 20) + 4096)
-#define MEM_SIZE_MAP_PAGES (MEM_SIZE_MAP / 4096)
#define MEM_TEST_MAP_SIZE (MEM_SIZE_MAP - 4096)
-#define MEM_TEST_MAP_SIZE_PAGES (MEM_TEST_MAP_SIZE / 4096)
-static_assert(MEM_SIZE_MAP % 4096 == 0, "invalid map test region size");
-static_assert(MEM_TEST_MAP_SIZE % 4096 == 0, "invalid map test region size");
-static_assert(MEM_TEST_MAP_SIZE_PAGES % 2 == 0, "invalid map test region size");
-static_assert(MEM_TEST_MAP_SIZE_PAGES > 2, "invalid map test region size");

/*
* 128 MiB is min size that fills 32k slots with at least one page in each
* while at the same time gets 100+ iterations in such test
+ *
+ * 2 MiB chunk size like a typical huge page
*/
#define MEM_TEST_UNMAP_SIZE (128U << 20)
-#define MEM_TEST_UNMAP_SIZE_PAGES (MEM_TEST_UNMAP_SIZE / 4096)
-/* 2 MiB chunk size like a typical huge page */
-#define MEM_TEST_UNMAP_CHUNK_PAGES (2U << (20 - 12))
-static_assert(MEM_TEST_UNMAP_SIZE <= MEM_TEST_SIZE,
- "invalid unmap test region size");
-static_assert(MEM_TEST_UNMAP_SIZE % 4096 == 0,
- "invalid unmap test region size");
-static_assert(MEM_TEST_UNMAP_SIZE_PAGES %
- (2 * MEM_TEST_UNMAP_CHUNK_PAGES) == 0,
- "invalid unmap test region size");
+#define MEM_TEST_UNMAP_CHUNK_SIZE (2U << 20)

/*
* For the move active test the middle of the test area is placed on
* a memslot boundary: half lies in the memslot being moved, half in
* other memslot(s).
*
- * When running this test with 32k memslots (32764, really) each memslot
- * contains 4 pages.
- * The last one additionally contains the remaining 21 pages of memory,
- * for the total size of 25 pages.
- * Hence, the maximum size here is 50 pages.
+ * We have different number of memory slots, excluding the reserved
+ * memory slot 0, on various architectures and configurations. The
+ * memory size in this test is calculated by picking the maximal
+ * last memory slot's memory size, with alignment to the largest
+ * supported page size (64KB). In this way, the selected memory
+ * size for this test is compatible with test_memslot_move_prepare().
+ *
+ * architecture slots memory-per-slot memory-on-last-slot
+ * --------------------------------------------------------------
+ * x86-4KB 32763 16KB 100KB
+ * arm64-4KB 32766 16KB 52KB
+ * arm64-16KB 32766 16KB 48KB
+ * arm64-64KB 8192 64KB 64KB
*/
-#define MEM_TEST_MOVE_SIZE_PAGES (50)
-#define MEM_TEST_MOVE_SIZE (MEM_TEST_MOVE_SIZE_PAGES * 4096)
+#define MEM_TEST_MOVE_SIZE 0x10000
#define MEM_TEST_MOVE_GPA_DEST (MEM_GPA + MEM_SIZE)
static_assert(MEM_TEST_MOVE_SIZE <= MEM_TEST_SIZE,
"invalid move test region size");
@@ -100,6 +91,7 @@ struct vm_data {
};

struct sync_area {
+ uint32_t guest_page_size;
atomic_bool start_flag;
atomic_bool exit_flag;
atomic_bool sync_flag;
@@ -192,14 +184,15 @@ static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages)
uint64_t gpage, pgoffs;
uint32_t slot, slotoffs;
void *base;
+ uint32_t guest_page_size = data->vm->page_size;

TEST_ASSERT(gpa >= MEM_GPA, "Too low gpa to translate");
- TEST_ASSERT(gpa < MEM_GPA + data->npages * 4096,
+ TEST_ASSERT(gpa < MEM_GPA + data->npages * guest_page_size,
"Too high gpa to translate");
gpa -= MEM_GPA;

- gpage = gpa / 4096;
- pgoffs = gpa % 4096;
+ gpage = gpa / guest_page_size;
+ pgoffs = gpa % guest_page_size;
slot = min(gpage / data->pages_per_slot, (uint64_t)data->nslots - 1);
slotoffs = gpage - (slot * data->pages_per_slot);

@@ -217,14 +210,16 @@ static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages)
}

base = data->hva_slots[slot];
- return (uint8_t *)base + slotoffs * 4096 + pgoffs;
+ return (uint8_t *)base + slotoffs * guest_page_size + pgoffs;
}

static uint64_t vm_slot2gpa(struct vm_data *data, uint32_t slot)
{
+ uint32_t guest_page_size = data->vm->page_size;
+
TEST_ASSERT(slot < data->nslots, "Too high slot number");

- return MEM_GPA + slot * data->pages_per_slot * 4096;
+ return MEM_GPA + slot * data->pages_per_slot * guest_page_size;
}

static struct vm_data *alloc_vm(void)
@@ -242,33 +237,35 @@ static struct vm_data *alloc_vm(void)
}

static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
- void *guest_code, uint64_t mempages,
+ void *guest_code, uint64_t mem_size,
struct timespec *slot_runtime)
{
- uint64_t rempages;
+ uint64_t mempages, rempages;
uint64_t guest_addr;
- uint32_t slot;
+ uint32_t slot, guest_page_size;
struct timespec tstart;
struct sync_area *sync;

- TEST_ASSERT(mempages > 1,
- "Can't test without any memory");
+ guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size;
+ mempages = mem_size / guest_page_size;
+
+ data->vm = __vm_create_with_one_vcpu(&data->vcpu, mempages, guest_code);
+ ucall_init(data->vm, NULL);
+ TEST_ASSERT(data->vm->page_size == guest_page_size, "Invalid VM page size");

data->npages = mempages;
+ TEST_ASSERT(data->npages > 1, "Can't test without any memory");
data->nslots = nslots;
- data->pages_per_slot = mempages / data->nslots;
+ data->pages_per_slot = data->npages / data->nslots;
if (!data->pages_per_slot) {
- *maxslots = mempages + 1;
+ *maxslots = data->npages + 1;
return false;
}

- rempages = mempages % data->nslots;
+ rempages = data->npages % data->nslots;
data->hva_slots = malloc(sizeof(*data->hva_slots) * data->nslots);
TEST_ASSERT(data->hva_slots, "malloc() fail");

- data->vm = __vm_create_with_one_vcpu(&data->vcpu, mempages, guest_code);
- ucall_init(data->vm, NULL);
-
pr_info_v("Adding slots 1..%i, each slot with %"PRIu64" pages + %"PRIu64" extra pages last\n",
data->nslots, data->pages_per_slot, rempages);

@@ -283,7 +280,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
vm_userspace_mem_region_add(data->vm, VM_MEM_SRC_ANONYMOUS,
guest_addr, slot, npages,
0);
- guest_addr += npages * 4096;
+ guest_addr += npages * guest_page_size;
}
*slot_runtime = timespec_elapsed(tstart);

@@ -300,12 +297,12 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
"vm_phy_pages_alloc() failed\n");

data->hva_slots[slot - 1] = addr_gpa2hva(data->vm, guest_addr);
- memset(data->hva_slots[slot - 1], 0, npages * 4096);
+ memset(data->hva_slots[slot - 1], 0, npages * guest_page_size);

- guest_addr += npages * 4096;
+ guest_addr += npages * guest_page_size;
}

- virt_map(data->vm, MEM_GPA, MEM_GPA, mempages);
+ virt_map(data->vm, MEM_GPA, MEM_GPA, data->npages);

sync = (typeof(sync))vm_gpa2hva(data, MEM_SYNC_GPA, NULL);
atomic_init(&sync->start_flag, false);
@@ -404,6 +401,7 @@ static bool guest_perform_sync(void)
static void guest_code_test_memslot_move(void)
{
struct sync_area *sync = (typeof(sync))MEM_SYNC_GPA;
+ uint32_t page_size = (typeof(page_size))READ_ONCE(sync->guest_page_size);
uintptr_t base = (typeof(base))READ_ONCE(sync->move_area_ptr);

GUEST_SYNC(0);
@@ -414,7 +412,7 @@ static void guest_code_test_memslot_move(void)
uintptr_t ptr;

for (ptr = base; ptr < base + MEM_TEST_MOVE_SIZE;
- ptr += 4096)
+ ptr += page_size)
*(uint64_t *)ptr = MEM_TEST_VAL_1;

/*
@@ -432,6 +430,7 @@ static void guest_code_test_memslot_move(void)
static void guest_code_test_memslot_map(void)
{
struct sync_area *sync = (typeof(sync))MEM_SYNC_GPA;
+ uint32_t page_size = (typeof(page_size))READ_ONCE(sync->guest_page_size);

GUEST_SYNC(0);

@@ -441,14 +440,16 @@ static void guest_code_test_memslot_map(void)
uintptr_t ptr;

for (ptr = MEM_TEST_GPA;
- ptr < MEM_TEST_GPA + MEM_TEST_MAP_SIZE / 2; ptr += 4096)
+ ptr < MEM_TEST_GPA + MEM_TEST_MAP_SIZE / 2;
+ ptr += page_size)
*(uint64_t *)ptr = MEM_TEST_VAL_1;

if (!guest_perform_sync())
break;

for (ptr = MEM_TEST_GPA + MEM_TEST_MAP_SIZE / 2;
- ptr < MEM_TEST_GPA + MEM_TEST_MAP_SIZE; ptr += 4096)
+ ptr < MEM_TEST_GPA + MEM_TEST_MAP_SIZE;
+ ptr += page_size)
*(uint64_t *)ptr = MEM_TEST_VAL_2;

if (!guest_perform_sync())
@@ -495,6 +496,9 @@ static void guest_code_test_memslot_unmap(void)

static void guest_code_test_memslot_rw(void)
{
+ struct sync_area *sync = (typeof(sync))MEM_SYNC_GPA;
+ uint32_t page_size = (typeof(page_size))READ_ONCE(sync->guest_page_size);
+
GUEST_SYNC(0);

guest_spin_until_start();
@@ -503,14 +507,14 @@ static void guest_code_test_memslot_rw(void)
uintptr_t ptr;

for (ptr = MEM_TEST_GPA;
- ptr < MEM_TEST_GPA + MEM_TEST_SIZE; ptr += 4096)
+ ptr < MEM_TEST_GPA + MEM_TEST_SIZE; ptr += page_size)
*(uint64_t *)ptr = MEM_TEST_VAL_1;

if (!guest_perform_sync())
break;

- for (ptr = MEM_TEST_GPA + 4096 / 2;
- ptr < MEM_TEST_GPA + MEM_TEST_SIZE; ptr += 4096) {
+ for (ptr = MEM_TEST_GPA + page_size / 2;
+ ptr < MEM_TEST_GPA + MEM_TEST_SIZE; ptr += page_size) {
uint64_t val = *(uint64_t *)ptr;

GUEST_ASSERT_1(val == MEM_TEST_VAL_2, val);
@@ -528,6 +532,8 @@ static bool test_memslot_move_prepare(struct vm_data *data,
struct sync_area *sync,
uint64_t *maxslots, bool isactive)
{
+ uint32_t guest_page_size = data->vm->page_size;
+ uint64_t move_pages = MEM_TEST_MOVE_SIZE / guest_page_size;
uint64_t movesrcgpa, movetestgpa;

movesrcgpa = vm_slot2gpa(data, data->nslots - 1);
@@ -536,7 +542,7 @@ static bool test_memslot_move_prepare(struct vm_data *data,
uint64_t lastpages;

vm_gpa2hva(data, movesrcgpa, &lastpages);
- if (lastpages < MEM_TEST_MOVE_SIZE_PAGES / 2) {
+ if (lastpages < move_pages / 2) {
*maxslots = 0;
return false;
}
@@ -582,8 +588,9 @@ static void test_memslot_do_unmap(struct vm_data *data,
uint64_t offsp, uint64_t count)
{
uint64_t gpa, ctr;
+ uint32_t guest_page_size = data->vm->page_size;

- for (gpa = MEM_TEST_GPA + offsp * 4096, ctr = 0; ctr < count; ) {
+ for (gpa = MEM_TEST_GPA + offsp * guest_page_size, ctr = 0; ctr < count; ) {
uint64_t npages;
void *hva;
int ret;
@@ -591,12 +598,12 @@ static void test_memslot_do_unmap(struct vm_data *data,
hva = vm_gpa2hva(data, gpa, &npages);
TEST_ASSERT(npages, "Empty memory slot at gptr 0x%"PRIx64, gpa);
npages = min(npages, count - ctr);
- ret = madvise(hva, npages * 4096, MADV_DONTNEED);
+ ret = madvise(hva, npages * guest_page_size, MADV_DONTNEED);
TEST_ASSERT(!ret,
"madvise(%p, MADV_DONTNEED) on VM memory should not fail for gptr 0x%"PRIx64,
hva, gpa);
ctr += npages;
- gpa += npages * 4096;
+ gpa += npages * guest_page_size;
}
TEST_ASSERT(ctr == count,
"madvise(MADV_DONTNEED) should exactly cover all of the requested area");
@@ -607,11 +614,12 @@ static void test_memslot_map_unmap_check(struct vm_data *data,
{
uint64_t gpa;
uint64_t *val;
+ uint32_t guest_page_size = data->vm->page_size;

if (!map_unmap_verify)
return;

- gpa = MEM_TEST_GPA + offsp * 4096;
+ gpa = MEM_TEST_GPA + offsp * guest_page_size;
val = (typeof(val))vm_gpa2hva(data, gpa, NULL);
TEST_ASSERT(*val == valexp,
"Guest written values should read back correctly before unmap (%"PRIu64" vs %"PRIu64" @ %"PRIx64")",
@@ -621,12 +629,14 @@ static void test_memslot_map_unmap_check(struct vm_data *data,

static void test_memslot_map_loop(struct vm_data *data, struct sync_area *sync)
{
+ uint32_t guest_page_size = data->vm->page_size;
+ uint64_t guest_pages = MEM_TEST_MAP_SIZE / guest_page_size;
+
/*
* Unmap the second half of the test area while guest writes to (maps)
* the first half.
*/
- test_memslot_do_unmap(data, MEM_TEST_MAP_SIZE_PAGES / 2,
- MEM_TEST_MAP_SIZE_PAGES / 2);
+ test_memslot_do_unmap(data, guest_pages / 2, guest_pages / 2);

/*
* Wait for the guest to finish writing the first half of the test
@@ -637,10 +647,8 @@ static void test_memslot_map_loop(struct vm_data *data, struct sync_area *sync)
*/
host_perform_sync(sync);
test_memslot_map_unmap_check(data, 0, MEM_TEST_VAL_1);
- test_memslot_map_unmap_check(data,
- MEM_TEST_MAP_SIZE_PAGES / 2 - 1,
- MEM_TEST_VAL_1);
- test_memslot_do_unmap(data, 0, MEM_TEST_MAP_SIZE_PAGES / 2);
+ test_memslot_map_unmap_check(data, guest_pages / 2 - 1, MEM_TEST_VAL_1);
+ test_memslot_do_unmap(data, 0, guest_pages / 2);


/*
@@ -653,16 +661,16 @@ static void test_memslot_map_loop(struct vm_data *data, struct sync_area *sync)
* the test area.
*/
host_perform_sync(sync);
- test_memslot_map_unmap_check(data, MEM_TEST_MAP_SIZE_PAGES / 2,
- MEM_TEST_VAL_2);
- test_memslot_map_unmap_check(data, MEM_TEST_MAP_SIZE_PAGES - 1,
- MEM_TEST_VAL_2);
+ test_memslot_map_unmap_check(data, guest_pages / 2, MEM_TEST_VAL_2);
+ test_memslot_map_unmap_check(data, guest_pages - 1, MEM_TEST_VAL_2);
}

static void test_memslot_unmap_loop_common(struct vm_data *data,
struct sync_area *sync,
uint64_t chunk)
{
+ uint32_t guest_page_size = data->vm->page_size;
+ uint64_t guest_pages = MEM_TEST_UNMAP_SIZE / guest_page_size;
uint64_t ctr;

/*
@@ -674,42 +682,49 @@ static void test_memslot_unmap_loop_common(struct vm_data *data,
*/
host_perform_sync(sync);
test_memslot_map_unmap_check(data, 0, MEM_TEST_VAL_1);
- for (ctr = 0; ctr < MEM_TEST_UNMAP_SIZE_PAGES / 2; ctr += chunk)
+ for (ctr = 0; ctr < guest_pages / 2; ctr += chunk)
test_memslot_do_unmap(data, ctr, chunk);

/* Likewise, but for the opposite host / guest areas */
host_perform_sync(sync);
- test_memslot_map_unmap_check(data, MEM_TEST_UNMAP_SIZE_PAGES / 2,
- MEM_TEST_VAL_2);
- for (ctr = MEM_TEST_UNMAP_SIZE_PAGES / 2;
- ctr < MEM_TEST_UNMAP_SIZE_PAGES; ctr += chunk)
+ test_memslot_map_unmap_check(data, guest_pages / 2, MEM_TEST_VAL_2);
+ for (ctr = guest_pages / 2; ctr < guest_pages; ctr += chunk)
test_memslot_do_unmap(data, ctr, chunk);
}

static void test_memslot_unmap_loop(struct vm_data *data,
struct sync_area *sync)
{
- test_memslot_unmap_loop_common(data, sync, 1);
+ uint32_t host_page_size = getpagesize();
+ uint32_t guest_page_size = data->vm->page_size;
+ uint64_t guest_chunk_pages = guest_page_size >= host_page_size ?
+ 1 : host_page_size / guest_page_size;
+
+ test_memslot_unmap_loop_common(data, sync, guest_chunk_pages);
}

static void test_memslot_unmap_loop_chunked(struct vm_data *data,
struct sync_area *sync)
{
- test_memslot_unmap_loop_common(data, sync, MEM_TEST_UNMAP_CHUNK_PAGES);
+ uint32_t guest_page_size = data->vm->page_size;
+ uint64_t guest_chunk_pages = MEM_TEST_UNMAP_CHUNK_SIZE / guest_page_size;
+
+ test_memslot_unmap_loop_common(data, sync, guest_chunk_pages);
}

static void test_memslot_rw_loop(struct vm_data *data, struct sync_area *sync)
{
uint64_t gptr;
+ uint32_t guest_page_size = data->vm->page_size;

- for (gptr = MEM_TEST_GPA + 4096 / 2;
- gptr < MEM_TEST_GPA + MEM_TEST_SIZE; gptr += 4096)
+ for (gptr = MEM_TEST_GPA + guest_page_size / 2;
+ gptr < MEM_TEST_GPA + MEM_TEST_SIZE; gptr += guest_page_size)
*(uint64_t *)vm_gpa2hva(data, gptr, NULL) = MEM_TEST_VAL_2;

host_perform_sync(sync);

for (gptr = MEM_TEST_GPA;
- gptr < MEM_TEST_GPA + MEM_TEST_SIZE; gptr += 4096) {
+ gptr < MEM_TEST_GPA + MEM_TEST_SIZE; gptr += guest_page_size) {
uint64_t *vptr = (typeof(vptr))vm_gpa2hva(data, gptr, NULL);
uint64_t val = *vptr;

@@ -738,7 +753,7 @@ static bool test_execute(int nslots, uint64_t *maxslots,
struct timespec *slot_runtime,
struct timespec *guest_runtime)
{
- uint64_t mem_size = tdata->mem_size ? : MEM_SIZE_PAGES;
+ uint64_t mem_size = tdata->mem_size ? : MEM_SIZE;
struct vm_data *data;
struct sync_area *sync;
struct timespec tstart;
@@ -753,6 +768,7 @@ static bool test_execute(int nslots, uint64_t *maxslots,

sync = (typeof(sync))vm_gpa2hva(data, MEM_SYNC_GPA, NULL);

+ sync->guest_page_size = data->vm->page_size;
if (tdata->prepare &&
!tdata->prepare(data, sync, maxslots)) {
ret = false;
@@ -786,19 +802,19 @@ static bool test_execute(int nslots, uint64_t *maxslots,
static const struct test_data tests[] = {
{
.name = "map",
- .mem_size = MEM_SIZE_MAP_PAGES,
+ .mem_size = MEM_SIZE_MAP,
.guest_code = guest_code_test_memslot_map,
.loop = test_memslot_map_loop,
},
{
.name = "unmap",
- .mem_size = MEM_TEST_UNMAP_SIZE_PAGES + 1,
+ .mem_size = MEM_TEST_UNMAP_SIZE + 4096,
.guest_code = guest_code_test_memslot_unmap,
.loop = test_memslot_unmap_loop,
},
{
.name = "unmap chunked",
- .mem_size = MEM_TEST_UNMAP_SIZE_PAGES + 1,
+ .mem_size = MEM_TEST_UNMAP_SIZE + 4096,
.guest_code = guest_code_test_memslot_unmap,
.loop = test_memslot_unmap_loop_chunked,
},
@@ -856,6 +872,35 @@ static void help(char *name, struct test_args *targs)
pr_info("%d: %s\n", ctr, tests[ctr].name);
}

+static bool check_memory_sizes(void)
+{
+ uint32_t guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size;
+
+ if (MEM_SIZE % guest_page_size ||
+ MEM_TEST_SIZE % guest_page_size) {
+ pr_info("invalid MEM_SIZE or MEM_TEST_SIZE\n");
+ return false;
+ }
+
+ if (MEM_SIZE_MAP % guest_page_size ||
+ MEM_TEST_MAP_SIZE % guest_page_size ||
+ (MEM_TEST_MAP_SIZE / guest_page_size) <= 2 ||
+ (MEM_TEST_MAP_SIZE / guest_page_size) % 2) {
+ pr_info("invalid MEM_SIZE_MAP or MEM_TEST_MAP_SIZE\n");
+ return false;
+ }
+
+ if (MEM_TEST_UNMAP_SIZE > MEM_TEST_SIZE ||
+ MEM_TEST_UNMAP_SIZE % guest_page_size ||
+ (MEM_TEST_UNMAP_SIZE / guest_page_size) %
+ (2 * MEM_TEST_UNMAP_CHUNK_SIZE / guest_page_size)) {
+ pr_info("invalid MEM_TEST_UNMAP_SIZE or MEM_TEST_UNMAP_CHUNK_SIZE\n");
+ return false;
+ }
+
+ return true;
+}
+
static bool parse_args(int argc, char *argv[],
struct test_args *targs)
{
@@ -1015,6 +1060,9 @@ int main(int argc, char *argv[])
/* Tell stdout not to buffer its content */
setbuf(stdout, NULL);

+ if (!check_memory_sizes())
+ return -1;
+
if (!parse_args(argc, argv, &targs))
return -1;

--
2.23.0

2022-10-20 08:04:10

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v3 3/6] KVM: selftests: memslot_perf_test: Probe memory slots for once

prepare_vm() is called in every iteration and run. The allowed memory
slots (KVM_CAP_NR_MEMSLOTS) are probed for multiple times. It's not
free and unnecessary.

Move the probing logic for the allowed memory slots to parse_args()
for once, which is upper layer of prepare_vm().

No functional change intended.

Signed-off-by: Gavin Shan <[email protected]>
---
.../testing/selftests/kvm/memslot_perf_test.c | 32 +++++++++++--------
1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index dcb492b3f27b..f0ea3f75b6e1 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -245,27 +245,17 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
void *guest_code, uint64_t mempages,
struct timespec *slot_runtime)
{
- uint32_t max_mem_slots;
uint64_t rempages;
uint64_t guest_addr;
uint32_t slot;
struct timespec tstart;
struct sync_area *sync;

- max_mem_slots = kvm_check_cap(KVM_CAP_NR_MEMSLOTS);
- TEST_ASSERT(max_mem_slots > 1,
- "KVM_CAP_NR_MEMSLOTS should be greater than 1");
- TEST_ASSERT(nslots > 1 || nslots == -1,
- "Slot count cap should be greater than 1");
- if (nslots != -1)
- max_mem_slots = min(max_mem_slots, (uint32_t)nslots);
- pr_info_v("Allowed number of memory slots: %"PRIu32"\n", max_mem_slots);
-
TEST_ASSERT(mempages > 1,
"Can't test without any memory");

data->npages = mempages;
- data->nslots = max_mem_slots - 1;
+ data->nslots = nslots;
data->pages_per_slot = mempages / data->nslots;
if (!data->pages_per_slot) {
*maxslots = mempages + 1;
@@ -869,6 +859,7 @@ static void help(char *name, struct test_args *targs)
static bool parse_args(int argc, char *argv[],
struct test_args *targs)
{
+ uint32_t max_mem_slots;
int opt;

while ((opt = getopt(argc, argv, "hvds:f:e:l:r:")) != -1) {
@@ -885,8 +876,8 @@ static bool parse_args(int argc, char *argv[],
break;
case 's':
targs->nslots = atoi(optarg);
- if (targs->nslots <= 0 && targs->nslots != -1) {
- pr_info("Slot count cap has to be positive or -1 for no cap\n");
+ if (targs->nslots <= 1 && targs->nslots != -1) {
+ pr_info("Slot count cap must be larger than 1 or -1 for no cap\n");
return false;
}
break;
@@ -932,6 +923,21 @@ static bool parse_args(int argc, char *argv[],
return false;
}

+ max_mem_slots = kvm_check_cap(KVM_CAP_NR_MEMSLOTS);
+ if (max_mem_slots <= 1) {
+ pr_info("KVM_CAP_NR_MEMSLOTS should be greater than 1\n");
+ return false;
+ }
+
+ /* Memory slot 0 is reserved */
+ if (targs->nslots == -1)
+ targs->nslots = max_mem_slots - 1;
+ else
+ targs->nslots = min_t(int, targs->nslots, max_mem_slots) - 1;
+
+ pr_info_v("Allowed Number of memory slots: %"PRIu32"\n",
+ targs->nslots + 1);
+
return true;
}

--
2.23.0

2022-10-25 01:05:48

by Maciej S. Szmigiero

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] KVM: selftests: memslot_perf_test: aarch64 cleanup/fixes

On 20.10.2022 09:12, Gavin Shan wrote:
> kvm/selftests/memslots_perf_test doesn't work with 64KB-page-size-host
> and 4KB-page-size-guest on aarch64. In the implementation, the host and
> guest page size have been hardcoded to 4KB. It's ovbiously not working
> on aarch64 which supports 4KB, 16KB, 64KB individually on host and guest.
>
> This series tries to fix it. After the series is applied, the test runs
> successfully with 64KB-page-size-host and 4KB-page-size-guest.
>
> # ./memslots_perf_tests -v -s 512
>
> Since we're here, the code is cleaned up a bit as PATCH[1-3] do. The
> other patches are fixes to handle the mismatched host/guest page
> sized.
>
> v1: https://lore.kernel.org/kvmarm/[email protected]/T/#t
> v2: https://lore.kernel.org/kvmarm/[email protected]/T/#t
>
> Changelog
> =========
> v3:
> * Improved comments about MEM_TEST_MOVE_SIZE, which is set
> to 64KB in PATCH[v3 4/6] and finally fixed to 192KB in
> PATCH[v3 5/6]. (Maciej)
> * Use size instead of pages to do the comparison in
> test_memslot_move_prepare() (Maciej)
> * Use tools/include/linux/sizes.h instead of inventing
> our own macros. (Oliver)
> v2:
> * Pick the smaller value between the ones specified by
> user or probed from KVM_CAP_NR_MEMSLOTS in PATCH[v2 3/6] (Maciej)
> * Improved comments about MEM_TEST_MOVE_SIZE in
> PATCH[v2 4/6] (Maciej)
> * Avoid mismatched guest page size after VM is started in
> prepare_vm() in PATCH[v2 4/6] (Maciej)
> * Fix condition to check MEM_TEST_{UNMAP, UNMAP_CHUNK}_SIZE
> in check_memory_size() in PATCH[v2 4/6] (Maciej)
> * Define base and huge page size in kvm_util_base.h in
> PATCH[v2 5/6] (Sean)
> * Add checks on host/guest page size in check_memory_size()
> and fail early if any of them exceeds 64KB in PATCH[v2 5/6] (Maciej)
>
>
> Gavin Shan (6):
> KVM: selftests: memslot_perf_test: Use data->nslots in prepare_vm()
> KVM: selftests: memslot_perf_test: Consolidate loop conditions in
> prepare_vm()
> KVM: selftests: memslot_perf_test: Probe memory slots for once
> KVM: selftests: memslot_perf_test: Support variable guest page size
> KVM: selftests: memslot_perf_test: Consolidate memory
> KVM: selftests: memslot_perf_test: Report optimal memory slots
>

This patch set now looks good to me, so for the whole series:
Reviewed-by: Maciej S. Szmigiero <[email protected]>

Thanks,
Maciej

2022-11-05 00:20:34

by Gavin Shan

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] KVM: selftests: memslot_perf_test: aarch64 cleanup/fixes

On 10/25/22 7:18 AM, Maciej S. Szmigiero wrote:
> On 20.10.2022 09:12, Gavin Shan wrote:
>> kvm/selftests/memslots_perf_test doesn't work with 64KB-page-size-host
>> and 4KB-page-size-guest on aarch64. In the implementation, the host and
>> guest page size have been hardcoded to 4KB. It's ovbiously not working
>> on aarch64 which supports 4KB, 16KB, 64KB individually on host and guest.
>>
>> This series tries to fix it. After the series is applied, the test runs
>> successfully with 64KB-page-size-host and 4KB-page-size-guest.
>>
>>     # ./memslots_perf_tests -v -s 512
>>
>> Since we're here, the code is cleaned up a bit as PATCH[1-3] do. The
>> other patches are fixes to handle the mismatched host/guest page
>> sized.
>>
>> v1: https://lore.kernel.org/kvmarm/[email protected]/T/#t
>> v2: https://lore.kernel.org/kvmarm/[email protected]/T/#t
>>
>> Changelog
>> =========
>> v3:
>>    * Improved comments about MEM_TEST_MOVE_SIZE, which is set
>>      to 64KB in PATCH[v3 4/6] and finally fixed to 192KB in
>>      PATCH[v3 5/6].                                              (Maciej)
>>    * Use size instead of pages to do the comparison in
>>      test_memslot_move_prepare()                                 (Maciej)
>>    * Use tools/include/linux/sizes.h instead of inventing
>>      our own macros.                                             (Oliver)
>> v2:
>>    * Pick the smaller value between the ones specified by
>>      user or probed from KVM_CAP_NR_MEMSLOTS in PATCH[v2 3/6]    (Maciej)
>>    * Improved comments about MEM_TEST_MOVE_SIZE in
>>      PATCH[v2 4/6]                                               (Maciej)
>>    * Avoid mismatched guest page size after VM is started in
>>      prepare_vm() in PATCH[v2 4/6]                               (Maciej)
>>    * Fix condition to check MEM_TEST_{UNMAP, UNMAP_CHUNK}_SIZE
>>      in check_memory_size() in PATCH[v2 4/6]                     (Maciej)
>>    * Define base and huge page size in kvm_util_base.h in
>>      PATCH[v2 5/6]                                               (Sean)
>>    * Add checks on host/guest page size in check_memory_size()
>>      and fail early if any of them exceeds 64KB in PATCH[v2 5/6] (Maciej)
>>
>>
>> Gavin Shan (6):
>>    KVM: selftests: memslot_perf_test: Use data->nslots in prepare_vm()
>>    KVM: selftests: memslot_perf_test: Consolidate loop conditions in
>>      prepare_vm()
>>    KVM: selftests: memslot_perf_test: Probe memory slots for once
>>    KVM: selftests: memslot_perf_test: Support variable guest page size
>>    KVM: selftests: memslot_perf_test: Consolidate memory
>>    KVM: selftests: memslot_perf_test: Report optimal memory slots
>>
>
> This patch set now looks good to me, so for the whole series:
> Reviewed-by: Maciej S. Szmigiero <[email protected]>
>

Thanks for your time on reviews, Maciej. The broken test case was reported
in our downstream Linux, which means our downstream linux needs the improvements
and fixes to make the test case working.

Thanks,
Gavin


2022-11-10 12:19:13

by Gavin Shan

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] KVM: selftests: memslot_perf_test: aarch64 cleanup/fixes

Hi Marc,

On 10/25/22 7:18 AM, Maciej S. Szmigiero wrote:
> On 20.10.2022 09:12, Gavin Shan wrote:
>> kvm/selftests/memslots_perf_test doesn't work with 64KB-page-size-host
>> and 4KB-page-size-guest on aarch64. In the implementation, the host and
>> guest page size have been hardcoded to 4KB. It's ovbiously not working
>> on aarch64 which supports 4KB, 16KB, 64KB individually on host and guest.
>>
>> This series tries to fix it. After the series is applied, the test runs
>> successfully with 64KB-page-size-host and 4KB-page-size-guest.
>>
>>     # ./memslots_perf_tests -v -s 512
>>
>> Since we're here, the code is cleaned up a bit as PATCH[1-3] do. The
>> other patches are fixes to handle the mismatched host/guest page
>> sized.
>>
>> v1: https://lore.kernel.org/kvmarm/[email protected]/T/#t
>> v2: https://lore.kernel.org/kvmarm/[email protected]/T/#t
>>
>> Changelog
>> =========
>> v3:
>>    * Improved comments about MEM_TEST_MOVE_SIZE, which is set
>>      to 64KB in PATCH[v3 4/6] and finally fixed to 192KB in
>>      PATCH[v3 5/6].                                              (Maciej)
>>    * Use size instead of pages to do the comparison in
>>      test_memslot_move_prepare()                                 (Maciej)
>>    * Use tools/include/linux/sizes.h instead of inventing
>>      our own macros.                                             (Oliver)
>> v2:
>>    * Pick the smaller value between the ones specified by
>>      user or probed from KVM_CAP_NR_MEMSLOTS in PATCH[v2 3/6]    (Maciej)
>>    * Improved comments about MEM_TEST_MOVE_SIZE in
>>      PATCH[v2 4/6]                                               (Maciej)
>>    * Avoid mismatched guest page size after VM is started in
>>      prepare_vm() in PATCH[v2 4/6]                               (Maciej)
>>    * Fix condition to check MEM_TEST_{UNMAP, UNMAP_CHUNK}_SIZE
>>      in check_memory_size() in PATCH[v2 4/6]                     (Maciej)
>>    * Define base and huge page size in kvm_util_base.h in
>>      PATCH[v2 5/6]                                               (Sean)
>>    * Add checks on host/guest page size in check_memory_size()
>>      and fail early if any of them exceeds 64KB in PATCH[v2 5/6] (Maciej)
>>
>>
>> Gavin Shan (6):
>>    KVM: selftests: memslot_perf_test: Use data->nslots in prepare_vm()
>>    KVM: selftests: memslot_perf_test: Consolidate loop conditions in
>>      prepare_vm()
>>    KVM: selftests: memslot_perf_test: Probe memory slots for once
>>    KVM: selftests: memslot_perf_test: Support variable guest page size
>>    KVM: selftests: memslot_perf_test: Consolidate memory
>>    KVM: selftests: memslot_perf_test: Report optimal memory slots
>>
>
> This patch set now looks good to me, so for the whole series:
> Reviewed-by: Maciej S. Szmigiero <[email protected]>
>

If possible, could you please merge this series to 'next' branch either?
I hope it can be merged early because our downstream needs the fixes to
make the test case work. It's definitely fine to wait for more comments,
but I haven't receive any more comments in last month :)

Thanks,
Gavin


2022-11-10 19:21:44

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] KVM: selftests: memslot_perf_test: aarch64 cleanup/fixes

On Thu, 20 Oct 2022 15:12:03 +0800, Gavin Shan wrote:
> kvm/selftests/memslots_perf_test doesn't work with 64KB-page-size-host
> and 4KB-page-size-guest on aarch64. In the implementation, the host and
> guest page size have been hardcoded to 4KB. It's ovbiously not working
> on aarch64 which supports 4KB, 16KB, 64KB individually on host and guest.
>
> This series tries to fix it. After the series is applied, the test runs
> successfully with 64KB-page-size-host and 4KB-page-size-guest.
>
> [...]

Applied to next, thanks!

[1/6] KVM: selftests: memslot_perf_test: Use data->nslots in prepare_vm()
commit: 3bfadb2325891d122771ce534336af531e93d7b2
[2/6] KVM: selftests: memslot_perf_test: Consolidate loop conditions in prepare_vm()
commit: 2aae5e6795e1407334bb849f96f11c9051b959e2
[3/6] KVM: selftests: memslot_perf_test: Probe memory slots for once
commit: 34396437b11f904fc61b272e3974f4c92868451b
[4/6] KVM: selftests: memslot_perf_test: Support variable guest page size
commit: 8675c6f226986ddb67752be22279a0e2385b197e
[5/6] KVM: selftests: memslot_perf_test: Consolidate memory
commit: 88a64e65484ef6b5cb09fe545d0dd00c950a1131
[6/6] KVM: selftests: memslot_perf_test: Report optimal memory slots
commit: a69170c65acdf430e24fc1b6174dcc3aa501fe2f

Cheers,

M.
--
Without deviation from the norm, progress is not possible.