KVM: selftests: Support multiple slots in dirty_log_perf_test
authorDavid Matlack <dmatlack@google.com>
Wed, 4 Aug 2021 22:28:44 +0000 (22:28 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 6 Aug 2021 11:53:01 +0000 (07:53 -0400)
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>
tools/testing/selftests/kvm/access_tracking_perf_test.c
tools/testing/selftests/kvm/demand_paging_test.c
tools/testing/selftests/kvm/dirty_log_perf_test.c
tools/testing/selftests/kvm/include/perf_test_util.h
tools/testing/selftests/kvm/lib/perf_test_util.c
tools/testing/selftests/kvm/memslot_modification_stress_test.c

index e2baa187a21eda244db0282bf2ae103d9c975c6c..3e23b2105f4b3a565e91d0e40e49c8b17763a454 100644 (file)
@@ -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,
index b74704305835e5b5398fa2b46fa99fd7147e0973..61266a729d88e877b37d6d3d14b3a869589cc7d6 100644 (file)
@@ -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;
index 80cbd3a748c0271565e566746fc92fc119267494..034458dd89a2ecf78cc8eeb8c0712fa4bca7871e 100644 (file)
@@ -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;
@@ -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;
 
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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;
 
@@ -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);
@@ -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]);
index 005f2143adebd1bbc79950d6cc7690fc4edc84f6..df9f1a3a3ffb9a5922ddff89e8557d6e039b3fcb 100644 (file)
@@ -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,
index b488f4aefea8212028403e2e44988340c03f8581..aebb223d34a73412c9fe7f9a26c5b41f81239595 100644 (file)
@@ -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));
 
@@ -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,
@@ -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);
index 98351ba0933cdb4e89281cdaf98c5a8ccc85a05f..8a9c6ccce3cab84a88471daadd1c39794f0797fe 100644 (file)
@@ -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;