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;
        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;
 
 
        /* 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);
                        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);
 
                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);
 
        /* 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);
 {
        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);
               "     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);
                .wr_fract = 1,
                .partition_vcpu_memory_access = true,
                .backing_src = VM_MEM_SRC_ANONYMOUS,
+               .slots = 1,
        };
        int opt;
 
 
        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);
                case 's':
                        p.backing_src = parse_backing_src_type(optarg);
                        break;
+               case 'x':
+                       p.slots = atoi(optarg);
+                       break;
                case 'h':
                default:
                        help(argv[0]);
 
 }
 
 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));
 
                    "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,
 #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);