Commit 609e6202 authored by David Matlack's avatar David Matlack Committed by Paolo Bonzini

KVM: selftests: Support multiple slots in dirty_log_perf_test

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: default avatarDavid Matlack <dmatlack@google.com>
Message-Id: <20210804222844.1419481-8-dmatlack@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 93e083d4
...@@ -333,7 +333,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -333,7 +333,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
pthread_t *vcpu_threads; pthread_t *vcpu_threads;
int vcpus = params->vcpus; 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); params->backing_src);
perf_test_setup_vcpus(vm, vcpus, params->vcpu_memory_bytes, perf_test_setup_vcpus(vm, vcpus, params->vcpu_memory_bytes,
......
...@@ -293,7 +293,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -293,7 +293,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
int vcpu_id; int vcpu_id;
int r; 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); p->src_type);
perf_test_args.wr_fract = 1; perf_test_args.wr_fract = 1;
......
...@@ -94,8 +94,59 @@ struct test_params { ...@@ -94,8 +94,59 @@ struct test_params {
int wr_fract; int wr_fract;
bool partition_vcpu_memory_access; bool partition_vcpu_memory_access;
enum vm_mem_backing_src_type backing_src; 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) static void run_test(enum vm_guest_mode mode, void *arg)
{ {
struct test_params *p = arg; struct test_params *p = arg;
...@@ -114,7 +165,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -114,7 +165,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
struct timespec clear_dirty_log_total = (struct timespec){0}; struct timespec clear_dirty_log_total = (struct timespec){0};
vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 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; perf_test_args.wr_fract = p->wr_fract;
...@@ -163,8 +214,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -163,8 +214,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
/* Enable dirty logging */ /* Enable dirty logging */
clock_gettime(CLOCK_MONOTONIC, &start); clock_gettime(CLOCK_MONOTONIC, &start);
vm_mem_region_set_flags(vm, PERF_TEST_MEM_SLOT_INDEX, enable_dirty_logging(vm, p->slots);
KVM_MEM_LOG_DIRTY_PAGES);
ts_diff = timespec_elapsed(start); ts_diff = timespec_elapsed(start);
pr_info("Enabling dirty logging time: %ld.%.9lds\n\n", pr_info("Enabling dirty logging time: %ld.%.9lds\n\n",
ts_diff.tv_sec, ts_diff.tv_nsec); ts_diff.tv_sec, ts_diff.tv_nsec);
...@@ -190,8 +240,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -190,8 +240,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
iteration, ts_diff.tv_sec, ts_diff.tv_nsec); iteration, ts_diff.tv_sec, ts_diff.tv_nsec);
clock_gettime(CLOCK_MONOTONIC, &start); 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); ts_diff = timespec_elapsed(start);
get_dirty_log_total = timespec_add(get_dirty_log_total, get_dirty_log_total = timespec_add(get_dirty_log_total,
ts_diff); ts_diff);
...@@ -200,9 +249,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -200,9 +249,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
if (dirty_log_manual_caps) { if (dirty_log_manual_caps) {
clock_gettime(CLOCK_MONOTONIC, &start); clock_gettime(CLOCK_MONOTONIC, &start);
kvm_vm_clear_dirty_log(vm, PERF_TEST_MEM_SLOT_INDEX, bmap, 0, clear_dirty_log(vm, p->slots, bmap, host_num_pages);
host_num_pages);
ts_diff = timespec_elapsed(start); ts_diff = timespec_elapsed(start);
clear_dirty_log_total = timespec_add(clear_dirty_log_total, clear_dirty_log_total = timespec_add(clear_dirty_log_total,
ts_diff); ts_diff);
...@@ -213,7 +260,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -213,7 +260,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
/* Disable dirty logging */ /* Disable dirty logging */
clock_gettime(CLOCK_MONOTONIC, &start); 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); ts_diff = timespec_elapsed(start);
pr_info("Disabling dirty logging time: %ld.%.9lds\n", pr_info("Disabling dirty logging time: %ld.%.9lds\n",
ts_diff.tv_sec, ts_diff.tv_nsec); ts_diff.tv_sec, ts_diff.tv_nsec);
...@@ -244,7 +291,8 @@ static void help(char *name) ...@@ -244,7 +291,8 @@ static void help(char *name)
{ {
puts(""); puts("");
printf("usage: %s [-h] [-i iterations] [-p offset] " 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(""); puts("");
printf(" -i: specify iteration counts (default: %"PRIu64")\n", printf(" -i: specify iteration counts (default: %"PRIu64")\n",
TEST_HOST_LOOP_N); TEST_HOST_LOOP_N);
...@@ -263,6 +311,8 @@ static void help(char *name) ...@@ -263,6 +311,8 @@ static void help(char *name)
" them into a separate region of memory for each vCPU.\n"); " them into a separate region of memory for each vCPU.\n");
printf(" -s: specify the type of memory that should be used to\n" printf(" -s: specify the type of memory that should be used to\n"
" back the guest data region.\n\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(); backing_src_help();
puts(""); puts("");
exit(0); exit(0);
...@@ -276,6 +326,7 @@ int main(int argc, char *argv[]) ...@@ -276,6 +326,7 @@ int main(int argc, char *argv[])
.wr_fract = 1, .wr_fract = 1,
.partition_vcpu_memory_access = true, .partition_vcpu_memory_access = true,
.backing_src = VM_MEM_SRC_ANONYMOUS, .backing_src = VM_MEM_SRC_ANONYMOUS,
.slots = 1,
}; };
int opt; int opt;
...@@ -286,7 +337,7 @@ int main(int argc, char *argv[]) ...@@ -286,7 +337,7 @@ int main(int argc, char *argv[])
guest_modes_append_default(); 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) { switch (opt) {
case 'i': case 'i':
p.iterations = atoi(optarg); p.iterations = atoi(optarg);
...@@ -316,6 +367,9 @@ int main(int argc, char *argv[]) ...@@ -316,6 +367,9 @@ int main(int argc, char *argv[])
case 's': case 's':
p.backing_src = parse_backing_src_type(optarg); p.backing_src = parse_backing_src_type(optarg);
break; break;
case 'x':
p.slots = atoi(optarg);
break;
case 'h': case 'h':
default: default:
help(argv[0]); help(argv[0]);
......
...@@ -44,7 +44,7 @@ extern struct perf_test_args perf_test_args; ...@@ -44,7 +44,7 @@ extern struct perf_test_args perf_test_args;
extern uint64_t guest_test_phys_mem; extern uint64_t guest_test_phys_mem;
struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, 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); enum vm_mem_backing_src_type backing_src);
void perf_test_destroy_vm(struct kvm_vm *vm); void perf_test_destroy_vm(struct kvm_vm *vm);
void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus, void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus,
......
...@@ -50,11 +50,12 @@ static void guest_code(uint32_t vcpu_id) ...@@ -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, 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) enum vm_mem_backing_src_type backing_src)
{ {
struct kvm_vm *vm; struct kvm_vm *vm;
uint64_t guest_num_pages; uint64_t guest_num_pages;
int i;
pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode));
...@@ -68,6 +69,9 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, ...@@ -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."); "Guest memory size is not host page size aligned.");
TEST_ASSERT(vcpu_memory_bytes % perf_test_args.guest_page_size == 0, TEST_ASSERT(vcpu_memory_bytes % perf_test_args.guest_page_size == 0,
"Guest memory size is not guest page size aligned."); "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, vm = vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES,
(vcpus * vcpu_memory_bytes) / perf_test_args.guest_page_size, (vcpus * vcpu_memory_bytes) / perf_test_args.guest_page_size,
...@@ -95,10 +99,16 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, ...@@ -95,10 +99,16 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
#endif #endif
pr_info("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem); pr_info("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem);
/* Add an extra memory slot for testing */ /* Add extra memory slots for testing */
vm_userspace_mem_region_add(vm, backing_src, guest_test_phys_mem, for (i = 0; i < slots; i++) {
PERF_TEST_MEM_SLOT_INDEX, uint64_t region_pages = guest_num_pages / slots;
guest_num_pages, 0); 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 */ /* Do mapping for the demand paging memory slot */
virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages); virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
......
...@@ -105,7 +105,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ...@@ -105,7 +105,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
struct kvm_vm *vm; struct kvm_vm *vm;
int vcpu_id; 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); VM_MEM_SRC_ANONYMOUS);
perf_test_args.wr_fract = 1; perf_test_args.wr_fract = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment