From patchwork Thu Jan 23 18:04:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348883 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A8F1D1398 for ; Thu, 23 Jan 2020 18:04:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6C30220718 for ; Thu, 23 Jan 2020 18:04:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rnm/qkL6" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729100AbgAWSEo (ORCPT ); Thu, 23 Jan 2020 13:04:44 -0500 Received: from mail-pj1-f73.google.com ([209.85.216.73]:36885 "EHLO mail-pj1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729095AbgAWSEo (ORCPT ); Thu, 23 Jan 2020 13:04:44 -0500 Received: by mail-pj1-f73.google.com with SMTP id dw15so2181776pjb.2 for ; Thu, 23 Jan 2020 10:04:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=bMP1ivEYoLfoo6BRmP/QM19zZPKbKMUaSN+cV58XwBY=; b=rnm/qkL6XwvQ9ewRf1qRycdXFqb5Sc/cWvYqnoSrhLhSHPYOBflIrl6zCRlWo5s9c7 R1KW07O0CsdrMUmZfVRF3jFppovxYZEbk45pgwA3Bka+ES+Sc+dEjzZbhxID/HRamGZ1 lusNwskr7vLxyRgBKsT2fIVMuFU+oE1hKp4E9GBjqygrFuOjPGA0cREvQIRmcOLBML8C C9szYjrGKi7lGH2AXomELIOHnCAsyOxUER7a92ISYiAQbp5CZn05kwGlTf5dDlLdyVyX taypNkkDKPQWJEC8lDplD/JcOkwOS/xMRVlluZJAVCACUMZ1RCl43clTfulS0wq5ji2i lgLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=bMP1ivEYoLfoo6BRmP/QM19zZPKbKMUaSN+cV58XwBY=; b=F3HmMrRGsppmGOdl4m9bWyjWvjeh8K+s7em3JxXzr8He48QTyLc2++GbpNDb5orVUt 5mQSp1drj1OE/Nwg1oZlH+arehxtDHW+/B9EH1/BVcTRj+YYVgrVZbVJ228e41lMJAZS Xu9VVyyrVGCUvsjRmBDBe6dyfFQBzn+udNHpFr/TSDthz9tAlalmJLVy1v6JHKfBvDBJ wA9Hg1ub7Eu6qDUkAupLlMbvqKxxuM58cTnrwSd9FiRIiyP7bRLguhPI1mx43II2t12y W/jljaXya+7m4OwCXfb/m5IsGiNoeXP4BotDJuzf5xYwqQfm8HPTLBxtNuAFsEu0Obbv 5Xfw== X-Gm-Message-State: APjAAAUQj/PzICyppSOoGAnMcvoGUStUilgdZP9DDdc+YaPAiWwclfhn sBeZMV4fwzJqkdnF+HJxMNrI3yqZ5lxZ X-Google-Smtp-Source: APXvYqyPWFqxAvupwDLIpRrTc0OQgiU48aRNgUulYGhJGc5OflL7FrsXvdpC//WzGV7MjoQkLJnRcIzWZ8aM X-Received: by 2002:a65:6914:: with SMTP id s20mr31136pgq.44.1579802683140; Thu, 23 Jan 2020 10:04:43 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:27 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-2-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 01/10] KVM: selftests: Create a demand paging test From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org While userfaultfd, KVM's demand paging implementation, is not specific to KVM, having a benchmark for its performance will be useful for guiding performance improvements to KVM. As a first step towards creating a userfaultfd demand paging test, create a simple memory access test, based on dirty_log_test. Reviewed-by: Oliver Upton Signed-off-by: Ben Gardon --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 3 + .../selftests/kvm/demand_paging_test.c | 286 ++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 tools/testing/selftests/kvm/demand_paging_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 30072c3f52fbe..9619d96e15c41 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -17,3 +17,4 @@ /clear_dirty_log_test /dirty_log_test /kvm_create_max_vcpus +/demand_paging_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 3138a916574a9..e2e1b92faee3b 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -28,15 +28,18 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test TEST_GEN_PROGS_x86_64 += clear_dirty_log_test TEST_GEN_PROGS_x86_64 += dirty_log_test +TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus TEST_GEN_PROGS_aarch64 += clear_dirty_log_test TEST_GEN_PROGS_aarch64 += dirty_log_test +TEST_GEN_PROGS_aarch64 += demand_paging_test TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_s390x = s390x/memop TEST_GEN_PROGS_s390x += s390x/sync_regs_test TEST_GEN_PROGS_s390x += dirty_log_test +TEST_GEN_PROGS_s390x += demand_paging_test TEST_GEN_PROGS_s390x += kvm_create_max_vcpus TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c new file mode 100644 index 0000000000000..5f214517ba1de --- /dev/null +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KVM demand paging test + * Adapted from dirty_log_test.c + * + * Copyright (C) 2018, Red Hat, Inc. + * Copyright (C) 2019, Google, Inc. + */ + +#define _GNU_SOURCE /* for program_invocation_name */ + +#include +#include +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#define VCPU_ID 1 + +/* The memory slot index demand page */ +#define TEST_MEM_SLOT_INDEX 1 + +/* Default guest test virtual memory offset */ +#define DEFAULT_GUEST_TEST_MEM 0xc0000000 + +/* + * Guest/Host shared variables. Ensure addr_gva2hva() and/or + * sync_global_to/from_guest() are used when accessing from + * the host. READ/WRITE_ONCE() should also be used with anything + * that may change. + */ +static uint64_t host_page_size; +static uint64_t guest_page_size; +static uint64_t guest_num_pages; + +/* + * Guest physical memory offset of the testing memory slot. + * This will be set to the topmost valid physical address minus + * the test memory size. + */ +static uint64_t guest_test_phys_mem; + +/* + * Guest virtual memory offset of the testing memory slot. + * Must not conflict with identity mapped test code. + */ +static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; + +/* + * Continuously write to the first 8 bytes of each page in the demand paging + * memory region. + */ +static void guest_code(void) +{ + int i; + + for (i = 0; i < guest_num_pages; i++) { + uint64_t addr = guest_test_virt_mem; + + addr += i * guest_page_size; + addr &= ~(host_page_size - 1); + *(uint64_t *)addr = 0x0123456789ABCDEF; + } + + GUEST_SYNC(1); +} + +/* Points to the test VM memory region on which we are doing demand paging */ +static void *host_test_mem; +static uint64_t host_num_pages; + +static void *vcpu_worker(void *data) +{ + int ret; + struct kvm_vm *vm = data; + struct kvm_run *run; + + run = vcpu_state(vm, VCPU_ID); + + /* Let the guest access its memory */ + ret = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); + if (get_ucall(vm, VCPU_ID, NULL) != UCALL_SYNC) { + TEST_ASSERT(false, + "Invalid guest sync status: exit_reason=%s\n", + exit_reason_str(run->exit_reason)); + } + + return NULL; +} + +static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, + uint64_t extra_mem_pages, void *guest_code) +{ + struct kvm_vm *vm; + uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; + + vm = _vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + kvm_vm_elf_load(vm, program_invocation_name, 0, 0); +#ifdef __x86_64__ + vm_create_irqchip(vm); +#endif + vm_vcpu_add_default(vm, vcpuid, guest_code); + return vm; +} + +#define GUEST_MEM_SHIFT 30 /* 1G */ +#define PAGE_SHIFT_4K 12 + +static void run_test(enum vm_guest_mode mode) +{ + pthread_t vcpu_thread; + struct kvm_vm *vm; + + /* + * We reserve page table for 2 times of extra dirty mem which + * will definitely cover the original (1G+) test range. Here + * we do the calculation with 4K page size which is the + * smallest so the page number will be enough for all archs + * (e.g., 64K page size guest will need even less memory for + * page tables). + */ + vm = create_vm(mode, VCPU_ID, + 2ul << (GUEST_MEM_SHIFT - PAGE_SHIFT_4K), + guest_code); + + guest_page_size = vm_get_page_size(vm); + /* + * A little more than 1G of guest page sized pages. Cover the + * case where the size is not aligned to 64 pages. + */ + guest_num_pages = (1ul << (GUEST_MEM_SHIFT - + vm_get_page_shift(vm))) + 16; +#ifdef __s390x__ + /* Round up to multiple of 1M (segment size) */ + guest_num_pages = (guest_num_pages + 0xff) & ~0xffUL; +#endif + + host_page_size = getpagesize(); + host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + + !!((guest_num_pages * guest_page_size) % + host_page_size); + + guest_test_phys_mem = (vm_get_max_gfn(vm) - guest_num_pages) * + guest_page_size; + guest_test_phys_mem &= ~(host_page_size - 1); + +#ifdef __s390x__ + /* Align to 1M (segment size) */ + guest_test_phys_mem &= ~((1 << 20) - 1); +#endif + + DEBUG("guest physical test memory offset: 0x%lx\n", + guest_test_phys_mem); + + + /* Add an extra memory slot for testing demand paging */ + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + guest_test_phys_mem, + TEST_MEM_SLOT_INDEX, + guest_num_pages, 0); + + /* Do mapping for the demand paging memory slot */ + virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, + guest_num_pages * guest_page_size, 0); + + /* Cache the HVA pointer of the region */ + host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_phys_mem); + +#ifdef __x86_64__ + vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); +#endif +#ifdef __aarch64__ + ucall_init(vm, NULL); +#endif + + /* Export the shared variables to the guest */ + sync_global_to_guest(vm, host_page_size); + sync_global_to_guest(vm, guest_page_size); + sync_global_to_guest(vm, guest_test_virt_mem); + sync_global_to_guest(vm, guest_num_pages); + + pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); + + /* Wait for the vcpu thread to quit */ + pthread_join(vcpu_thread, NULL); + + ucall_uninit(vm); + kvm_vm_free(vm); +} + +struct vm_guest_mode_params { + bool supported; + bool enabled; +}; +struct vm_guest_mode_params vm_guest_mode_params[NUM_VM_MODES]; + +#define vm_guest_mode_params_init(mode, supported, enabled) \ +({ \ + vm_guest_mode_params[mode] = \ + (struct vm_guest_mode_params){ supported, enabled }; \ +}) + +static void help(char *name) +{ + int i; + + puts(""); + printf("usage: %s [-h] [-m mode]\n", name); + printf(" -m: specify the guest mode ID to test\n" + " (default: test all supported modes)\n" + " This option may be used multiple times.\n" + " Guest mode IDs:\n"); + for (i = 0; i < NUM_VM_MODES; ++i) { + printf(" %d: %s%s\n", i, vm_guest_mode_string(i), + vm_guest_mode_params[i].supported ? " (supported)" : ""); + } + puts(""); + exit(0); +} + +int main(int argc, char *argv[]) +{ + bool mode_selected = false; + unsigned int mode; + int opt, i; +#ifdef __aarch64__ + unsigned int host_ipa_limit; +#endif + +#ifdef __x86_64__ + vm_guest_mode_params_init(VM_MODE_PXXV48_4K, true, true); +#endif +#ifdef __aarch64__ + vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); + vm_guest_mode_params_init(VM_MODE_P40V48_64K, true, true); + + host_ipa_limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); + if (host_ipa_limit >= 52) + vm_guest_mode_params_init(VM_MODE_P52V48_64K, true, true); + if (host_ipa_limit >= 48) { + vm_guest_mode_params_init(VM_MODE_P48V48_4K, true, true); + vm_guest_mode_params_init(VM_MODE_P48V48_64K, true, true); + } +#endif +#ifdef __s390x__ + vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); +#endif + + while ((opt = getopt(argc, argv, "hm:")) != -1) { + switch (opt) { + case 'm': + if (!mode_selected) { + for (i = 0; i < NUM_VM_MODES; ++i) + vm_guest_mode_params[i].enabled = false; + mode_selected = true; + } + mode = strtoul(optarg, NULL, 10); + TEST_ASSERT(mode < NUM_VM_MODES, + "Guest mode ID %d too big", mode); + vm_guest_mode_params[mode].enabled = true; + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + for (i = 0; i < NUM_VM_MODES; ++i) { + if (!vm_guest_mode_params[i].enabled) + continue; + TEST_ASSERT(vm_guest_mode_params[i].supported, + "Guest mode ID %d (%s) not supported.", + i, vm_guest_mode_string(i)); + run_test(i); + } + + return 0; +} From patchwork Thu Jan 23 18:04:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348887 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AFCF717EA for ; Thu, 23 Jan 2020 18:04:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7DF3C22522 for ; Thu, 23 Jan 2020 18:04:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rswnlLqJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729134AbgAWSEq (ORCPT ); Thu, 23 Jan 2020 13:04:46 -0500 Received: from mail-pj1-f74.google.com ([209.85.216.74]:43031 "EHLO mail-pj1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729122AbgAWSEq (ORCPT ); Thu, 23 Jan 2020 13:04:46 -0500 Received: by mail-pj1-f74.google.com with SMTP id 9so2167587pjn.8 for ; Thu, 23 Jan 2020 10:04:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=cQGsf25lgBgmgowyMdPpkSI0OuBqPxdwaRG5rlH9TOU=; b=rswnlLqJs/N1oZ4FNZqHbpYcIuJcQYsbmECvlEebHuZ55/jIHXM5X3BBmd+Q9TPDjO RgO5d7U9XPgGYwUIF0IXAfvuH14l0cWO1VI08ZXxIHUPO+4sUgz4Eg3luV6gpjTWNgPr mty2L4wiRXu07cFnPtwBOKGOWiu/068Op2nmNmAoeG0hbvBVJv9x4aayMxpiQGBEQuhh fKarS5kA6j920y23By7hydU90vCEYFUL/7C/dwJF+RvoWsAkuTi8ks+bXpN9i3lJLE0z +iz+P//gyeWtvV8E7dUuaxwW/oJjnq+jdsLDBrrXE3VUkJ0tAnjU3baWuWfyMFLGjsTT 8vqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=cQGsf25lgBgmgowyMdPpkSI0OuBqPxdwaRG5rlH9TOU=; b=M+1faRiP/BDlOa2aKFj4anSu3XVDgRc7778opfDD5gWW/XD/B9yZwPbDWnHLtxFbZM tAsO5lQMdtNGk6lam+m+jWKZv1dWfQ4ZMKTLl+vt41KB+X/KCI+bfyaRtI/l1IChZXMX 9TbAr0Xr4UuZDZlk9rnPCNPLZGAGD3EAmuFni2SX8/Jzb8siCdMjd1tvg1Y1LfkLjtOb TrpF4MfdZpHx7j0xDsJh2cSbW3cuqPP8xQYw6EyfLRzmpcXm9IZcUB3wdVKjyRUvssG2 GZFAvtf/EO+Q56qvbT6Fp3q+/B6bMtkJJuitNZ5zSXWweBEIC6diUEW1kuyczUU34vmx aaRA== X-Gm-Message-State: APjAAAUsLtzK6fe2rAf4ismhB+Fp4tuUaabTTWsroVtDwNDg50cEXXVO PnFzEp1gCcefWqwWS5ZhcFoUxdFI0tx5 X-Google-Smtp-Source: APXvYqxuGC8Dx7jeTN0VJLhlrXVvqKWPjVviG9Lm8j5L1hEdkhn3GjC9uldIJqgx+Pkw06HCeMxsgx/oLXnc X-Received: by 2002:a63:ce4b:: with SMTP id r11mr5432103pgi.419.1579802685421; Thu, 23 Jan 2020 10:04:45 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:28 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-3-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 02/10] KVM: selftests: Add demand paging content to the demand paging test From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org The demand paging test is currently a simple page access test which, while potentially useful, doesn't add much versus the existing dirty logging test. To improve the demand paging test, add a basic userfaultfd demand paging implementation. Signed-off-by: Ben Gardon --- .../selftests/kvm/demand_paging_test.c | 196 +++++++++++++++++- 1 file changed, 192 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 5f214517ba1de..6fab4468f97f6 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -11,11 +11,14 @@ #include #include +#include #include #include +#include #include #include #include +#include #include "test_util.h" #include "kvm_util.h" @@ -39,6 +42,8 @@ static uint64_t host_page_size; static uint64_t guest_page_size; static uint64_t guest_num_pages; +static char *guest_data_prototype; + /* * Guest physical memory offset of the testing memory slot. * This will be set to the topmost valid physical address minus @@ -110,13 +115,169 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, return vm; } +static int handle_uffd_page_request(int uffd, uint64_t addr) +{ + pid_t tid; + struct uffdio_copy copy; + int r; + + tid = syscall(__NR_gettid); + + copy.src = (uint64_t)guest_data_prototype; + copy.dst = addr; + copy.len = host_page_size; + copy.mode = 0; + + r = ioctl(uffd, UFFDIO_COPY, ©); + if (r == -1) { + DEBUG("Failed Paged in 0x%lx from thread %d with errno: %d\n", + addr, tid, errno); + return r; + } + + return 0; +} + +bool quit_uffd_thread; + +struct uffd_handler_args { + int uffd; + int pipefd; +}; + +static void *uffd_handler_thread_fn(void *arg) +{ + struct uffd_handler_args *uffd_args = (struct uffd_handler_args *)arg; + int uffd = uffd_args->uffd; + int pipefd = uffd_args->pipefd; + int64_t pages = 0; + + while (!quit_uffd_thread) { + struct uffd_msg msg; + struct pollfd pollfd[2]; + char tmp_chr; + int r; + uint64_t addr; + + pollfd[0].fd = uffd; + pollfd[0].events = POLLIN; + pollfd[1].fd = pipefd; + pollfd[1].events = POLLIN; + + r = poll(pollfd, 2, -1); + switch (r) { + case -1: + DEBUG("poll err"); + continue; + case 0: + continue; + case 1: + break; + default: + DEBUG("Polling uffd returned %d", r); + return NULL; + } + + if (pollfd[0].revents & POLLERR) { + DEBUG("uffd revents has POLLERR"); + return NULL; + } + + if (pollfd[1].revents & POLLIN) { + r = read(pollfd[1].fd, &tmp_chr, 1); + TEST_ASSERT(r == 1, + "Error reading pipefd in UFFD thread\n"); + return NULL; + } + + if (!pollfd[0].revents & POLLIN) + continue; + + r = read(uffd, &msg, sizeof(msg)); + if (r == -1) { + if (errno == EAGAIN) + continue; + DEBUG("Read of uffd gor errno %d", errno); + return NULL; + } + + if (r != sizeof(msg)) { + DEBUG("Read on uffd returned unexpected size: %d bytes", + r); + return NULL; + } + + if (!(msg.event & UFFD_EVENT_PAGEFAULT)) + continue; + + addr = msg.arg.pagefault.address; + r = handle_uffd_page_request(uffd, addr); + if (r < 0) + return NULL; + pages++; + } + + return NULL; +} + +static int setup_demand_paging(struct kvm_vm *vm, + pthread_t *uffd_handler_thread, int pipefd) +{ + int uffd; + struct uffdio_api uffdio_api; + struct uffdio_register uffdio_register; + struct uffd_handler_args uffd_args; + + guest_data_prototype = malloc(host_page_size); + TEST_ASSERT(guest_data_prototype, + "Failed to allocate buffer for guest data pattern"); + memset(guest_data_prototype, 0xAB, host_page_size); + + uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (uffd == -1) { + DEBUG("uffd creation failed\n"); + return -1; + } + + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1) { + DEBUG("ioctl uffdio_api failed\n"); + return -1; + } + + uffdio_register.range.start = (uint64_t)host_test_mem; + uffdio_register.range.len = host_num_pages * host_page_size; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) { + DEBUG("ioctl uffdio_register failed\n"); + return -1; + } + + if ((uffdio_register.ioctls & UFFD_API_RANGE_IOCTLS) != + UFFD_API_RANGE_IOCTLS) { + DEBUG("unexpected userfaultfd ioctl set\n"); + return -1; + } + + uffd_args.uffd = uffd; + uffd_args.pipefd = pipefd; + pthread_create(uffd_handler_thread, NULL, uffd_handler_thread_fn, + &uffd_args); + + return 0; +} + #define GUEST_MEM_SHIFT 30 /* 1G */ #define PAGE_SHIFT_4K 12 -static void run_test(enum vm_guest_mode mode) +static void run_test(enum vm_guest_mode mode, bool use_uffd) { pthread_t vcpu_thread; + pthread_t uffd_handler_thread; + int pipefd[2]; struct kvm_vm *vm; + int r; /* * We reserve page table for 2 times of extra dirty mem which @@ -173,6 +334,16 @@ static void run_test(enum vm_guest_mode mode) /* Cache the HVA pointer of the region */ host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_phys_mem); + if (use_uffd) { + /* Set up user fault fd to handle demand paging requests. */ + r = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK); + TEST_ASSERT(!r, "Failed to set up pipefd"); + + r = setup_demand_paging(vm, &uffd_handler_thread, pipefd[0]); + if (r < 0) + exit(-r); + } + #ifdef __x86_64__ vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); #endif @@ -191,8 +362,20 @@ static void run_test(enum vm_guest_mode mode) /* Wait for the vcpu thread to quit */ pthread_join(vcpu_thread, NULL); + if (use_uffd) { + char c; + + /* Tell the user fault fd handler thread to quit */ + r = write(pipefd[1], &c, 1); + TEST_ASSERT(r == 1, "Unable to write to pipefd"); + + pthread_join(uffd_handler_thread, NULL); + } + ucall_uninit(vm); kvm_vm_free(vm); + + free(guest_data_prototype); } struct vm_guest_mode_params { @@ -212,7 +395,7 @@ static void help(char *name) int i; puts(""); - printf("usage: %s [-h] [-m mode]\n", name); + printf("usage: %s [-h] [-m mode] [-u]\n", name); printf(" -m: specify the guest mode ID to test\n" " (default: test all supported modes)\n" " This option may be used multiple times.\n" @@ -221,6 +404,7 @@ static void help(char *name) printf(" %d: %s%s\n", i, vm_guest_mode_string(i), vm_guest_mode_params[i].supported ? " (supported)" : ""); } + printf(" -u: Use User Fault FD to handle vCPU page faults.\n"); puts(""); exit(0); } @@ -230,6 +414,7 @@ int main(int argc, char *argv[]) bool mode_selected = false; unsigned int mode; int opt, i; + bool use_uffd = false; #ifdef __aarch64__ unsigned int host_ipa_limit; #endif @@ -253,7 +438,7 @@ int main(int argc, char *argv[]) vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); #endif - while ((opt = getopt(argc, argv, "hm:")) != -1) { + while ((opt = getopt(argc, argv, "hm:u")) != -1) { switch (opt) { case 'm': if (!mode_selected) { @@ -266,6 +451,9 @@ int main(int argc, char *argv[]) "Guest mode ID %d too big", mode); vm_guest_mode_params[mode].enabled = true; break; + case 'u': + use_uffd = true; + break; case 'h': default: help(argv[0]); @@ -279,7 +467,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(vm_guest_mode_params[i].supported, "Guest mode ID %d (%s) not supported.", i, vm_guest_mode_string(i)); - run_test(i); + run_test(i, use_uffd); } return 0; From patchwork Thu Jan 23 18:04:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348921 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 900381398 for ; Thu, 23 Jan 2020 18:05:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5E94622464 for ; Thu, 23 Jan 2020 18:05:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="E+iKTJpp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729157AbgAWSEu (ORCPT ); Thu, 23 Jan 2020 13:04:50 -0500 Received: from mail-pl1-f202.google.com ([209.85.214.202]:51236 "EHLO mail-pl1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729146AbgAWSEs (ORCPT ); Thu, 23 Jan 2020 13:04:48 -0500 Received: by mail-pl1-f202.google.com with SMTP id r2so1825482pls.18 for ; Thu, 23 Jan 2020 10:04:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=+ajBlD4ZsHzsHJt9G432a6UKIjktZtDyWcSq/QWbHJg=; b=E+iKTJppKfOA15AHNg+JNQPSdGCNa5Uim57JFueZ6xE2XII/5MRDURCmW2HDphgv4z LKGdN16W71YvHNQtTZhiMUJEKlkk3gQnGLB+AAdgS3DPuhQl5Ro/NcXNPR/vK43uOlHp bnXvAW/Y4EcMRojH2fnMUdD8Mt6HPLKAZVV0p86vH/PCc62W5I0dM5DD77tVKV6BFDCF ByQOt+sBgOU25p6T9O/J7gw/xNjI9uHh1g76P/D2x86cmhVlZZ/LlNU9B+0lL+CjOp19 H621VSO0YK5egEusQt9dZUPuZ96hyimPiOr8/Co3HQwFdB/aPAjoDI2RkR0qlM7xifmt BpMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=+ajBlD4ZsHzsHJt9G432a6UKIjktZtDyWcSq/QWbHJg=; b=mn5qp+Oa4QO0+78UsBdqTyJ+R6Lkmug6gy58iPPa+1RgpMhQQFq60A1dLJ0pebP+sA dFyTYPs2JK67Kd2bKFxJ8I8yI1T30zkwTXXYH7R09ZCXFbZPAANo5E5rBpQkb34+CKjI uUa8PaRxjF1SLyPTDMgHWoJqW0DqYWqgBN1Vnt7SWSO6ppTQeOFfjgF5Fc9Th4Rsafgr LlTxCjLEaZ8HoeCEDsf6DTJx9OIf2KhyhFSUbNVkICJBVsF4SVDCcITcfXBDkPELz4Mt nJCHEfNFVLNC0LtYfznPbcbJ+F0U7aT7lZ8/beJqcW5FhzOwHCk2UV04X0ArYpkvvV9d V0vA== X-Gm-Message-State: APjAAAVc6tT52oSfDFKkuMXB84iOKw4Hh3lWws2FbHNhasSUyoTg8x+f 68WEZo14pGPmNRz+Z7wNUqemwOOiJ3LQ X-Google-Smtp-Source: APXvYqznzCF8rkNRgq/SBrtTpV1jgeJBFQ2M2VKjD3QumwjpQ1GXpdc/5kqyqt7Z2jAeQ3iIDZCvgKjQ69Cq X-Received: by 2002:a63:d306:: with SMTP id b6mr5132435pgg.195.1579802687628; Thu, 23 Jan 2020 10:04:47 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:29 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-4-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 03/10] KVM: selftests: Add configurable demand paging delay From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org When running the demand paging test with the -u option, the User Fault FD handler essentially adds an arbitrary delay to page fault resolution. To enable better simulation of a real demand paging scenario, add a configurable delay to the UFFD handler. Reviewed-by: Peter Xu Signed-off-by: Ben Gardon --- .../selftests/kvm/demand_paging_test.c | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 6fab4468f97f6..01d2c76ada55d 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -143,6 +143,7 @@ bool quit_uffd_thread; struct uffd_handler_args { int uffd; int pipefd; + useconds_t delay; }; static void *uffd_handler_thread_fn(void *arg) @@ -150,6 +151,7 @@ static void *uffd_handler_thread_fn(void *arg) struct uffd_handler_args *uffd_args = (struct uffd_handler_args *)arg; int uffd = uffd_args->uffd; int pipefd = uffd_args->pipefd; + useconds_t delay = uffd_args->delay; int64_t pages = 0; while (!quit_uffd_thread) { @@ -210,6 +212,8 @@ static void *uffd_handler_thread_fn(void *arg) if (!(msg.event & UFFD_EVENT_PAGEFAULT)) continue; + if (delay) + usleep(delay); addr = msg.arg.pagefault.address; r = handle_uffd_page_request(uffd, addr); if (r < 0) @@ -221,7 +225,8 @@ static void *uffd_handler_thread_fn(void *arg) } static int setup_demand_paging(struct kvm_vm *vm, - pthread_t *uffd_handler_thread, int pipefd) + pthread_t *uffd_handler_thread, int pipefd, + useconds_t uffd_delay) { int uffd; struct uffdio_api uffdio_api; @@ -262,6 +267,7 @@ static int setup_demand_paging(struct kvm_vm *vm, uffd_args.uffd = uffd; uffd_args.pipefd = pipefd; + uffd_args.delay = uffd_delay; pthread_create(uffd_handler_thread, NULL, uffd_handler_thread_fn, &uffd_args); @@ -271,7 +277,8 @@ static int setup_demand_paging(struct kvm_vm *vm, #define GUEST_MEM_SHIFT 30 /* 1G */ #define PAGE_SHIFT_4K 12 -static void run_test(enum vm_guest_mode mode, bool use_uffd) +static void run_test(enum vm_guest_mode mode, bool use_uffd, + useconds_t uffd_delay) { pthread_t vcpu_thread; pthread_t uffd_handler_thread; @@ -339,7 +346,8 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd) r = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK); TEST_ASSERT(!r, "Failed to set up pipefd"); - r = setup_demand_paging(vm, &uffd_handler_thread, pipefd[0]); + r = setup_demand_paging(vm, &uffd_handler_thread, pipefd[0], + uffd_delay); if (r < 0) exit(-r); } @@ -395,7 +403,7 @@ static void help(char *name) int i; puts(""); - printf("usage: %s [-h] [-m mode] [-u]\n", name); + printf("usage: %s [-h] [-m mode] [-u] [-d uffd_delay_usec]\n", name); printf(" -m: specify the guest mode ID to test\n" " (default: test all supported modes)\n" " This option may be used multiple times.\n" @@ -404,7 +412,11 @@ static void help(char *name) printf(" %d: %s%s\n", i, vm_guest_mode_string(i), vm_guest_mode_params[i].supported ? " (supported)" : ""); } - printf(" -u: Use User Fault FD to handle vCPU page faults.\n"); + printf(" -u: use User Fault FD to handle vCPU page\n" + " faults.\n"); + printf(" -d: add a delay in usec to the User Fault\n" + " FD handler to simulate demand paging\n" + " overheads. Ignored without -u.\n"); puts(""); exit(0); } @@ -415,6 +427,7 @@ int main(int argc, char *argv[]) unsigned int mode; int opt, i; bool use_uffd = false; + useconds_t uffd_delay = 0; #ifdef __aarch64__ unsigned int host_ipa_limit; #endif @@ -438,7 +451,7 @@ int main(int argc, char *argv[]) vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); #endif - while ((opt = getopt(argc, argv, "hm:u")) != -1) { + while ((opt = getopt(argc, argv, "hm:ud:")) != -1) { switch (opt) { case 'm': if (!mode_selected) { @@ -454,6 +467,11 @@ int main(int argc, char *argv[]) case 'u': use_uffd = true; break; + case 'd': + uffd_delay = strtoul(optarg, NULL, 0); + TEST_ASSERT(uffd_delay >= 0, + "A negative UFFD delay is not supported."); + break; case 'h': default: help(argv[0]); @@ -467,7 +485,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(vm_guest_mode_params[i].supported, "Guest mode ID %d (%s) not supported.", i, vm_guest_mode_string(i)); - run_test(i, use_uffd); + run_test(i, use_uffd, uffd_delay); } return 0; From patchwork Thu Jan 23 18:04:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348891 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1F26F17EA for ; Thu, 23 Jan 2020 18:04:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D864D24125 for ; Thu, 23 Jan 2020 18:04:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RlzHUnZd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729174AbgAWSEv (ORCPT ); Thu, 23 Jan 2020 13:04:51 -0500 Received: from mail-pg1-f202.google.com ([209.85.215.202]:49507 "EHLO mail-pg1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729158AbgAWSEu (ORCPT ); Thu, 23 Jan 2020 13:04:50 -0500 Received: by mail-pg1-f202.google.com with SMTP id u14so2222462pgq.16 for ; Thu, 23 Jan 2020 10:04:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=MyR2A3lG/6QZG1DSQDGZ1Xyya7Fcg8NXjHhCQPSoGIY=; b=RlzHUnZdlr2kuwqncMOZ9TpW0T8gMRYwxGtx+ywksjUQpzix1ZLfp+Puk+FjAU7Vid 7gS0I3dp7o97USaMcHQ0ONQnvTqMoMFUWdW1ZtLI4mon1Pj587pZhuph8HKqpL3rUP5E m1BvKW+6JJW+8LOC/l4JDog8G0V1M14wFCJ7tONfEt1dQKaacGfrqgvyPVGAoLAz0lr0 GC8f1r9+LPfvcN2S8JuesYPDn5MUVxS9qY7+2xSSprpAfgEi1sWcvzqV++78IJ/MuLtp QdSqk1rUDN2LqzdGlfIQEuGa8bkfdMGo/si2F1JzfdouYGyjwT7S5z8AsHPRwJ5ki7JW VU8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=MyR2A3lG/6QZG1DSQDGZ1Xyya7Fcg8NXjHhCQPSoGIY=; b=pKe1udMzL/sv98TvKYcVBKD0pb+F2SI4MURNk9osyQUSjZwatmG9hg3j8mb91br7lh JQkAHZ8iMudCv4RYyIF9UFsbA5lr+sRjGwMpksarpmEqiWJnNOkGhBZBHvDiXgqPrWQ3 6pt7N8zu6o+ba+hdyKM0XV+eganoCkq/ymuYKhxehQsuFMX+kxE36LqHDtSLito1HmXv HWk9/JzUh22DinjyGAp/nXQdSupupVVBJIZrpcPVcYVE7JTLxLDC8MbHPxUQqEWWjwAE U5DKAOeysvLeE2xJkNr4VH87fpR4RrB/9/YE7/d6wb84C5sFOfG4VaY6IgsI0Z4zK1KF QKQw== X-Gm-Message-State: APjAAAVva6wonwKX4dhzzZXauaBJmL+X54bOWR3zz0mCoGOP4JxEMwjD JviFrhefVjNvSw32Ii3MkRZCvj6/i6jJ X-Google-Smtp-Source: APXvYqwMosnV9otkmUQmnv1fnNu+pzuFVtdPbNtGNih2YrjaFj5/U612rkJAHjRqsAYBuyNxABqKDFAF+NTd X-Received: by 2002:a63:211f:: with SMTP id h31mr4933362pgh.299.1579802689866; Thu, 23 Jan 2020 10:04:49 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:30 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-5-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 04/10] KVM: selftests: Add memory size parameter to the demand paging test From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Add an argument to allow the demand paging test to work on larger and smaller guest sizes. Signed-off-by: Ben Gardon --- tools/testing/selftests/kvm/Makefile | 2 +- .../selftests/kvm/demand_paging_test.c | 57 ++++++++++------- .../testing/selftests/kvm/include/test_util.h | 2 + tools/testing/selftests/kvm/lib/test_util.c | 61 +++++++++++++++++++ 4 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 tools/testing/selftests/kvm/lib/test_util.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index e2e1b92faee3b..89bf05d4c2f3e 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -7,7 +7,7 @@ top_srcdir = ../../../.. KSFT_KHDR_INSTALL := 1 UNAME_M := $(shell uname -m) -LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c +LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c lib/test_util.c LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/ucall.c LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 01d2c76ada55d..9d7514e96a639 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -32,6 +32,8 @@ /* Default guest test virtual memory offset */ #define DEFAULT_GUEST_TEST_MEM 0xc0000000 +#define DEFAULT_GUEST_TEST_MEM_SIZE (1 << 30) /* 1G */ + /* * Guest/Host shared variables. Ensure addr_gva2hva() and/or * sync_global_to/from_guest() are used when accessing from @@ -274,11 +276,10 @@ static int setup_demand_paging(struct kvm_vm *vm, return 0; } -#define GUEST_MEM_SHIFT 30 /* 1G */ #define PAGE_SHIFT_4K 12 static void run_test(enum vm_guest_mode mode, bool use_uffd, - useconds_t uffd_delay) + useconds_t uffd_delay, uint64_t guest_memory_bytes) { pthread_t vcpu_thread; pthread_t uffd_handler_thread; @@ -287,33 +288,40 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, int r; /* - * We reserve page table for 2 times of extra dirty mem which - * will definitely cover the original (1G+) test range. Here - * we do the calculation with 4K page size which is the - * smallest so the page number will be enough for all archs - * (e.g., 64K page size guest will need even less memory for - * page tables). + * We reserve page table for twice the ammount of memory we intend + * to use in the test region for demand paging. Here we do the + * calculation with 4K page size which is the smallest so the page + * number will be enough for all archs. (e.g., 64K page size guest + * will need even less memory for page tables). */ vm = create_vm(mode, VCPU_ID, - 2ul << (GUEST_MEM_SHIFT - PAGE_SHIFT_4K), + (2 * guest_memory_bytes) >> PAGE_SHIFT_4K, guest_code); guest_page_size = vm_get_page_size(vm); - /* - * A little more than 1G of guest page sized pages. Cover the - * case where the size is not aligned to 64 pages. - */ - guest_num_pages = (1ul << (GUEST_MEM_SHIFT - - vm_get_page_shift(vm))) + 16; + + TEST_ASSERT(guest_memory_bytes % guest_page_size == 0, + "Guest memory size is not guest page size aligned."); + + guest_num_pages = guest_memory_bytes / guest_page_size; + #ifdef __s390x__ /* Round up to multiple of 1M (segment size) */ guest_num_pages = (guest_num_pages + 0xff) & ~0xffUL; #endif + /* + * If there should be more memory in the guest test region than there + * can be pages in the guest, it will definitely cause problems. + */ + TEST_ASSERT(guest_num_pages < vm_get_max_gfn(vm), + "Requested more guest memory than address space allows.\n" + " guest pages: %lx max gfn: %lx\n", + guest_num_pages, vm_get_max_gfn(vm)); host_page_size = getpagesize(); - host_num_pages = (guest_num_pages * guest_page_size) / host_page_size + - !!((guest_num_pages * guest_page_size) % - host_page_size); + TEST_ASSERT(guest_memory_bytes % host_page_size == 0, + "Guest memory size is not host page size aligned."); + host_num_pages = guest_memory_bytes / host_page_size; guest_test_phys_mem = (vm_get_max_gfn(vm) - guest_num_pages) * guest_page_size; @@ -403,7 +411,8 @@ static void help(char *name) int i; puts(""); - printf("usage: %s [-h] [-m mode] [-u] [-d uffd_delay_usec]\n", name); + printf("usage: %s [-h] [-m mode] [-u] [-d uffd_delay_usec]\n" + " [-b memory]\n", name); printf(" -m: specify the guest mode ID to test\n" " (default: test all supported modes)\n" " This option may be used multiple times.\n" @@ -417,6 +426,8 @@ static void help(char *name) printf(" -d: add a delay in usec to the User Fault\n" " FD handler to simulate demand paging\n" " overheads. Ignored without -u.\n"); + printf(" -b: specify the size of the memory region which should be\n" + " demand paged. e.g. 10M or 3G. Default: 1G\n"); puts(""); exit(0); } @@ -424,6 +435,7 @@ static void help(char *name) int main(int argc, char *argv[]) { bool mode_selected = false; + uint64_t guest_memory_bytes = DEFAULT_GUEST_TEST_MEM_SIZE; unsigned int mode; int opt, i; bool use_uffd = false; @@ -451,7 +463,7 @@ int main(int argc, char *argv[]) vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); #endif - while ((opt = getopt(argc, argv, "hm:ud:")) != -1) { + while ((opt = getopt(argc, argv, "hm:ud:b:")) != -1) { switch (opt) { case 'm': if (!mode_selected) { @@ -472,6 +484,9 @@ int main(int argc, char *argv[]) TEST_ASSERT(uffd_delay >= 0, "A negative UFFD delay is not supported."); break; + case 'b': + guest_memory_bytes = parse_size(optarg); + break; case 'h': default: help(argv[0]); @@ -485,7 +500,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(vm_guest_mode_params[i].supported, "Guest mode ID %d (%s) not supported.", i, vm_guest_mode_string(i)); - run_test(i, use_uffd, uffd_delay); + run_test(i, use_uffd, uffd_delay, guest_memory_bytes); } return 0; diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index a41db6fb7e24b..e696c8219d69a 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -39,4 +39,6 @@ void test_assert(bool exp, const char *exp_str, #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ } while (0) +size_t parse_size(const char *size); + #endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c new file mode 100644 index 0000000000000..706e0f963a44b --- /dev/null +++ b/tools/testing/selftests/kvm/lib/test_util.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tools/testing/selftests/kvm/lib/test_util.c + * + * Copyright (C) 2020, Google LLC. + */ + +#include "test_util.h" + +#include + +/* + * Parses "[0-9]+[kmgt]?". + */ +size_t parse_size(const char *size) +{ + size_t len = strlen(size); + size_t i; + size_t scale_shift = 0; + size_t base; + + TEST_ASSERT(len > 0, "Need at least 1 digit in '%s'", size); + + /* Find the first letter in the string, indicating scale. */ + for (i = 0; i < len; i++) { + if (!isdigit(size[i])) { + TEST_ASSERT(i > 0, "Need at least 1 digit in '%s'", + size); + TEST_ASSERT(i == len - 1, + "Expected letter at the end in '%s'.", + size); + switch (tolower(size[i])) { + case 't': + scale_shift = 40; + break; + case 'g': + scale_shift = 30; + break; + case 'm': + scale_shift = 20; + break; + case 'k': + scale_shift = 10; + break; + default: + TEST_ASSERT(false, "Unknown size letter %c", + size[i]); + } + } + } + + TEST_ASSERT(scale_shift < 8 * sizeof(size_t), + "Overflow parsing scale!"); + + base = atoi(size); + + TEST_ASSERT(!(base & ~((1 << (sizeof(size_t) - scale_shift)) - 1)), + "Overflow parsing size!"); + + return base << scale_shift; +} From patchwork Thu Jan 23 18:04:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348915 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1210617EF for ; Thu, 23 Jan 2020 18:05:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DFEE722522 for ; Thu, 23 Jan 2020 18:05:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="PLyp6z0C" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728827AbgAWSEx (ORCPT ); Thu, 23 Jan 2020 13:04:53 -0500 Received: from mail-pj1-f73.google.com ([209.85.216.73]:34178 "EHLO mail-pj1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729187AbgAWSEw (ORCPT ); Thu, 23 Jan 2020 13:04:52 -0500 Received: by mail-pj1-f73.google.com with SMTP id c67so1508800pje.1 for ; Thu, 23 Jan 2020 10:04:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ii0SHfgzZYUwZb7/pvTlYqckx+NQoa62QNzOVUMGLgE=; b=PLyp6z0CAVfybtr5KJdK4BBfI+xCS6iijTEsVuy8dz1EF81cfVUm4jiBXsFCTUknHo PQcVYi9HFjlQ5LQF3cJuh3cErtPPBfqEOtl80cfSmYoh6giejP2Xkeq55zSVbOmvAN5c 8k0WJW1tSCXKy6+3lSxlXbHecJrTCsrfCfi0xHnYWCcovJUUbkNozPqdX0W6PNALccJq jIl8iyp/gVfDlvYKWBhGVu7CU958B2XFlDQTIyeGJM1aTQZknxXggjEn6RRpB9A0BTJK LfB+OWKCtg9PDadtPS5KLpFsWhsJ7RvAWYpuz5CYl2wZLcS0n/uJcp4haojwUTA5E/Ig iH4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ii0SHfgzZYUwZb7/pvTlYqckx+NQoa62QNzOVUMGLgE=; b=T1mJViIJzGv+Bv0Wzdl4T9V2JHM9a5tUZZt7qndFKkbvOvAdkwJWwqJfmkRCtlCKrq a8Aj+e/LbEGGCTo0rUQ8Moof68peynhoTtVRc0Yy23zFDUTy6rUhMcMKYHCn0pvKwZD6 Y97npY0wmLnMX23Li8dcNa0h59bysbRXrUSd/qoHnnAW2YoPXZSN/rJnn9mIo8+ooJTI FWD4CCp65XLIEDCrlzvE7M3VSuI1HPiev+SIZ+6q11DEZZk5MKAnWmksFJyFm23Ld93X wq+340JPXMFToDtkVsiG/Ztsuz/GGbHrUtI+8JO0crb8noiX0N5UVOB7HCt5Ok/Bx1d/ vOvQ== X-Gm-Message-State: APjAAAVVArxcqZL9SFk3kUV1/F3KNVNnzMDKmNNSVTf/DbaSXQ9ii0EP DOZdMTTbkxHTSjbeMROCuR22NgY9R0Oq X-Google-Smtp-Source: APXvYqzoG885PQKUB+5r9e3ERU5dNsON806PZLYtG3pHCaY+uutcjNNjYcphpDoZq+MA1e7JH20yRhKI/XzA X-Received: by 2002:a63:5fca:: with SMTP id t193mr33015pgb.28.1579802691847; Thu, 23 Jan 2020 10:04:51 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:31 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-6-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 05/10] KVM: selftests: Pass args to vCPU in global vCPU args struct From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In preparation for supporting multiple vCPUs in the demand paging test, pass arguments to the vCPU in a consolidated global struct instead of syncing multiple globals. Signed-off-by: Ben Gardon --- .../selftests/kvm/demand_paging_test.c | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 9d7514e96a639..9e2a5f7dfa140 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -42,7 +42,6 @@ */ static uint64_t host_page_size; static uint64_t guest_page_size; -static uint64_t guest_num_pages; static char *guest_data_prototype; @@ -59,18 +58,30 @@ static uint64_t guest_test_phys_mem; */ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; +struct vcpu_args { + uint64_t gva; + uint64_t pages; + + /* Only used by the host userspace part of the vCPU thread */ + int vcpu_id; + struct kvm_vm *vm; +}; + +static struct vcpu_args vcpu_args; + /* * Continuously write to the first 8 bytes of each page in the demand paging * memory region. */ static void guest_code(void) { + uint64_t gva = vcpu_args.gva; + uint64_t pages = vcpu_args.pages; int i; - for (i = 0; i < guest_num_pages; i++) { - uint64_t addr = guest_test_virt_mem; + for (i = 0; i < pages; i++) { + uint64_t addr = gva + (i * guest_page_size); - addr += i * guest_page_size; addr &= ~(host_page_size - 1); *(uint64_t *)addr = 0x0123456789ABCDEF; } @@ -85,15 +96,16 @@ static uint64_t host_num_pages; static void *vcpu_worker(void *data) { int ret; - struct kvm_vm *vm = data; + struct kvm_vm *vm = vcpu_args.vm; + int vcpu_id = vcpu_args.vcpu_id; struct kvm_run *run; - run = vcpu_state(vm, VCPU_ID); + run = vcpu_state(vm, vcpu_id); /* Let the guest access its memory */ - ret = _vcpu_run(vm, VCPU_ID); + ret = _vcpu_run(vm, vcpu_id); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - if (get_ucall(vm, VCPU_ID, NULL) != UCALL_SYNC) { + if (get_ucall(vm, vcpu_id, NULL) != UCALL_SYNC) { TEST_ASSERT(false, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); @@ -285,6 +297,7 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, pthread_t uffd_handler_thread; int pipefd[2]; struct kvm_vm *vm; + uint64_t guest_num_pages; int r; /* @@ -370,10 +383,13 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, /* Export the shared variables to the guest */ sync_global_to_guest(vm, host_page_size); sync_global_to_guest(vm, guest_page_size); - sync_global_to_guest(vm, guest_test_virt_mem); - sync_global_to_guest(vm, guest_num_pages); - pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); + vcpu_args.vm = vm; + vcpu_args.vcpu_id = VCPU_ID; + vcpu_args.gva = guest_test_virt_mem; + vcpu_args.pages = guest_num_pages; + sync_global_to_guest(vm, vcpu_args); + pthread_create(&vcpu_thread, NULL, vcpu_worker, &vcpu_args); /* Wait for the vcpu thread to quit */ pthread_join(vcpu_thread, NULL); From patchwork Thu Jan 23 18:04:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348913 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 87D571398 for ; Thu, 23 Jan 2020 18:05:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6149322522 for ; Thu, 23 Jan 2020 18:05:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="I/C8CMtD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729335AbgAWSF0 (ORCPT ); Thu, 23 Jan 2020 13:05:26 -0500 Received: from mail-pf1-f201.google.com ([209.85.210.201]:47016 "EHLO mail-pf1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729214AbgAWSEy (ORCPT ); Thu, 23 Jan 2020 13:04:54 -0500 Received: by mail-pf1-f201.google.com with SMTP id i6so2085886pfa.13 for ; Thu, 23 Jan 2020 10:04:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=fRJtGzU1nWtZCwyyEdBQOQV0uriURdFY4YOkq57xKFA=; b=I/C8CMtDyMwkAyRWTigJSrx8ByPwzQxVcP2Y+qJ4lGvA2rQUQ+UnnLo7HnBLIstBBI Se+PwmLQHN+LOVGuJqJzd/H7Bcbp05STGoP3ij0oUhXZqXYtjMxODspqKQ+r0Qf/48bi XXhUwajJPI3kaI+9Ok0tfbC6HBRjJ6XiYJGcpudGe+aY+EvqIUsCZEGShQlf86XZaWzo Q2P/+Y2eTaAm8vFcIPTkCe/0dFigQC6wmq42DqOwPkIRwZyXrBrWJGdFPD1QSYjfNjYL rV8Z0D6oaAwGzyN0FI4d4McSMqWxeax+btspKH6/+JWKqHjpJ9le7DXX1SDGH0LLCwJn jHSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=fRJtGzU1nWtZCwyyEdBQOQV0uriURdFY4YOkq57xKFA=; b=iUHi+kMojvN2k3QjFRcyJtr6FLYjGi7sxY7kCpgrpxG0qkCJGXqH3DQTu+Hl8B8l3b GBg8ppqtML1Z2Q4gkoPsd/aS4SCDkzAc8Lm/6nhEGH3TFWkj+tygSDjAR2Gpzys4sLE6 4hRtuR2hfqVSJNbLN2ZrIgBs75XzFqIXSrS3gg7MmGGGkngHlzCWmxwRIA1TvY3S9GUM FdXP5uA23T4VVzcdwCoxfLkHi/wlk/RyQAjyb1R6Z22QILk+6RKK2TFxHNshbYmQhNV4 nfOSlQWjkVViWMryd1RSzvdVaFmact9ikzjn/mQ/lbJ+dK5oP++was6uxcLB6dwl3FS6 tWsQ== X-Gm-Message-State: APjAAAVT2h2OZt36ybikpxblSavSKIHMTETY2kSyg5dUJBCx5yIf/vSh sD1mr8MfbqEBnrliIodyFVqJJ3iJAA5d X-Google-Smtp-Source: APXvYqx0aHZM1DcqSFTVtQf5JBTmVMs5XjbKOT9oAFEQnjFFCQcfL2/KGMJmFYibuxRpdeVN5YZ1pdPKWiZd X-Received: by 2002:a63:6c86:: with SMTP id h128mr14829pgc.200.1579802694008; Thu, 23 Jan 2020 10:04:54 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:32 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-7-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 06/10] KVM: selftests: Add support for vcpu_args_set to aarch64 and s390x From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Currently vcpu_args_set is only implemented for x86. This makes writing tests with multiple vCPUs difficult as each guest vCPU must either a.) do the same thing or b.) derive some kind of unique token from it's registers or the architecture. To simplify the process of writing tests with multiple vCPUs for s390 and aarch64, add set args functions for those architectures. Signed-off-by: Ben Gardon Reviewed-by: ... --- .../selftests/kvm/lib/aarch64/processor.c | 33 +++++++++++++++++ .../selftests/kvm/lib/s390x/processor.c | 35 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 86036a59a668e..a2ff90a75f326 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -333,3 +333,36 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) { aarch64_vcpu_add_default(vm, vcpuid, NULL, guest_code); } + +/* VM VCPU Args Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * num - number of arguments + * ... - arguments, each of type uint64_t + * + * Output Args: None + * + * Return: None + * + * Sets the first num function input arguments to the values + * given as variable args. Each of the variable args is expected to + * be of type uint64_t. The registers set by this function are r0-r7. + */ +void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +{ + va_list ap; + + TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n" + " num: %u\n", + num); + + va_start(ap, num); + + for (i = 0; i < num; i++) + set_reg(vm, vcpuid, ARM64_CORE_REG(regs.regs[num]), + va_arg(ap, uint64_t)); + + va_end(ap); +} diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index 32a02360b1eb0..680f37be9dbc9 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -269,6 +269,41 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) run->psw_addr = (uintptr_t)guest_code; } +/* VM VCPU Args Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * num - number of arguments + * ... - arguments, each of type uint64_t + * + * Output Args: None + * + * Return: None + * + * Sets the first num function input arguments to the values + * given as variable args. Each of the variable args is expected to + * be of type uint64_t. The registers set by this function are r2-r6. + */ +void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +{ + va_list ap; + struct kvm_regs regs; + + TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args,\n" + " num: %u\n", + num); + + va_start(ap, num); + vcpu_regs_get(vm, vcpuid, ®s); + + for (i = 0; i < num; i++) + regs.gprs[i + 2] = va_arg(ap, uint64_t); + + vcpu_regs_set(vm, vcpuid, ®s); + va_end(ap); +} + void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { struct vcpu *vcpu = vm->vcpu_head; From patchwork Thu Jan 23 18:04:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348911 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EA6741398 for ; Thu, 23 Jan 2020 18:05:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9FA2E22522 for ; Thu, 23 Jan 2020 18:05:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="scIBMgPi" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729207AbgAWSFT (ORCPT ); Thu, 23 Jan 2020 13:05:19 -0500 Received: from mail-pj1-f73.google.com ([209.85.216.73]:41229 "EHLO mail-pj1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729160AbgAWSE5 (ORCPT ); Thu, 23 Jan 2020 13:04:57 -0500 Received: by mail-pj1-f73.google.com with SMTP id gn11so2175804pjb.6 for ; Thu, 23 Jan 2020 10:04:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=iHwk2I40SfwaU3weFFb5+gmEFCYp0781ytUemeZAP8g=; b=scIBMgPiJJpKIoAPUz1MO/whBbLkQC/q1Thd+cjzNryymJFDgRDk9QCL4zrFhT2m4h RYmmcNrFIYpGFGpSI04lhTEZ5cOph9oW4APAMPbHGbSDyesTmD3x9dPKIARh+sxddDVm FynfpcZFMkV7KaTdCFT6oekdxiWuk6HoOVSRDZsktMSKQZuxKCGN/dREIdTEHdRB4kQd KdlRfcEgTyRxwsYH+4QfsivJNLShnnplgv+ZadWC7bUMrOJQ5OoYXTqpiAGYy71ijmAG 8j7AE1bkQQjv5EyBNdeyPLNL+Xpeq/SS3wB3DYp0SRAlmKUcSRVLKSrEejjdIlA7UZEC qqVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=iHwk2I40SfwaU3weFFb5+gmEFCYp0781ytUemeZAP8g=; b=ou+ZlpfkiV7NgW/ukR4OtKEl3JfpKZbT7qzXpECple4KfR0HcWcuWPrc3Y5UummMZk AOTQsvxU+kF/9qYSbFGq+kgPnKoGw+LLfdYzfKW8ZsxfVU2t1rsKLfWXr+M92QOxvV++ CcT9gCd1DqiKkKrNI96vlhDjrrR1N+lkjNeeMOKdBSiD6Jn8C99aTF89WTGMAidufjxu LL2LYx8ds/Ts/+6+Anp8qRL6B2DYrDdob6it2h1mM7miNArzYqfId75VTwHVy8uSrkEE rq7yQ4YAqceDjFsvvKz53Np3rQnD9cj74Z5goh7H27V7vDFwgvO2ohRfqWVyPrTiHxqw TOag== X-Gm-Message-State: APjAAAUkd2rHil+4xJs6l5G4hnQltQJtYg0pIDn/GshMm2UeQKEHf0qx ikAhHsstvWsgcp7ZDrfmwgXBencC3U5P X-Google-Smtp-Source: APXvYqx1PBlcR6fcT32ekbGS3nK0y7JTBOV9CvtV+J0kw6XdVT5rTrJUWipfhhy9GNBrobkH6pD78O4ucDGB X-Received: by 2002:a63:184d:: with SMTP id 13mr24166pgy.132.1579802696285; Thu, 23 Jan 2020 10:04:56 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:33 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-8-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 07/10] KVM: selftests: Support multiple vCPUs in demand paging test From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Most VMs have multiple vCPUs, the concurrent execution of which has a substantial impact on demand paging performance. Add an option to create multiple vCPUs to each access disjoint regions of memory. Signed-off-by: Ben Gardon --- .../selftests/kvm/demand_paging_test.c | 255 ++++++++++++------ 1 file changed, 172 insertions(+), 83 deletions(-) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 9e2a5f7dfa140..2002032df32cc 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -24,8 +24,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 1 - /* The memory slot index demand page */ #define TEST_MEM_SLOT_INDEX 1 @@ -34,6 +32,14 @@ #define DEFAULT_GUEST_TEST_MEM_SIZE (1 << 30) /* 1G */ +#ifdef PRINT_PER_VCPU_UPDATES +#define PER_VCPU_DEBUG(...) DEBUG(__VA_ARGS__) +#else +#define PER_VCPU_DEBUG(...) +#endif + +#define MAX_VCPUS 512 + /* * Guest/Host shared variables. Ensure addr_gva2hva() and/or * sync_global_to/from_guest() are used when accessing from @@ -67,18 +73,25 @@ struct vcpu_args { struct kvm_vm *vm; }; -static struct vcpu_args vcpu_args; +static struct vcpu_args vcpu_args[MAX_VCPUS]; /* * Continuously write to the first 8 bytes of each page in the demand paging * memory region. */ -static void guest_code(void) +static void guest_code(uint32_t vcpu_id) { - uint64_t gva = vcpu_args.gva; - uint64_t pages = vcpu_args.pages; + uint64_t gva; + uint64_t pages; int i; + /* Return to signal error if vCPU args data structure is courrupt. */ + if (vcpu_args[vcpu_id].vcpu_id != vcpu_id) + return; + + gva = vcpu_args[vcpu_id].gva; + pages = vcpu_args[vcpu_id].pages; + for (i = 0; i < pages; i++) { uint64_t addr = gva + (i * guest_page_size); @@ -89,17 +102,15 @@ static void guest_code(void) GUEST_SYNC(1); } -/* Points to the test VM memory region on which we are doing demand paging */ -static void *host_test_mem; -static uint64_t host_num_pages; - static void *vcpu_worker(void *data) { int ret; - struct kvm_vm *vm = vcpu_args.vm; - int vcpu_id = vcpu_args.vcpu_id; + struct vcpu_args *args = (struct vcpu_args *)data; + struct kvm_vm *vm = args->vm; + int vcpu_id = args->vcpu_id; struct kvm_run *run; + vcpu_args_set(vm, vcpu_id, 1, vcpu_id); run = vcpu_state(vm, vcpu_id); /* Let the guest access its memory */ @@ -114,18 +125,33 @@ static void *vcpu_worker(void *data) return NULL; } -static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, - uint64_t extra_mem_pages, void *guest_code) +#define PAGE_SHIFT_4K 12 +#define PTES_PER_4K_PT 512 + +static struct kvm_vm *create_vm(enum vm_guest_mode mode, int vcpus, + uint64_t vcpu_memory_bytes) { struct kvm_vm *vm; - uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; + uint64_t pages = DEFAULT_GUEST_PHY_PAGES; + + /* Account for a few pages per-vCPU for stacks */ + pages += DEFAULT_STACK_PGS * vcpus; + + /* + * Reserve twice the ammount of memory needed to map the test region and + * the page table / stacks region, at 4k, for page tables. Do the + * calculation with 4K page size: the smallest of all archs. (e.g., 64K + * page size guest will need even less memory for page tables). + */ + pages += (2 * pages) / PTES_PER_4K_PT; + pages += ((2 * vcpus * vcpu_memory_bytes) >> PAGE_SHIFT_4K) / + PTES_PER_4K_PT; - vm = _vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + vm = _vm_create(mode, pages, O_RDWR); kvm_vm_elf_load(vm, program_invocation_name, 0, 0); #ifdef __x86_64__ vm_create_irqchip(vm); #endif - vm_vcpu_add_default(vm, vcpuid, guest_code); return vm; } @@ -240,17 +266,13 @@ static void *uffd_handler_thread_fn(void *arg) static int setup_demand_paging(struct kvm_vm *vm, pthread_t *uffd_handler_thread, int pipefd, - useconds_t uffd_delay) + useconds_t uffd_delay, + struct uffd_handler_args *uffd_args, + void *hva, uint64_t len) { int uffd; struct uffdio_api uffdio_api; struct uffdio_register uffdio_register; - struct uffd_handler_args uffd_args; - - guest_data_prototype = malloc(host_page_size); - TEST_ASSERT(guest_data_prototype, - "Failed to allocate buffer for guest data pattern"); - memset(guest_data_prototype, 0xAB, host_page_size); uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd == -1) { @@ -265,8 +287,8 @@ static int setup_demand_paging(struct kvm_vm *vm, return -1; } - uffdio_register.range.start = (uint64_t)host_test_mem; - uffdio_register.range.len = host_num_pages * host_page_size; + uffdio_register.range.start = (uint64_t)hva; + uffdio_register.range.len = len; uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1) { DEBUG("ioctl uffdio_register failed\n"); @@ -279,44 +301,39 @@ static int setup_demand_paging(struct kvm_vm *vm, return -1; } - uffd_args.uffd = uffd; - uffd_args.pipefd = pipefd; - uffd_args.delay = uffd_delay; + uffd_args->uffd = uffd; + uffd_args->pipefd = pipefd; + uffd_args->delay = uffd_delay; pthread_create(uffd_handler_thread, NULL, uffd_handler_thread_fn, - &uffd_args); + uffd_args); + + PER_VCPU_DEBUG("Created uffd thread for HVA range [%p, %p)\n", + hva, hva + len); return 0; } -#define PAGE_SHIFT_4K 12 - static void run_test(enum vm_guest_mode mode, bool use_uffd, - useconds_t uffd_delay, uint64_t guest_memory_bytes) + useconds_t uffd_delay, int vcpus, + uint64_t vcpu_memory_bytes) { - pthread_t vcpu_thread; - pthread_t uffd_handler_thread; - int pipefd[2]; + pthread_t *vcpu_threads; + pthread_t *uffd_handler_threads = NULL; + struct uffd_handler_args *uffd_args = NULL; + int *pipefds; struct kvm_vm *vm; uint64_t guest_num_pages; + int vcpu_id; int r; - /* - * We reserve page table for twice the ammount of memory we intend - * to use in the test region for demand paging. Here we do the - * calculation with 4K page size which is the smallest so the page - * number will be enough for all archs. (e.g., 64K page size guest - * will need even less memory for page tables). - */ - vm = create_vm(mode, VCPU_ID, - (2 * guest_memory_bytes) >> PAGE_SHIFT_4K, - guest_code); + vm = create_vm(mode, vcpus, vcpu_memory_bytes); guest_page_size = vm_get_page_size(vm); - TEST_ASSERT(guest_memory_bytes % guest_page_size == 0, + TEST_ASSERT(vcpu_memory_bytes % guest_page_size == 0, "Guest memory size is not guest page size aligned."); - guest_num_pages = guest_memory_bytes / guest_page_size; + guest_num_pages = (vcpus * vcpu_memory_bytes) / guest_page_size; #ifdef __s390x__ /* Round up to multiple of 1M (segment size) */ @@ -328,13 +345,13 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, */ TEST_ASSERT(guest_num_pages < vm_get_max_gfn(vm), "Requested more guest memory than address space allows.\n" - " guest pages: %lx max gfn: %lx\n", - guest_num_pages, vm_get_max_gfn(vm)); + " guest pages: %lx max gfn: %lx vcpus: %d wss: %lx]\n", + guest_num_pages, vm_get_max_gfn(vm), vcpus, + vcpu_memory_bytes); host_page_size = getpagesize(); - TEST_ASSERT(guest_memory_bytes % host_page_size == 0, + TEST_ASSERT(vcpu_memory_bytes % host_page_size == 0, "Guest memory size is not host page size aligned."); - host_num_pages = guest_memory_bytes / host_page_size; guest_test_phys_mem = (vm_get_max_gfn(vm) - guest_num_pages) * guest_page_size; @@ -359,55 +376,116 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages * guest_page_size, 0); - /* Cache the HVA pointer of the region */ - host_test_mem = addr_gpa2hva(vm, (vm_paddr_t)guest_test_phys_mem); +#ifdef __aarch64__ + ucall_init(vm, NULL); +#endif + + guest_data_prototype = malloc(host_page_size); + TEST_ASSERT(guest_data_prototype, + "Failed to allocate buffer for guest data pattern"); + memset(guest_data_prototype, 0xAB, host_page_size); + + vcpu_threads = malloc(vcpus * sizeof(*vcpu_threads)); + TEST_ASSERT(vcpu_threads, "Memory allocation failed"); if (use_uffd) { - /* Set up user fault fd to handle demand paging requests. */ - r = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK); - TEST_ASSERT(!r, "Failed to set up pipefd"); + uffd_handler_threads = + malloc(vcpus * sizeof(*uffd_handler_threads)); + TEST_ASSERT(uffd_handler_threads, "Memory allocation failed"); - r = setup_demand_paging(vm, &uffd_handler_thread, pipefd[0], - uffd_delay); - if (r < 0) - exit(-r); + uffd_args = malloc(vcpus * sizeof(*uffd_args)); + TEST_ASSERT(uffd_args, "Memory allocation failed"); + + pipefds = malloc(sizeof(int) * vcpus * 2); + TEST_ASSERT(pipefds, "Unable to allocate memory for pipefd"); } + for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { + vm_paddr_t vcpu_gpa; + void *vcpu_hva; + + vm_vcpu_add_default(vm, vcpu_id, guest_code); + + vcpu_gpa = guest_test_phys_mem + (vcpu_id * vcpu_memory_bytes); + PER_VCPU_DEBUG("Added VCPU %d with test mem gpa [%lx, %lx)\n", + vcpu_id, vcpu_gpa, vcpu_gpa + vcpu_memory_bytes); + + /* Cache the HVA pointer of the region */ + vcpu_hva = addr_gpa2hva(vm, vcpu_gpa); + + if (use_uffd) { + /* + * Set up user fault fd to handle demand paging + * requests. + */ + r = pipe2(&pipefds[vcpu_id * 2], + O_CLOEXEC | O_NONBLOCK); + TEST_ASSERT(!r, "Failed to set up pipefd"); + + r = setup_demand_paging(vm, + &uffd_handler_threads[vcpu_id], + pipefds[vcpu_id * 2], + uffd_delay, &uffd_args[vcpu_id], + vcpu_hva, vcpu_memory_bytes); + if (r < 0) + exit(-r); + } + #ifdef __x86_64__ - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); -#endif -#ifdef __aarch64__ - ucall_init(vm, NULL); + vcpu_set_cpuid(vm, vcpu_id, kvm_get_supported_cpuid()); #endif + vcpu_args[vcpu_id].vm = vm; + vcpu_args[vcpu_id].vcpu_id = vcpu_id; + vcpu_args[vcpu_id].gva = guest_test_virt_mem + + (vcpu_id * vcpu_memory_bytes); + vcpu_args[vcpu_id].pages = vcpu_memory_bytes / guest_page_size; + } + /* Export the shared variables to the guest */ sync_global_to_guest(vm, host_page_size); sync_global_to_guest(vm, guest_page_size); - - vcpu_args.vm = vm; - vcpu_args.vcpu_id = VCPU_ID; - vcpu_args.gva = guest_test_virt_mem; - vcpu_args.pages = guest_num_pages; sync_global_to_guest(vm, vcpu_args); - pthread_create(&vcpu_thread, NULL, vcpu_worker, &vcpu_args); - /* Wait for the vcpu thread to quit */ - pthread_join(vcpu_thread, NULL); + DEBUG("Finished creating vCPUs and starting uffd threads\n"); + + for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { + pthread_create(&vcpu_threads[vcpu_id], NULL, vcpu_worker, + &vcpu_args[vcpu_id]); + } + + DEBUG("Started all vCPUs\n"); + + /* Wait for the vcpu threads to quit */ + for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { + pthread_join(vcpu_threads[vcpu_id], NULL); + PER_VCPU_DEBUG("Joined thread for vCPU %d\n", vcpu_id); + } + + DEBUG("All vCPU threads joined\n"); if (use_uffd) { char c; - /* Tell the user fault fd handler thread to quit */ - r = write(pipefd[1], &c, 1); - TEST_ASSERT(r == 1, "Unable to write to pipefd"); + /* Tell the user fault fd handler threads to quit */ + for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { + r = write(pipefds[vcpu_id * 2 + 1], &c, 1); + TEST_ASSERT(r == 1, "Unable to write to pipefd"); - pthread_join(uffd_handler_thread, NULL); + pthread_join(uffd_handler_threads[vcpu_id], NULL); + } } ucall_uninit(vm); kvm_vm_free(vm); free(guest_data_prototype); + free(vcpu_threads); + if (use_uffd) { + free(uffd_handler_threads); + free(uffd_args); + free(pipefds); + } } struct vm_guest_mode_params { @@ -428,7 +506,7 @@ static void help(char *name) puts(""); printf("usage: %s [-h] [-m mode] [-u] [-d uffd_delay_usec]\n" - " [-b memory]\n", name); + " [-b memory] [-v vcpus]\n", name); printf(" -m: specify the guest mode ID to test\n" " (default: test all supported modes)\n" " This option may be used multiple times.\n" @@ -443,7 +521,9 @@ static void help(char *name) " FD handler to simulate demand paging\n" " overheads. Ignored without -u.\n"); printf(" -b: specify the size of the memory region which should be\n" - " demand paged. e.g. 10M or 3G. Default: 1G\n"); + " demand paged by each vCPU. e.g. 10M or 3G.\n" + " Default: 1G\n"); + printf(" -v: specify the number of vCPUs to run.\n"); puts(""); exit(0); } @@ -451,7 +531,8 @@ static void help(char *name) int main(int argc, char *argv[]) { bool mode_selected = false; - uint64_t guest_memory_bytes = DEFAULT_GUEST_TEST_MEM_SIZE; + uint64_t vcpu_memory_bytes = DEFAULT_GUEST_TEST_MEM_SIZE; + int vcpus = 1; unsigned int mode; int opt, i; bool use_uffd = false; @@ -479,7 +560,7 @@ int main(int argc, char *argv[]) vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); #endif - while ((opt = getopt(argc, argv, "hm:ud:b:")) != -1) { + while ((opt = getopt(argc, argv, "hm:ud:b:v:")) != -1) { switch (opt) { case 'm': if (!mode_selected) { @@ -501,7 +582,15 @@ int main(int argc, char *argv[]) "A negative UFFD delay is not supported."); break; case 'b': - guest_memory_bytes = parse_size(optarg); + vcpu_memory_bytes = parse_size(optarg); + break; + case 'v': + vcpus = atoi(optarg); + TEST_ASSERT(vcpus > 0, + "Must have a positive number of vCPUs"); + TEST_ASSERT(vcpus <= MAX_VCPUS, + "This test does not currently support\n" + "more than %d vCPUs.", MAX_VCPUS); break; case 'h': default: @@ -516,7 +605,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(vm_guest_mode_params[i].supported, "Guest mode ID %d (%s) not supported.", i, vm_guest_mode_string(i)); - run_test(i, use_uffd, uffd_delay, guest_memory_bytes); + run_test(i, use_uffd, uffd_delay, vcpus, vcpu_memory_bytes); } return 0; From patchwork Thu Jan 23 18:04:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348907 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 78F0A1398 for ; Thu, 23 Jan 2020 18:05:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4690522522 for ; Thu, 23 Jan 2020 18:05:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="D3gvjm8H" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729260AbgAWSFQ (ORCPT ); Thu, 23 Jan 2020 13:05:16 -0500 Received: from mail-pg1-f201.google.com ([209.85.215.201]:43879 "EHLO mail-pg1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729273AbgAWSE7 (ORCPT ); Thu, 23 Jan 2020 13:04:59 -0500 Received: by mail-pg1-f201.google.com with SMTP id d9so2231508pgd.10 for ; Thu, 23 Jan 2020 10:04:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=zQsk+O6KeZ1NWUkCto7Wkzwr5mCAi8+GMe3pWZCtfx8=; b=D3gvjm8Hkjs/fWfSh6hd6ba41HjLwDycYiddKOlsYEF6zj+FGkMXQJQc0JmNr6VTUz NGK3/iIJEQyCffEaFO+BW+BxznvvpQs7Lu2JWgirdMxaptDvO+csVJpsebDPQNV6BAqC a6SLSg9LMxrJlf+nW4uQ4WC2+1Pu1W0R0tgrhvvVSpRmOuL7QywtaevwMvMu4mHojDm0 OCGNRT1lVxP2RXK2JXBDucXxizNqM3wiWr5de2ivVUfxLZsqolidtIFuV2vY/PB1bK9z 73vedQ2wKGzIS770ADhiR6jVpPx/ERuhasYk/QkZm9ZkrPBGJifPNf57ZHs+5ihmGESF 6XpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=zQsk+O6KeZ1NWUkCto7Wkzwr5mCAi8+GMe3pWZCtfx8=; b=FPucLJIXe3BwMGeUnnLBmETAspaVsjkM4SYAu9nityRiFizUQ1TzPonqN6pD+wWx+4 HL8A2kntXp6XTZ/8Tzo8lNNa3V9NuipH1Mvin1r76w5f2xQmxALJeoT+/G6T0oIo6M7F ktSmuU7lc+WG5JMmoxK6djUkbUjs1FCRVQyAREi5Uwst6DxwzCcVpRjLiHGDlxoqbbqq yENsJgf75LQ2HaZILSct3EyN3J8x7YDCzZ0LK5LxQbzjkGyfdq+uUWhHYXi9P+hY3v7k 7KAseKoZkYzvzbpPkcH6/fZZKEEfbB42FFQ7CQzejYRDGyDz/SAueybuNWTBjV/WBD1H XqdQ== X-Gm-Message-State: APjAAAVMCIXG2lRqHnLa63f69Db9hozl5+tioUGhFS0tU8XFZn2Y7ziF I6kXQz8+KDEngbgLuAvjHL8r9hj9wUtL X-Google-Smtp-Source: APXvYqybxeibSo2GtbUigxYXRUWl5nVrUrZ2sWGnT63r8bM/diDvzZiwn87GrhTSWXC/GK8UOe4Z/8U1Lpgn X-Received: by 2002:a63:6d0e:: with SMTP id i14mr34255pgc.12.1579802698334; Thu, 23 Jan 2020 10:04:58 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:34 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-9-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 08/10] KVM: selftests: Time guest demand paging From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In order to quantify demand paging performance, time guest execution during demand paging. Signed-off-by: Ben Gardon --- .../selftests/kvm/demand_paging_test.c | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 2002032df32cc..0dc5d04718678 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -32,6 +32,12 @@ #define DEFAULT_GUEST_TEST_MEM_SIZE (1 << 30) /* 1G */ +#ifdef PRINT_PER_PAGE_UPDATES +#define PER_PAGE_DEBUG(...) DEBUG(__VA_ARGS__) +#else +#define PER_PAGE_DEBUG(...) +#endif + #ifdef PRINT_PER_VCPU_UPDATES #define PER_VCPU_DEBUG(...) DEBUG(__VA_ARGS__) #else @@ -64,6 +70,26 @@ static uint64_t guest_test_phys_mem; */ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; +int64_t to_ns(struct timespec ts) +{ + return (int64_t)ts.tv_nsec + 1000000000LL * (int64_t)ts.tv_sec; +} + +struct timespec diff(struct timespec start, struct timespec end) +{ + struct timespec temp; + + if ((end.tv_nsec-start.tv_nsec) < 0) { + temp.tv_sec = end.tv_sec - start.tv_sec - 1; + temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec - start.tv_sec; + temp.tv_nsec = end.tv_nsec - start.tv_nsec; + } + + return temp; +} + struct vcpu_args { uint64_t gva; uint64_t pages; @@ -109,10 +135,14 @@ static void *vcpu_worker(void *data) struct kvm_vm *vm = args->vm; int vcpu_id = args->vcpu_id; struct kvm_run *run; + struct timespec start; + struct timespec end; vcpu_args_set(vm, vcpu_id, 1, vcpu_id); run = vcpu_state(vm, vcpu_id); + clock_gettime(CLOCK_MONOTONIC, &start); + /* Let the guest access its memory */ ret = _vcpu_run(vm, vcpu_id); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); @@ -122,6 +152,11 @@ static void *vcpu_worker(void *data) exit_reason_str(run->exit_reason)); } + clock_gettime(CLOCK_MONOTONIC, &end); + PER_VCPU_DEBUG("vCPU %d execution time: %lld.%.9lds\n", vcpu_id, + (long long)(diff(start, end).tv_sec), + diff(start, end).tv_nsec); + return NULL; } @@ -158,6 +193,8 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, int vcpus, static int handle_uffd_page_request(int uffd, uint64_t addr) { pid_t tid; + struct timespec start; + struct timespec end; struct uffdio_copy copy; int r; @@ -168,6 +205,8 @@ static int handle_uffd_page_request(int uffd, uint64_t addr) copy.len = host_page_size; copy.mode = 0; + clock_gettime(CLOCK_MONOTONIC, &start); + r = ioctl(uffd, UFFDIO_COPY, ©); if (r == -1) { DEBUG("Failed Paged in 0x%lx from thread %d with errno: %d\n", @@ -175,6 +214,13 @@ static int handle_uffd_page_request(int uffd, uint64_t addr) return r; } + clock_gettime(CLOCK_MONOTONIC, &end); + + PER_PAGE_DEBUG("UFFDIO_COPY %d \t%lld ns\n", tid, + (long long)to_ns(diff(start, end))); + PER_PAGE_DEBUG("Paged in %ld bytes at 0x%lx from thread %d\n", + host_page_size, addr, tid); + return 0; } @@ -193,7 +239,10 @@ static void *uffd_handler_thread_fn(void *arg) int pipefd = uffd_args->pipefd; useconds_t delay = uffd_args->delay; int64_t pages = 0; + struct timespec start; + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &start); while (!quit_uffd_thread) { struct uffd_msg msg; struct pollfd pollfd[2]; @@ -261,6 +310,13 @@ static void *uffd_handler_thread_fn(void *arg) pages++; } + clock_gettime(CLOCK_MONOTONIC, &end); + PER_VCPU_DEBUG("userfaulted %ld pages over %lld.%.9lds. (%f/sec)\n", + pages, (long long)(diff(start, end).tv_sec), + diff(start, end).tv_nsec, pages / + ((double)diff(start, end).tv_sec + + (double)diff(start, end).tv_nsec / 100000000.0)); + return NULL; } @@ -325,6 +381,8 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, uint64_t guest_num_pages; int vcpu_id; int r; + struct timespec start; + struct timespec end; vm = create_vm(mode, vcpus, vcpu_memory_bytes); @@ -449,6 +507,8 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, DEBUG("Finished creating vCPUs and starting uffd threads\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { pthread_create(&vcpu_threads[vcpu_id], NULL, vcpu_worker, &vcpu_args[vcpu_id]); @@ -464,6 +524,8 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, DEBUG("All vCPU threads joined\n"); + clock_gettime(CLOCK_MONOTONIC, &end); + if (use_uffd) { char c; @@ -476,6 +538,12 @@ static void run_test(enum vm_guest_mode mode, bool use_uffd, } } + DEBUG("Total guest execution time: %lld.%.9lds\n", + (long long)(diff(start, end).tv_sec), diff(start, end).tv_nsec); + DEBUG("Overall demand paging rate: %f pgs/sec\n", + guest_num_pages / ((double)diff(start, end).tv_sec + + (double)diff(start, end).tv_nsec / 100000000.0)); + ucall_uninit(vm); kvm_vm_free(vm); From patchwork Thu Jan 23 18:04:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348897 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6C9DB1398 for ; Thu, 23 Jan 2020 18:05:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4685220718 for ; Thu, 23 Jan 2020 18:05:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="n+Pcpr5w" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729324AbgAWSFD (ORCPT ); Thu, 23 Jan 2020 13:05:03 -0500 Received: from mail-qk1-f201.google.com ([209.85.222.201]:34790 "EHLO mail-qk1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729332AbgAWSFC (ORCPT ); Thu, 23 Jan 2020 13:05:02 -0500 Received: by mail-qk1-f201.google.com with SMTP id u10so2227562qkk.1 for ; Thu, 23 Jan 2020 10:05:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=UdYBz3AD49871PUkNPj4Uebf8Il0FeRd7J00v5oi04U=; b=n+Pcpr5wOrgmU2c65Sgk80FsAlBLVRmkLo0XbwUrvO9lDOhlDLvWFp2fHgsz+gjvvb 9lx4qvrnQ8p0/CkVzkNSU4oXoXO4CMa9BtSrE3crfGshR1UTDh0RwJK+DOwDma3gFbB8 F2dNcvr12Zzft48S7piu2oUTIsarWn5vyptyDl6Z6M0aEf95Ms8tdNZBCUyhPXA4tfav D2CILGxOu/uL0cyVXZztwjdsLpDRa641IIbvddCDN9ZqBeb5/T0uxvaWjoTO+YiCRWmn e+kv/mrOHQAq2kqUGToqJpMknvIq8Zd00f9/JSuXKO3dmmwH4r909as/b2CLtB0pcfrn Sxow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=UdYBz3AD49871PUkNPj4Uebf8Il0FeRd7J00v5oi04U=; b=Z40P4/+XzYNRqLDs8Yiqddo2mCBCR1o2erVmesBvT4vqRMxImlDvVB5EJYNShCp8Dh UfeDhVR9ZraSpV/m91pbvfOQGV2PG2CALYKjMS+iskzX03a2BVYVa7GuwU/2XRRQJmGJ QcKkXSvrBSnIwADIN5IFq33zLPkgbli+nxfVATi22tzctM6ZCarZB0wfZDIO/bUTSs70 NmwUnSBusqUVDNvoVOvbMk7gTeLzFNCBwFkr/mNdGo9iEWL0q/nw8oJ9R+PNPAWJVO1h y7Zl1oSTyoI2c7QJ0kMHOFGrB7+rkOFxQhJQiXwB477ASeNyLHOz1uA9q9en/D9y/gnw OG+A== X-Gm-Message-State: APjAAAVIYYtJC4hmSPYhFKTtqYCZ0SWB+nBv0IDoKSEI2R/RXb6/3kYM 0ID8p6xOyrS0sHSaoPY+3jNO1tqK2vFT X-Google-Smtp-Source: APXvYqw/mRdsaZ41fljNpl0GCv0XtJYfDahhtiR1QNY/cSbWhanCWfktv1CfZhgA95ua8wi2fyuKZN0sD5DP X-Received: by 2002:a37:a881:: with SMTP id r123mr5611982qke.275.1579802700645; Thu, 23 Jan 2020 10:05:00 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:35 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-10-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 09/10] KVM: selftests: Stop memslot creation in KVM internal memslot region From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org KVM creates internal memslots covering the region between 3G and 4G in the guest physical address space, when the first vCPU is created. Mapping this region before creation of the first vCPU causes vCPU creation to fail. Prohibit tests from creating such a memslot and fail with a helpful warning when they try to. Signed-off-by: Ben Gardon --- tools/testing/selftests/kvm/lib/kvm_util.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 41cf45416060f..5b971c04f1643 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -113,6 +113,8 @@ const char * const vm_guest_mode_string[] = { _Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES, "Missing new mode strings?"); +#define KVM_INTERNAL_MEMSLOTS_START_PADDR (3UL << 30) +#define KVM_INTERNAL_MEMSLOTS_END_PADDR (4UL << 30) /* * VM Create * @@ -593,6 +595,20 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, " vm->max_gfn: 0x%lx vm->page_size: 0x%x", guest_paddr, npages, vm->max_gfn, vm->page_size); + /* + * Check that this region does not overlap with KVM internal memslots + * which are created when the first vCPU is created. + */ + TEST_ASSERT(guest_paddr >= KVM_INTERNAL_MEMSLOTS_END_PADDR || + guest_paddr + npages < KVM_INTERNAL_MEMSLOTS_START_PADDR, + "Memslot overlapps with region mapped by internal KVM\n" + "memslots:\n" + " Requested paddr range: [0x%lx, 0x%lx)\n" + " KVM internal memslot range: [0x%lx, 0x%lx)\n", + guest_paddr, guest_paddr + npages, + KVM_INTERNAL_MEMSLOTS_START_PADDR, + KVM_INTERNAL_MEMSLOTS_END_PADDR); + /* * Confirm a mem region with an overlapping address doesn't * already exist. From patchwork Thu Jan 23 18:04:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 11348899 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 733BE17EA for ; Thu, 23 Jan 2020 18:05:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4D45D24676 for ; Thu, 23 Jan 2020 18:05:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="t1FZb1fR" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729342AbgAWSFE (ORCPT ); Thu, 23 Jan 2020 13:05:04 -0500 Received: from mail-vk1-f201.google.com ([209.85.221.201]:54951 "EHLO mail-vk1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729174AbgAWSFE (ORCPT ); Thu, 23 Jan 2020 13:05:04 -0500 Received: by mail-vk1-f201.google.com with SMTP id b68so1638993vkh.21 for ; Thu, 23 Jan 2020 10:05:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=IgY/A9lI8I0CLEHHbAfWjUttLZ/uMo5ZHLdhVrD7cM0=; b=t1FZb1fRlGn6sS3KiIywlF3SWXZSC72vi3l8yghm1rqJkGVi2ppxi2bhsdIjvKvpRo mtWcSzCLmK9615UMLkHpgpsmNt5T84sa65TDnvwPSa9ngmlIgsKEROMy5IpuHkvfb8N7 bCjmso/kge2qOgVpMLvorx9kPfR6WTEwTFQ8ai/lbr8rUqpqvjYUnTSXQVQ71Drj5GJK RECoQDzgsJUdJwfKMT9nw/Gcan8lFs4CF7xzacTYrzpmO7QXUtJ0wOvCMIvFcmKTG6ds S0JhBqH4xNZ9AdbRXFzXIauav8aPfCE3jZORlJTJUBw0/YItGp4DWvk1Kp8cXJfqmuFI 13ag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=IgY/A9lI8I0CLEHHbAfWjUttLZ/uMo5ZHLdhVrD7cM0=; b=i3MosjJUkxnow+BOtw5C3o9l6OAEYBR1451LkNUinggIKorqYZOGm26qJ7vh3VT+ag frbaBOpwqAw6hgjbDePBu4ZUWmGdNzDX50W0rjE2C1H5l2bLY5AJqisrQ/JlZMwXGX5/ I0fJypKAEffvvGxxOMKyr2kHPqfRQw/o534SpiMI0f9EERb3RtDaZ9+0VYle8sseNS5o PKcaTehzU9mTgl3a8/upvJtPMsaD/H0o1WtUPgxjxN8rb1X7Mk7HbQLmcK4ZkqjyQ1QT edmQU2VPd8sIuyZKNdL3GF6QB4NqZJ5ExREdxyJ57/+LDzj7HOOgvMlXGXqYmc5GFksr yHkw== X-Gm-Message-State: APjAAAXw6I/Kz/PZH1U78fA816rHVfKUVv0r8w/tC3mYOzfx1+z2kIEf 6QxdrD/zcfmxmsB3QEKXFWSoa1/0S752 X-Google-Smtp-Source: APXvYqxXhcIT67XYPNyAtt7N43so6bSsWc4OopxKKv8aAXTznOXWZ7A8M1Li4/dumBajBFClbx8iUmgtV+QX X-Received: by 2002:a67:e44b:: with SMTP id n11mr7496089vsm.115.1579802702764; Thu, 23 Jan 2020 10:05:02 -0800 (PST) Date: Thu, 23 Jan 2020 10:04:36 -0800 In-Reply-To: <20200123180436.99487-1-bgardon@google.com> Message-Id: <20200123180436.99487-11-bgardon@google.com> Mime-Version: 1.0 References: <20200123180436.99487-1-bgardon@google.com> X-Mailer: git-send-email 2.25.0.341.g760bfbb309-goog Subject: [PATCH v4 10/10] KVM: selftests: Move memslot 0 above KVM internal memslots From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Cannon Matthews , Peter Xu , Andrew Jones , Peter Shier , Oliver Upton , Ben Gardon Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org KVM creates internal memslots between 3 and 4 GiB paddrs on the first vCPU creation. If memslot 0 is large enough it collides with these memslots an causes vCPU creation to fail. Instead of creating memslot 0 at paddr 0, start it 4G into the guest physical address space. Signed-off-by: Ben Gardon --- tools/testing/selftests/kvm/lib/kvm_util.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 5b971c04f1643..427c88d32e988 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -130,9 +130,11 @@ _Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES, * * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). * When phy_pages is non-zero, a memory region of phy_pages physical pages - * is created and mapped starting at guest physical address 0. The file - * descriptor to control the created VM is created with the permissions - * given by perm (e.g. O_RDWR). + * is created, starting at 4G into the guest physical address space to avoid + * KVM internal memslots which map the region between 3G and 4G. If tests need + * to use the physical region between 0 and 3G, they can allocate another + * memslot for that region. The file descriptor to control the created VM is + * created with the permissions given by perm (e.g. O_RDWR). */ struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) { @@ -231,7 +233,8 @@ struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) vm->vpages_mapped = sparsebit_alloc(); if (phy_pages != 0) vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - 0, 0, phy_pages, 0); + KVM_INTERNAL_MEMSLOTS_END_PADDR, + 0, phy_pages, 0); return vm; }