linux/tools/testing/selftests/kvm/lib/perf_test_util.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2020, Google LLC.
   4 */
   5#include <inttypes.h>
   6
   7#include "kvm_util.h"
   8#include "perf_test_util.h"
   9#include "processor.h"
  10
  11struct perf_test_args perf_test_args;
  12
  13uint64_t guest_test_phys_mem;
  14
  15/*
  16 * Guest virtual memory offset of the testing memory slot.
  17 * Must not conflict with identity mapped test code.
  18 */
  19static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM;
  20
  21/*
  22 * Continuously write to the first 8 bytes of each page in the
  23 * specified region.
  24 */
  25static void guest_code(uint32_t vcpu_id)
  26{
  27        struct perf_test_vcpu_args *vcpu_args = &perf_test_args.vcpu_args[vcpu_id];
  28        uint64_t gva;
  29        uint64_t pages;
  30        int i;
  31
  32        /* Make sure vCPU args data structure is not corrupt. */
  33        GUEST_ASSERT(vcpu_args->vcpu_id == vcpu_id);
  34
  35        gva = vcpu_args->gva;
  36        pages = vcpu_args->pages;
  37
  38        while (true) {
  39                for (i = 0; i < pages; i++) {
  40                        uint64_t addr = gva + (i * perf_test_args.guest_page_size);
  41
  42                        if (i % perf_test_args.wr_fract == 0)
  43                                *(uint64_t *)addr = 0x0123456789ABCDEF;
  44                        else
  45                                READ_ONCE(*(uint64_t *)addr);
  46                }
  47
  48                GUEST_SYNC(1);
  49        }
  50}
  51
  52struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus,
  53                                   uint64_t vcpu_memory_bytes, int slots,
  54                                   enum vm_mem_backing_src_type backing_src)
  55{
  56        struct kvm_vm *vm;
  57        uint64_t guest_num_pages;
  58        int i;
  59
  60        pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode));
  61
  62        perf_test_args.host_page_size = getpagesize();
  63        perf_test_args.guest_page_size = vm_guest_mode_params[mode].page_size;
  64
  65        guest_num_pages = vm_adjust_num_guest_pages(mode,
  66                                (vcpus * vcpu_memory_bytes) / perf_test_args.guest_page_size);
  67
  68        TEST_ASSERT(vcpu_memory_bytes % perf_test_args.host_page_size == 0,
  69                    "Guest memory size is not host page size aligned.");
  70        TEST_ASSERT(vcpu_memory_bytes % perf_test_args.guest_page_size == 0,
  71                    "Guest memory size is not guest page size aligned.");
  72        TEST_ASSERT(guest_num_pages % slots == 0,
  73                    "Guest memory cannot be evenly divided into %d slots.",
  74                    slots);
  75
  76        vm = vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES,
  77                                  (vcpus * vcpu_memory_bytes) / perf_test_args.guest_page_size,
  78                                  0, guest_code, NULL);
  79
  80        perf_test_args.vm = vm;
  81
  82        /*
  83         * If there should be more memory in the guest test region than there
  84         * can be pages in the guest, it will definitely cause problems.
  85         */
  86        TEST_ASSERT(guest_num_pages < vm_get_max_gfn(vm),
  87                    "Requested more guest memory than address space allows.\n"
  88                    "    guest pages: %" PRIx64 " max gfn: %" PRIx64
  89                    " vcpus: %d wss: %" PRIx64 "]\n",
  90                    guest_num_pages, vm_get_max_gfn(vm), vcpus,
  91                    vcpu_memory_bytes);
  92
  93        guest_test_phys_mem = (vm_get_max_gfn(vm) - guest_num_pages) *
  94                              perf_test_args.guest_page_size;
  95        guest_test_phys_mem &= ~(perf_test_args.host_page_size - 1);
  96#ifdef __s390x__
  97        /* Align to 1M (segment size) */
  98        guest_test_phys_mem &= ~((1 << 20) - 1);
  99#endif
 100        pr_info("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem);
 101
 102        /* Add extra memory slots for testing */
 103        for (i = 0; i < slots; i++) {
 104                uint64_t region_pages = guest_num_pages / slots;
 105                vm_paddr_t region_start = guest_test_phys_mem +
 106                        region_pages * perf_test_args.guest_page_size * i;
 107
 108                vm_userspace_mem_region_add(vm, backing_src, region_start,
 109                                            PERF_TEST_MEM_SLOT_INDEX + i,
 110                                            region_pages, 0);
 111        }
 112
 113        /* Do mapping for the demand paging memory slot */
 114        virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
 115
 116        ucall_init(vm, NULL);
 117
 118        return vm;
 119}
 120
 121void perf_test_destroy_vm(struct kvm_vm *vm)
 122{
 123        ucall_uninit(vm);
 124        kvm_vm_free(vm);
 125}
 126
 127void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus,
 128                           uint64_t vcpu_memory_bytes,
 129                           bool partition_vcpu_memory_access)
 130{
 131        vm_paddr_t vcpu_gpa;
 132        struct perf_test_vcpu_args *vcpu_args;
 133        int vcpu_id;
 134
 135        for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) {
 136                vcpu_args = &perf_test_args.vcpu_args[vcpu_id];
 137
 138                vcpu_args->vcpu_id = vcpu_id;
 139                if (partition_vcpu_memory_access) {
 140                        vcpu_args->gva = guest_test_virt_mem +
 141                                         (vcpu_id * vcpu_memory_bytes);
 142                        vcpu_args->pages = vcpu_memory_bytes /
 143                                           perf_test_args.guest_page_size;
 144                        vcpu_gpa = guest_test_phys_mem +
 145                                   (vcpu_id * vcpu_memory_bytes);
 146                } else {
 147                        vcpu_args->gva = guest_test_virt_mem;
 148                        vcpu_args->pages = (vcpus * vcpu_memory_bytes) /
 149                                           perf_test_args.guest_page_size;
 150                        vcpu_gpa = guest_test_phys_mem;
 151                }
 152
 153                vcpu_args_set(vm, vcpu_id, 1, vcpu_id);
 154
 155                pr_debug("Added VCPU %d with test mem gpa [%lx, %lx)\n",
 156                         vcpu_id, vcpu_gpa, vcpu_gpa +
 157                         (vcpu_args->pages * perf_test_args.guest_page_size));
 158        }
 159}
 160