Skip to content

Commit

Permalink
KVM: selftests: Add option to overlap vCPU memory access
Browse files Browse the repository at this point in the history
Add an option to overlap the ranges of memory each vCPU accesses instead
of partitioning them. This option will increase the probability of
multiple vCPUs faulting on the same page at the same time, and causing
interesting races, if there are bugs in the page fault handler or
elsewhere in the kernel.

Reviewed-by: Jacob Xu <jacobhxu@google.com>
Reviewed-by: Makarand Sonare <makarandsonare@google.com>

Signed-off-by: Ben Gardon <bgardon@google.com>
Message-Id: <20210112214253.463999-6-bgardon@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Ben Gardon authored and Paolo Bonzini committed Feb 4, 2021
1 parent 86753bd commit 82f9133
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 18 deletions.
32 changes: 25 additions & 7 deletions tools/testing/selftests/kvm/demand_paging_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ static int setup_demand_paging(struct kvm_vm *vm,
struct test_params {
bool use_uffd;
useconds_t uffd_delay;
bool partition_vcpu_memory_access;
};

static void run_test(enum vm_guest_mode mode, void *arg)
Expand Down Expand Up @@ -277,7 +278,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
vcpu_threads = malloc(nr_vcpus * sizeof(*vcpu_threads));
TEST_ASSERT(vcpu_threads, "Memory allocation failed");

perf_test_setup_vcpus(vm, nr_vcpus, guest_percpu_mem_size);
perf_test_setup_vcpus(vm, nr_vcpus, guest_percpu_mem_size,
p->partition_vcpu_memory_access);

if (p->use_uffd) {
uffd_handler_threads =
Expand All @@ -293,10 +295,19 @@ static void run_test(enum vm_guest_mode mode, void *arg)
for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
vm_paddr_t vcpu_gpa;
void *vcpu_hva;
uint64_t vcpu_mem_size;

vcpu_gpa = guest_test_phys_mem + (vcpu_id * guest_percpu_mem_size);

if (p->partition_vcpu_memory_access) {
vcpu_gpa = guest_test_phys_mem +
(vcpu_id * guest_percpu_mem_size);
vcpu_mem_size = guest_percpu_mem_size;
} else {
vcpu_gpa = guest_test_phys_mem;
vcpu_mem_size = guest_percpu_mem_size * nr_vcpus;
}
PER_VCPU_DEBUG("Added VCPU %d with test mem gpa [%lx, %lx)\n",
vcpu_id, vcpu_gpa, vcpu_gpa + guest_percpu_mem_size);
vcpu_id, vcpu_gpa, vcpu_gpa + vcpu_mem_size);

/* Cache the HVA pointer of the region */
vcpu_hva = addr_gpa2hva(vm, vcpu_gpa);
Expand All @@ -313,7 +324,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
&uffd_handler_threads[vcpu_id],
pipefds[vcpu_id * 2],
p->uffd_delay, &uffd_args[vcpu_id],
vcpu_hva, guest_percpu_mem_size);
vcpu_hva, vcpu_mem_size);
if (r < 0)
exit(-r);
}
Expand Down Expand Up @@ -376,7 +387,7 @@ static void help(char *name)
{
puts("");
printf("usage: %s [-h] [-m mode] [-u] [-d uffd_delay_usec]\n"
" [-b memory] [-v vcpus]\n", name);
" [-b memory] [-v vcpus] [-o]\n", name);
guest_modes_help();
printf(" -u: use User Fault FD to handle vCPU page\n"
" faults.\n");
Expand All @@ -387,19 +398,23 @@ static void help(char *name)
" demand paged by each vCPU. e.g. 10M or 3G.\n"
" Default: 1G\n");
printf(" -v: specify the number of vCPUs to run.\n");
printf(" -o: Overlap guest memory accesses instead of partitioning\n"
" them into a separate region of memory for each vCPU.\n");
puts("");
exit(0);
}

int main(int argc, char *argv[])
{
int max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
struct test_params p = {};
struct test_params p = {
.partition_vcpu_memory_access = true,
};
int opt;

guest_modes_append_default();

while ((opt = getopt(argc, argv, "hm:ud:b:v:")) != -1) {
while ((opt = getopt(argc, argv, "hm:ud:b:v:o")) != -1) {
switch (opt) {
case 'm':
guest_modes_cmdline(optarg);
Expand All @@ -419,6 +434,9 @@ int main(int argc, char *argv[])
TEST_ASSERT(nr_vcpus > 0 && nr_vcpus <= max_vcpus,
"Invalid number of vcpus, must be between 1 and %d", max_vcpus);
break;
case 'o':
p.partition_vcpu_memory_access = false;
break;
case 'h':
default:
help(argv[0]);
Expand Down
14 changes: 11 additions & 3 deletions tools/testing/selftests/kvm/dirty_log_perf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ struct test_params {
unsigned long iterations;
uint64_t phys_offset;
int wr_fract;
bool partition_vcpu_memory_access;
};

static void run_test(enum vm_guest_mode mode, void *arg)
Expand Down Expand Up @@ -129,7 +130,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
vcpu_threads = malloc(nr_vcpus * sizeof(*vcpu_threads));
TEST_ASSERT(vcpu_threads, "Memory allocation failed");

perf_test_setup_vcpus(vm, nr_vcpus, guest_percpu_mem_size);
perf_test_setup_vcpus(vm, nr_vcpus, guest_percpu_mem_size,
p->partition_vcpu_memory_access);

sync_global_to_guest(vm, perf_test_args);

Expand Down Expand Up @@ -240,7 +242,7 @@ static void help(char *name)
{
puts("");
printf("usage: %s [-h] [-i iterations] [-p offset] "
"[-m mode] [-b vcpu bytes] [-v vcpus]\n", name);
"[-m mode] [-b vcpu bytes] [-v vcpus] [-o]\n", name);
puts("");
printf(" -i: specify iteration counts (default: %"PRIu64")\n",
TEST_HOST_LOOP_N);
Expand All @@ -255,6 +257,8 @@ static void help(char *name)
" 1/<fraction of pages to write>.\n"
" (default: 1 i.e. all pages are written to.)\n");
printf(" -v: specify the number of vCPUs to run.\n");
printf(" -o: Overlap guest memory accesses instead of partitioning\n"
" them into a separate region of memory for each vCPU.\n");
puts("");
exit(0);
}
Expand All @@ -265,6 +269,7 @@ int main(int argc, char *argv[])
struct test_params p = {
.iterations = TEST_HOST_LOOP_N,
.wr_fract = 1,
.partition_vcpu_memory_access = true,
};
int opt;

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

guest_modes_append_default();

while ((opt = getopt(argc, argv, "hi:p:m:b:f:v:")) != -1) {
while ((opt = getopt(argc, argv, "hi:p:m:b:f:v:o")) != -1) {
switch (opt) {
case 'i':
p.iterations = atoi(optarg);
Expand All @@ -299,6 +304,9 @@ int main(int argc, char *argv[])
TEST_ASSERT(nr_vcpus > 0 && nr_vcpus <= max_vcpus,
"Invalid number of vcpus, must be between 1 and %d", max_vcpus);
break;
case 'o':
p.partition_vcpu_memory_access = false;
break;
case 'h':
default:
help(argv[0]);
Expand Down
4 changes: 3 additions & 1 deletion tools/testing/selftests/kvm/include/perf_test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ 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);
void perf_test_destroy_vm(struct kvm_vm *vm);
void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus, uint64_t vcpu_memory_bytes);
void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus,
uint64_t vcpu_memory_bytes,
bool partition_vcpu_memory_access);

#endif /* SELFTEST_KVM_PERF_TEST_UTIL_H */
25 changes: 18 additions & 7 deletions tools/testing/selftests/kvm/lib/perf_test_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ void perf_test_destroy_vm(struct kvm_vm *vm)
kvm_vm_free(vm);
}

void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus, uint64_t vcpu_memory_bytes)
void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus,
uint64_t vcpu_memory_bytes,
bool partition_vcpu_memory_access)
{
vm_paddr_t vcpu_gpa;
struct perf_test_vcpu_args *vcpu_args;
Expand All @@ -122,13 +124,22 @@ void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus, uint64_t vcpu_memory_by
vcpu_args = &perf_test_args.vcpu_args[vcpu_id];

vcpu_args->vcpu_id = vcpu_id;
vcpu_args->gva = guest_test_virt_mem +
(vcpu_id * vcpu_memory_bytes);
vcpu_args->pages = vcpu_memory_bytes /
perf_test_args.guest_page_size;
if (partition_vcpu_memory_access) {
vcpu_args->gva = guest_test_virt_mem +
(vcpu_id * vcpu_memory_bytes);
vcpu_args->pages = vcpu_memory_bytes /
perf_test_args.guest_page_size;
vcpu_gpa = guest_test_phys_mem +
(vcpu_id * vcpu_memory_bytes);
} else {
vcpu_args->gva = guest_test_virt_mem;
vcpu_args->pages = (vcpus * vcpu_memory_bytes) /
perf_test_args.guest_page_size;
vcpu_gpa = guest_test_phys_mem;
}

vcpu_gpa = guest_test_phys_mem + (vcpu_id * vcpu_memory_bytes);
pr_debug("Added VCPU %d with test mem gpa [%lx, %lx)\n",
vcpu_id, vcpu_gpa, vcpu_gpa + vcpu_memory_bytes);
vcpu_id, vcpu_gpa, vcpu_gpa +
(vcpu_args->pages * perf_test_args.guest_page_size));
}
}

0 comments on commit 82f9133

Please sign in to comment.