[PATCH v1 14/18] KVM: selftest/memslot_perf_test: vcpu related code consolidation

From: Wei Wang
Date: Mon Oct 24 2022 - 07:40:28 EST


Remove the vcpu and vcpu_thread fields in the vm_data struct and reuse
the one in the kvm_vm strut. Rename vm_data to vcpu_thread_data and make
it be the vcpu thread's private data. Also use the helper functions to
create and join the vcpu thread.

Signed-off-by: Wei Wang <wei.w.wang@xxxxxxxxx>
---
.../testing/selftests/kvm/memslot_perf_test.c | 137 +++++++++---------
1 file changed, 71 insertions(+), 66 deletions(-)

diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index 44995446d942..bf37d1bb8d50 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -6,7 +6,6 @@
*
* Basic guest setup / host vCPU thread code lifted from set_memory_region_test.
*/
-#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
#include <stdatomic.h>
@@ -86,10 +85,7 @@ static_assert(MEM_TEST_MOVE_SIZE <= MEM_TEST_SIZE,
#define MEM_TEST_VAL_1 0x1122334455667788
#define MEM_TEST_VAL_2 0x99AABBCCDDEEFF00

-struct vm_data {
- struct kvm_vm *vm;
- struct kvm_vcpu *vcpu;
- pthread_t vcpu_thread;
+struct vcpu_thread_data {
uint32_t nslots;
uint64_t npages;
uint64_t pages_per_slot;
@@ -126,7 +122,7 @@ static bool verbose;
pr_info(__VA_ARGS__); \
} while (0)

-static void check_mmio_access(struct vm_data *data, struct kvm_run *run)
+static void check_mmio_access(struct vcpu_thread_data *data, struct kvm_run *run)
{
TEST_ASSERT(data->mmio_ok, "Unexpected mmio exit");
TEST_ASSERT(run->mmio.is_write, "Unexpected mmio read");
@@ -140,8 +136,9 @@ static void check_mmio_access(struct vm_data *data, struct kvm_run *run)

static void *vcpu_worker(void *__data)
{
- struct vm_data *data = __data;
- struct kvm_vcpu *vcpu = data->vcpu;
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)__data;
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;
struct kvm_run *run = vcpu->run;
struct ucall uc;

@@ -187,7 +184,8 @@ static void wait_for_vcpu(void)
"sem_timedwait() failed: %d\n", errno);
}

-static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages)
+static void *vm_gpa2hva(struct vcpu_thread_data *data,
+ uint64_t gpa, uint64_t *rempages)
{
uint64_t gpage, pgoffs;
uint32_t slot, slotoffs;
@@ -220,31 +218,19 @@ static void *vm_gpa2hva(struct vm_data *data, uint64_t gpa, uint64_t *rempages)
return (uint8_t *)base + slotoffs * 4096 + pgoffs;
}

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

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

-static struct vm_data *alloc_vm(void)
-{
- struct vm_data *data;
-
- data = malloc(sizeof(*data));
- TEST_ASSERT(data, "malloc(vmdata) failed");
-
- data->vm = NULL;
- data->vcpu = NULL;
- data->hva_slots = NULL;
-
- return data;
-}
-
-static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
- void *guest_code, uint64_t mempages,
- struct timespec *slot_runtime)
+static bool prepare_vm(struct kvm_vm **out_vm, int nslots, uint64_t *maxslots,
+ void *guest_code, uint64_t mempages, struct timespec *slot_runtime)
{
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ struct vcpu_thread_data *data;
uint32_t max_mem_slots;
uint64_t rempages;
uint64_t guest_addr;
@@ -263,6 +249,11 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,

TEST_ASSERT(mempages > 1,
"Can't test without any memory");
+ vm = __vm_create_with_one_vcpu(&vcpu, mempages, guest_code);
+ *out_vm = vm;
+ vm_vcpu_threads_private_data_alloc(vm,
+ sizeof(struct vcpu_thread_data));
+ data = (struct vcpu_thread_data *)vcpu->private_data;

data->npages = mempages;
data->nslots = max_mem_slots - 1;
@@ -276,8 +267,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
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);
+ ucall_init(vm, NULL);

pr_info_v("Adding slots 1..%i, each slot with %"PRIu64" pages + %"PRIu64" extra pages last\n",
max_mem_slots - 1, data->pages_per_slot, rempages);
@@ -290,7 +280,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
if (slot == max_mem_slots - 1)
npages += rempages;

- vm_userspace_mem_region_add(data->vm, VM_MEM_SRC_ANONYMOUS,
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
guest_addr, slot, npages,
0);
guest_addr += npages * 4096;
@@ -305,18 +295,18 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
if (slot == max_mem_slots - 2)
npages += rempages;

- gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr,
+ gpa = vm_phy_pages_alloc(vm, npages, guest_addr,
slot + 1);
TEST_ASSERT(gpa == guest_addr,
"vm_phy_pages_alloc() failed\n");

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

guest_addr += npages * 4096;
}

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

sync = (typeof(sync))vm_gpa2hva(data, MEM_SYNC_GPA, NULL);
atomic_init(&sync->start_flag, false);
@@ -328,26 +318,22 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots,
return true;
}

-static void launch_vm(struct vm_data *data)
+static void launch_vm(struct kvm_vm *vm)
{
pr_info_v("Launching the test VM\n");

- pthread_create(&data->vcpu_thread, NULL, vcpu_worker, data);
+ vm_vcpu_threads_create(vm, vcpu_worker, 0);

/* Ensure the guest thread is spun up. */
wait_for_vcpu();
}

-static void free_vm(struct vm_data *data)
+static void vcpu_thread_data_free(struct vcpu_thread_data *data)
{
- kvm_vm_free(data->vm);
- free(data->hva_slots);
- free(data);
-}
-
-static void wait_guest_exit(struct vm_data *data)
-{
- pthread_join(data->vcpu_thread, NULL);
+ if (data) {
+ free(data->hva_slots);
+ free(data);
+ }
}

static void let_guest_run(struct sync_area *sync)
@@ -535,7 +521,7 @@ static void guest_code_test_memslot_rw(void)
GUEST_DONE();
}

-static bool test_memslot_move_prepare(struct vm_data *data,
+static bool test_memslot_move_prepare(struct vcpu_thread_data *data,
struct sync_area *sync,
uint64_t *maxslots, bool isactive)
{
@@ -565,31 +551,33 @@ static bool test_memslot_move_prepare(struct vm_data *data,
return true;
}

-static bool test_memslot_move_prepare_active(struct vm_data *data,
+static bool test_memslot_move_prepare_active(struct vcpu_thread_data *data,
struct sync_area *sync,
uint64_t *maxslots)
{
return test_memslot_move_prepare(data, sync, maxslots, true);
}

-static bool test_memslot_move_prepare_inactive(struct vm_data *data,
+static bool test_memslot_move_prepare_inactive(struct vcpu_thread_data *data,
struct sync_area *sync,
uint64_t *maxslots)
{
return test_memslot_move_prepare(data, sync, maxslots, false);
}

-static void test_memslot_move_loop(struct vm_data *data, struct sync_area *sync)
+static void test_memslot_move_loop(struct kvm_vcpu *vcpu, struct sync_area *sync)
{
uint64_t movesrcgpa;
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;

movesrcgpa = vm_slot2gpa(data, data->nslots - 1);
- vm_mem_region_move(data->vm, data->nslots - 1 + 1,
+ vm_mem_region_move(vcpu->vm, data->nslots - 1 + 1,
MEM_TEST_MOVE_GPA_DEST);
- vm_mem_region_move(data->vm, data->nslots - 1 + 1, movesrcgpa);
+ vm_mem_region_move(vcpu->vm, data->nslots - 1 + 1, movesrcgpa);
}

-static void test_memslot_do_unmap(struct vm_data *data,
+static void test_memslot_do_unmap(struct vcpu_thread_data *data,
uint64_t offsp, uint64_t count)
{
uint64_t gpa, ctr;
@@ -613,7 +601,7 @@ static void test_memslot_do_unmap(struct vm_data *data,
"madvise(MADV_DONTNEED) should exactly cover all of the requested area");
}

-static void test_memslot_map_unmap_check(struct vm_data *data,
+static void test_memslot_map_unmap_check(struct vcpu_thread_data *data,
uint64_t offsp, uint64_t valexp)
{
uint64_t gpa;
@@ -630,8 +618,11 @@ static void test_memslot_map_unmap_check(struct vm_data *data,
*val = 0;
}

-static void test_memslot_map_loop(struct vm_data *data, struct sync_area *sync)
+static void test_memslot_map_loop(struct kvm_vcpu *vcpu,
+ struct sync_area *sync)
{
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;
/*
* Unmap the second half of the test area while guest writes to (maps)
* the first half.
@@ -670,7 +661,7 @@ static void test_memslot_map_loop(struct vm_data *data, struct sync_area *sync)
MEM_TEST_VAL_2);
}

-static void test_memslot_unmap_loop_common(struct vm_data *data,
+static void test_memslot_unmap_loop_common(struct vcpu_thread_data *data,
struct sync_area *sync,
uint64_t chunk)
{
@@ -697,21 +688,30 @@ static void test_memslot_unmap_loop_common(struct vm_data *data,
test_memslot_do_unmap(data, ctr, chunk);
}

-static void test_memslot_unmap_loop(struct vm_data *data,
+static void test_memslot_unmap_loop(struct kvm_vcpu *vcpu,
struct sync_area *sync)
{
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;
+
test_memslot_unmap_loop_common(data, sync, 1);
}

-static void test_memslot_unmap_loop_chunked(struct vm_data *data,
+static void test_memslot_unmap_loop_chunked(struct kvm_vcpu *vcpu,
struct sync_area *sync)
{
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;
+
test_memslot_unmap_loop_common(data, sync, MEM_TEST_UNMAP_CHUNK_PAGES);
}

-static void test_memslot_rw_loop(struct vm_data *data, struct sync_area *sync)
+static void test_memslot_rw_loop(struct kvm_vcpu *vcpu,
+ struct sync_area *sync)
{
uint64_t gptr;
+ struct vcpu_thread_data *data =
+ (struct vcpu_thread_data *)vcpu->private_data;

for (gptr = MEM_TEST_GPA + 4096 / 2;
gptr < MEM_TEST_GPA + MEM_TEST_SIZE; gptr += 4096)
@@ -737,9 +737,9 @@ struct test_data {
const char *name;
uint64_t mem_size;
void (*guest_code)(void);
- bool (*prepare)(struct vm_data *data, struct sync_area *sync,
+ bool (*prepare)(struct vcpu_thread_data *data, struct sync_area *sync,
uint64_t *maxslots);
- void (*loop)(struct vm_data *data, struct sync_area *sync);
+ void (*loop)(struct kvm_vcpu *vcpu, struct sync_area *sync);
};

static bool test_execute(int nslots, uint64_t *maxslots,
@@ -750,18 +750,22 @@ static bool test_execute(int nslots, uint64_t *maxslots,
struct timespec *guest_runtime)
{
uint64_t mem_size = tdata->mem_size ? : MEM_SIZE_PAGES;
- struct vm_data *data;
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ struct vcpu_thread_data *data = NULL;
struct sync_area *sync;
struct timespec tstart;
bool ret = true;

- data = alloc_vm();
- if (!prepare_vm(data, nslots, maxslots, tdata->guest_code,
+ if (!prepare_vm(&vm, nslots, maxslots, tdata->guest_code,
mem_size, slot_runtime)) {
ret = false;
goto exit_free;
}

+ vcpu = vm->vcpus[0];
+ data = (struct vcpu_thread_data *)vcpu->private_data;
+
sync = (typeof(sync))vm_gpa2hva(data, MEM_SYNC_GPA, NULL);

if (tdata->prepare &&
@@ -770,7 +774,7 @@ static bool test_execute(int nslots, uint64_t *maxslots,
goto exit_free;
}

- launch_vm(data);
+ launch_vm(vm);

clock_gettime(CLOCK_MONOTONIC, &tstart);
let_guest_run(sync);
@@ -780,16 +784,17 @@ static bool test_execute(int nslots, uint64_t *maxslots,
if (guest_runtime->tv_sec >= maxtime)
break;

- tdata->loop(data, sync);
+ tdata->loop(vcpu, sync);

(*nloops)++;
}

make_guest_exit(sync);
- wait_guest_exit(data);
+ vm_vcpu_threads_join(vm);

exit_free:
- free_vm(data);
+ vcpu_thread_data_free(data);
+ kvm_vm_free(vm);

return ret;
}
--
2.27.0