Skip to content

Commit

Permalink
KVM: selftests: Support multiple slots in dirty_log_perf_test
Browse files Browse the repository at this point in the history
Introduce a new option to dirty_log_perf_test: -x number_of_slots. This
causes the test to attempt to split the region of memory into the given
number of slots. If the region cannot be evenly divided, the test will
fail.

This allows testing with more than one slot and therefore measure how
performance scales with the number of memslots.

Signed-off-by: David Matlack <dmatlack@google.com>
Message-Id: <20210804222844.1419481-8-dmatlack@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
David Matlack authored and Paolo Bonzini committed Aug 6, 2021
1 parent 93e083d commit 609e620
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 20 deletions.
2 changes: 1 addition & 1 deletion tools/testing/selftests/kvm/access_tracking_perf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
pthread_t *vcpu_threads;
int vcpus = params->vcpus;

vm = perf_test_create_vm(mode, vcpus, params->vcpu_memory_bytes,
vm = perf_test_create_vm(mode, vcpus, params->vcpu_memory_bytes, 1,
params->backing_src);

perf_test_setup_vcpus(vm, vcpus, params->vcpu_memory_bytes,
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/kvm/demand_paging_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
int vcpu_id;
int r;

vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size,
vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,
p->src_type);

perf_test_args.wr_fract = 1;
Expand Down
76 changes: 65 additions & 11 deletions tools/testing/selftests/kvm/dirty_log_perf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,59 @@ struct test_params {
int wr_fract;
bool partition_vcpu_memory_access;
enum vm_mem_backing_src_type backing_src;
int slots;
};

static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable)
{
int i;

for (i = 0; i < slots; i++) {
int slot = PERF_TEST_MEM_SLOT_INDEX + i;
int flags = enable ? KVM_MEM_LOG_DIRTY_PAGES : 0;

vm_mem_region_set_flags(vm, slot, flags);
}
}

static inline void enable_dirty_logging(struct kvm_vm *vm, int slots)
{
toggle_dirty_logging(vm, slots, true);
}

static inline void disable_dirty_logging(struct kvm_vm *vm, int slots)
{
toggle_dirty_logging(vm, slots, false);
}

static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
uint64_t nr_pages)
{
uint64_t slot_pages = nr_pages / slots;
int i;

for (i = 0; i < slots; i++) {
int slot = PERF_TEST_MEM_SLOT_INDEX + i;
unsigned long *slot_bitmap = bitmap + i * slot_pages;

kvm_vm_get_dirty_log(vm, slot, slot_bitmap);
}
}

static void clear_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
uint64_t nr_pages)
{
uint64_t slot_pages = nr_pages / slots;
int i;

for (i = 0; i < slots; i++) {
int slot = PERF_TEST_MEM_SLOT_INDEX + i;
unsigned long *slot_bitmap = bitmap + i * slot_pages;

kvm_vm_clear_dirty_log(vm, slot, slot_bitmap, 0, slot_pages);
}
}

static void run_test(enum vm_guest_mode mode, void *arg)
{
struct test_params *p = arg;
Expand All @@ -114,7 +165,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
struct timespec clear_dirty_log_total = (struct timespec){0};

vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size,
p->backing_src);
p->slots, p->backing_src);

perf_test_args.wr_fract = p->wr_fract;

Expand Down Expand Up @@ -163,8 +214,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)

/* Enable dirty logging */
clock_gettime(CLOCK_MONOTONIC, &start);
vm_mem_region_set_flags(vm, PERF_TEST_MEM_SLOT_INDEX,
KVM_MEM_LOG_DIRTY_PAGES);
enable_dirty_logging(vm, p->slots);
ts_diff = timespec_elapsed(start);
pr_info("Enabling dirty logging time: %ld.%.9lds\n\n",
ts_diff.tv_sec, ts_diff.tv_nsec);
Expand All @@ -190,8 +240,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
iteration, ts_diff.tv_sec, ts_diff.tv_nsec);

clock_gettime(CLOCK_MONOTONIC, &start);
kvm_vm_get_dirty_log(vm, PERF_TEST_MEM_SLOT_INDEX, bmap);

get_dirty_log(vm, p->slots, bmap, host_num_pages);
ts_diff = timespec_elapsed(start);
get_dirty_log_total = timespec_add(get_dirty_log_total,
ts_diff);
Expand All @@ -200,9 +249,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)

if (dirty_log_manual_caps) {
clock_gettime(CLOCK_MONOTONIC, &start);
kvm_vm_clear_dirty_log(vm, PERF_TEST_MEM_SLOT_INDEX, bmap, 0,
host_num_pages);

clear_dirty_log(vm, p->slots, bmap, host_num_pages);
ts_diff = timespec_elapsed(start);
clear_dirty_log_total = timespec_add(clear_dirty_log_total,
ts_diff);
Expand All @@ -213,7 +260,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)

/* Disable dirty logging */
clock_gettime(CLOCK_MONOTONIC, &start);
vm_mem_region_set_flags(vm, PERF_TEST_MEM_SLOT_INDEX, 0);
disable_dirty_logging(vm, p->slots);
ts_diff = timespec_elapsed(start);
pr_info("Disabling dirty logging time: %ld.%.9lds\n",
ts_diff.tv_sec, ts_diff.tv_nsec);
Expand Down Expand Up @@ -244,7 +291,8 @@ static void help(char *name)
{
puts("");
printf("usage: %s [-h] [-i iterations] [-p offset] "
"[-m mode] [-b vcpu bytes] [-v vcpus] [-o] [-s mem type]\n", name);
"[-m mode] [-b vcpu bytes] [-v vcpus] [-o] [-s mem type]"
"[-x memslots]\n", name);
puts("");
printf(" -i: specify iteration counts (default: %"PRIu64")\n",
TEST_HOST_LOOP_N);
Expand All @@ -263,6 +311,8 @@ static void help(char *name)
" them into a separate region of memory for each vCPU.\n");
printf(" -s: specify the type of memory that should be used to\n"
" back the guest data region.\n\n");
printf(" -x: Split the memory region into this number of memslots.\n"
" (default: 1)");
backing_src_help();
puts("");
exit(0);
Expand All @@ -276,6 +326,7 @@ int main(int argc, char *argv[])
.wr_fract = 1,
.partition_vcpu_memory_access = true,
.backing_src = VM_MEM_SRC_ANONYMOUS,
.slots = 1,
};
int opt;

Expand All @@ -286,7 +337,7 @@ int main(int argc, char *argv[])

guest_modes_append_default();

while ((opt = getopt(argc, argv, "hi:p:m:b:f:v:os:")) != -1) {
while ((opt = getopt(argc, argv, "hi:p:m:b:f:v:os:x:")) != -1) {
switch (opt) {
case 'i':
p.iterations = atoi(optarg);
Expand Down Expand Up @@ -316,6 +367,9 @@ int main(int argc, char *argv[])
case 's':
p.backing_src = parse_backing_src_type(optarg);
break;
case 'x':
p.slots = atoi(optarg);
break;
case 'h':
default:
help(argv[0]);
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/kvm/include/perf_test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extern struct perf_test_args perf_test_args;
extern uint64_t guest_test_phys_mem;

struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
uint64_t vcpu_memory_bytes,
uint64_t vcpu_memory_bytes, int slots,
enum vm_mem_backing_src_type backing_src);
void perf_test_destroy_vm(struct kvm_vm *vm);
void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus,
Expand Down
20 changes: 15 additions & 5 deletions tools/testing/selftests/kvm/lib/perf_test_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ static void guest_code(uint32_t vcpu_id)
}

struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
uint64_t vcpu_memory_bytes,
uint64_t vcpu_memory_bytes, int slots,
enum vm_mem_backing_src_type backing_src)
{
struct kvm_vm *vm;
uint64_t guest_num_pages;
int i;

pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode));

Expand All @@ -68,6 +69,9 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
"Guest memory size is not host page size aligned.");
TEST_ASSERT(vcpu_memory_bytes % perf_test_args.guest_page_size == 0,
"Guest memory size is not guest page size aligned.");
TEST_ASSERT(guest_num_pages % slots == 0,
"Guest memory cannot be evenly divided into %d slots.",
slots);

vm = vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES,
(vcpus * vcpu_memory_bytes) / perf_test_args.guest_page_size,
Expand Down Expand Up @@ -95,10 +99,16 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
#endif
pr_info("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem);

/* Add an extra memory slot for testing */
vm_userspace_mem_region_add(vm, backing_src, guest_test_phys_mem,
PERF_TEST_MEM_SLOT_INDEX,
guest_num_pages, 0);
/* Add extra memory slots for testing */
for (i = 0; i < slots; i++) {
uint64_t region_pages = guest_num_pages / slots;
vm_paddr_t region_start = guest_test_phys_mem +
region_pages * perf_test_args.guest_page_size * i;

vm_userspace_mem_region_add(vm, backing_src, region_start,
PERF_TEST_MEM_SLOT_INDEX + i,
region_pages, 0);
}

/* Do mapping for the demand paging memory slot */
virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
struct kvm_vm *vm;
int vcpu_id;

vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size,
vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,
VM_MEM_SRC_ANONYMOUS);

perf_test_args.wr_fract = 1;
Expand Down

0 comments on commit 609e620

Please sign in to comment.