From patchwork Tue Jan 31 18:18:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 50998 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp57770wrn; Tue, 31 Jan 2023 10:21:13 -0800 (PST) X-Google-Smtp-Source: AK7set+KYtDx5GXAIbPmQQnIreVf3ldDvJFhFtWXTj0/sWNMJGiq76blU3rD9shUi9uaIDsVaFCx X-Received: by 2002:a05:6a20:840b:b0:bc:fb05:3c3f with SMTP id c11-20020a056a20840b00b000bcfb053c3fmr13080104pzd.43.1675189273042; Tue, 31 Jan 2023 10:21:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675189273; cv=none; d=google.com; s=arc-20160816; b=rUb4jBk+0/LNgHjVCHvG+tqgJhehlnHpoDY3Ytvib/FZNB3W3dUbZzsGl6JyzEBIH+ hzL5FNogJ/nZgv0b+R/EaKZbVXMOw8wGqRNRPX78z97lfH3V1fxt2R3tB1iMFymJlK8e Rh5A1ypxj0NzyiapO09k5thrR5ycXiFvxT5xtO5sR2sBqP3aRHxKon5xtQztDXwaWGi1 kkrxjlWkHdprb9avOJA3QFt11zuIbVsullhgPHDbpLVAH76Vo4xHvK9cMKZF47MZ6MT/ EQtd8MG2Ejc/a4bG2haD/sOWsOggYO1io23BFWXbJR3l0rzwBebufZEXuQTSqw9tR7ai lw7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=pgKsZ0Bh25hFzhxXEJXQv/JsnUoHDVhjIiyIEzL41Jo=; b=Mc4Rr4GDndEWDS92rYgIlo47LOurUDzXSfrH0tEy3Vwi/ag9+lO9fYTub6Gq3I95qp YVvMuNZxbeIvrTiCIgqVIcjLuzobKx6tmMe2fhDlX4V5IbB46VFV54cVN4CbVS10Jp7M ejmIMJVLXDYZ3NKsjsLPzb62Lg2f7OxJ+55eg4eX+nRMsk7i1gBIIb94mmRV5o+ErtIO WqF0K4sK0k++S8cvRmUxPkWv7V4Y011SQTXkneGihvzHnI5Go5dFYONOpdTzcrZF2+92 NGyZYs5WgiJRyDM2QbGsj4eZZsjP49+U5Ay9PDMUmHp24LEkqWkzHwN8zI25aGPMCHYn 6E1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=Z2g50fe+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j73-20020a636e4c000000b004ee642e01besi1589588pgc.528.2023.01.31.10.21.00; Tue, 31 Jan 2023 10:21:13 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=Z2g50fe+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229488AbjAaSS3 (ORCPT + 99 others); Tue, 31 Jan 2023 13:18:29 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230202AbjAaSS0 (ORCPT ); Tue, 31 Jan 2023 13:18:26 -0500 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BAF612BF23 for ; Tue, 31 Jan 2023 10:18:25 -0800 (PST) Received: by mail-pg1-x54a.google.com with SMTP id az7-20020a056a02004700b004ec117e57cfso2264112pgb.5 for ; Tue, 31 Jan 2023 10:18:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=pgKsZ0Bh25hFzhxXEJXQv/JsnUoHDVhjIiyIEzL41Jo=; b=Z2g50fe+CPZFO8tMIw/E1VLxD/KIRZsbBWBSJkEePWsRp8qIJl6CfO9RIXcHppw0xO L7tmqW9D1Et7+msz1GbU6hW2yP+8u0uN8lKgY1QkAl5qtAP+jtZ/lWnRpsXOYG/HbrUf EQPAeJwJxzrJNVgjd723NayafHeUco/ZKhLANbbCmL/+x94unnQg4DRrIySQQ2c/dcmn LT6P0NTkr5KKRrZIbsKX2rRAZf/ctRYzibrF7Pi0nbIh8yYj8PcbV1K6B0mdd3miU81K WUaXRmc/6Su7QKYv9b7bXRuS7EJZ6hO/aF0Ft2R4uyzrslddQSLFkwnVjap/Dp1a/j5J sb8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=pgKsZ0Bh25hFzhxXEJXQv/JsnUoHDVhjIiyIEzL41Jo=; b=YKgkuildD3L24PzQW7iujOjChMRIXhrSYVcDQXoGRupkjOWB7EKiOwg+jTM2UTTzqP iW8C0MmvbRPeMCEHnEup2ri//bDyjs2UAT/dP33O+Ufxgk5ZY8EF1qwrlLyiAvKH+wA6 zPHBM/Ehm0d3045o8g7BQzdvm62shzrrxzGMpSYF40CrU0jrB0JyCxv/u5FHux9b6Lpu /pddh3q8lKEhTnRzPCDDxCu4dcmWx1QqPUaBAJwAvcsFh8FbnFepviv5pDm/PEWzZXx8 jXhvC+09vMdjisDkdb70Z0MMDvxPSos5ado6mmHzngmiOLmv5+FC7m7Jfc/ya3rt9Czs idYQ== X-Gm-Message-State: AFqh2kpgMCNzEqQrs8pfqTbg8KfHH75vxpeVSstswhDxULRQf25R4u35 To1Cf7tkwC52mqszIpWUfY0Lu0Cs5eGINKpJpqOAzRHM1nFS/DJ2Y6p15fCRe7+kGZBEkj3d6XT lHKIqvtaIuK06lFBFaEvjSPM4/gLVmcy+/3IDzQoV2q3APPIwnj23/3yeRpUF0PA+Zxi0p0tA X-Received: from sweer.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:e45]) (user=bgardon job=sendgmr) by 2002:a62:1989:0:b0:58d:ae61:c14b with SMTP id 131-20020a621989000000b0058dae61c14bmr6820820pfz.51.1675189105091; Tue, 31 Jan 2023 10:18:25 -0800 (PST) Date: Tue, 31 Jan 2023 18:18:19 +0000 In-Reply-To: <20230131181820.179033-1-bgardon@google.com> Mime-Version: 1.0 References: <20230131181820.179033-1-bgardon@google.com> X-Mailer: git-send-email 2.39.1.456.gfc5497dd1b-goog Message-ID: <20230131181820.179033-2-bgardon@google.com> Subject: [PATCH V5 1/2] selftests: KVM: Move dirty logging functions to memstress.(c|h) From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: Paolo Bonzini , Peter Xu , Sean Christopherson , David Matlack , Vipin Sharma , Ricardo Koller , Ben Gardon X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756563266959074510?= X-GMAIL-MSGID: =?utf-8?q?1756563266959074510?= Move some helper functions from dirty_log_perf_test.c to the memstress library so that they can be used in a future commit which tests page splitting during dirty logging. Reviewed-by: Vipin Sharma Signed-off-by: Ben Gardon --- .../selftests/kvm/dirty_log_perf_test.c | 84 ++----------------- .../testing/selftests/kvm/include/memstress.h | 8 ++ tools/testing/selftests/kvm/lib/memstress.c | 72 ++++++++++++++++ 3 files changed, 87 insertions(+), 77 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index e9d6d1aecf89c..416719e205183 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -136,77 +136,6 @@ struct test_params { bool random_access; }; -static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable) -{ - int i; - - for (i = 0; i < slots; i++) { - int slot = MEMSTRESS_MEM_SLOT_INDEX + i; - int flags = enable ? KVM_MEM_LOG_DIRTY_PAGES : 0; - - vm_mem_region_set_flags(vm, slot, flags); - } -} - -static inline void enable_dirty_logging(struct kvm_vm *vm, int slots) -{ - toggle_dirty_logging(vm, slots, true); -} - -static inline void disable_dirty_logging(struct kvm_vm *vm, int slots) -{ - toggle_dirty_logging(vm, slots, false); -} - -static void get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots) -{ - int i; - - for (i = 0; i < slots; i++) { - int slot = MEMSTRESS_MEM_SLOT_INDEX + i; - - kvm_vm_get_dirty_log(vm, slot, bitmaps[i]); - } -} - -static void clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], - int slots, uint64_t pages_per_slot) -{ - int i; - - for (i = 0; i < slots; i++) { - int slot = MEMSTRESS_MEM_SLOT_INDEX + i; - - kvm_vm_clear_dirty_log(vm, slot, bitmaps[i], 0, pages_per_slot); - } -} - -static unsigned long **alloc_bitmaps(int slots, uint64_t pages_per_slot) -{ - unsigned long **bitmaps; - int i; - - bitmaps = malloc(slots * sizeof(bitmaps[0])); - TEST_ASSERT(bitmaps, "Failed to allocate bitmaps array."); - - for (i = 0; i < slots; i++) { - bitmaps[i] = bitmap_zalloc(pages_per_slot); - TEST_ASSERT(bitmaps[i], "Failed to allocate slot bitmap."); - } - - return bitmaps; -} - -static void free_bitmaps(unsigned long *bitmaps[], int slots) -{ - int i; - - for (i = 0; i < slots; i++) - free(bitmaps[i]); - - free(bitmaps); -} - static void run_test(enum vm_guest_mode mode, void *arg) { struct test_params *p = arg; @@ -236,7 +165,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) host_num_pages = vm_num_host_pages(mode, guest_num_pages); pages_per_slot = host_num_pages / p->slots; - bitmaps = alloc_bitmaps(p->slots, pages_per_slot); + bitmaps = memstress_alloc_bitmaps(p->slots, pages_per_slot); if (dirty_log_manual_caps) vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, @@ -277,7 +206,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) /* Enable dirty logging */ clock_gettime(CLOCK_MONOTONIC, &start); - enable_dirty_logging(vm, p->slots); + memstress_enable_dirty_logging(vm, p->slots); ts_diff = timespec_elapsed(start); pr_info("Enabling dirty logging time: %ld.%.9lds\n\n", ts_diff.tv_sec, ts_diff.tv_nsec); @@ -306,7 +235,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) iteration, ts_diff.tv_sec, ts_diff.tv_nsec); clock_gettime(CLOCK_MONOTONIC, &start); - get_dirty_log(vm, bitmaps, p->slots); + memstress_get_dirty_log(vm, bitmaps, p->slots); ts_diff = timespec_elapsed(start); get_dirty_log_total = timespec_add(get_dirty_log_total, ts_diff); @@ -315,7 +244,8 @@ static void run_test(enum vm_guest_mode mode, void *arg) if (dirty_log_manual_caps) { clock_gettime(CLOCK_MONOTONIC, &start); - clear_dirty_log(vm, bitmaps, p->slots, pages_per_slot); + memstress_clear_dirty_log(vm, bitmaps, p->slots, + pages_per_slot); ts_diff = timespec_elapsed(start); clear_dirty_log_total = timespec_add(clear_dirty_log_total, ts_diff); @@ -334,7 +264,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) /* Disable dirty logging */ clock_gettime(CLOCK_MONOTONIC, &start); - disable_dirty_logging(vm, p->slots); + memstress_disable_dirty_logging(vm, p->slots); ts_diff = timespec_elapsed(start); pr_info("Disabling dirty logging time: %ld.%.9lds\n", ts_diff.tv_sec, ts_diff.tv_nsec); @@ -359,7 +289,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) clear_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec); } - free_bitmaps(bitmaps, p->slots); + memstress_free_bitmaps(bitmaps, p->slots); arch_cleanup_vm(vm); memstress_destroy_vm(vm); } diff --git a/tools/testing/selftests/kvm/include/memstress.h b/tools/testing/selftests/kvm/include/memstress.h index 72e3e358ef7bd..ce4e603050eaa 100644 --- a/tools/testing/selftests/kvm/include/memstress.h +++ b/tools/testing/selftests/kvm/include/memstress.h @@ -72,4 +72,12 @@ void memstress_guest_code(uint32_t vcpu_id); uint64_t memstress_nested_pages(int nr_vcpus); void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[]); +void memstress_enable_dirty_logging(struct kvm_vm *vm, int slots); +void memstress_disable_dirty_logging(struct kvm_vm *vm, int slots); +void memstress_get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots); +void memstress_clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], + int slots, uint64_t pages_per_slot); +unsigned long **memstress_alloc_bitmaps(int slots, uint64_t pages_per_slot); +void memstress_free_bitmaps(unsigned long *bitmaps[], int slots); + #endif /* SELFTEST_KVM_MEMSTRESS_H */ diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c index 5f1d3173c238c..3632956c6bcf5 100644 --- a/tools/testing/selftests/kvm/lib/memstress.c +++ b/tools/testing/selftests/kvm/lib/memstress.c @@ -5,6 +5,7 @@ #define _GNU_SOURCE #include +#include #include "kvm_util.h" #include "memstress.h" @@ -320,3 +321,74 @@ void memstress_join_vcpu_threads(int nr_vcpus) for (i = 0; i < nr_vcpus; i++) pthread_join(vcpu_threads[i].thread, NULL); } + +static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable) +{ + int i; + + for (i = 0; i < slots; i++) { + int slot = MEMSTRESS_MEM_SLOT_INDEX + i; + int flags = enable ? KVM_MEM_LOG_DIRTY_PAGES : 0; + + vm_mem_region_set_flags(vm, slot, flags); + } +} + +void memstress_enable_dirty_logging(struct kvm_vm *vm, int slots) +{ + toggle_dirty_logging(vm, slots, true); +} + +void memstress_disable_dirty_logging(struct kvm_vm *vm, int slots) +{ + toggle_dirty_logging(vm, slots, false); +} + +void memstress_get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots) +{ + int i; + + for (i = 0; i < slots; i++) { + int slot = MEMSTRESS_MEM_SLOT_INDEX + i; + + kvm_vm_get_dirty_log(vm, slot, bitmaps[i]); + } +} + +void memstress_clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], + int slots, uint64_t pages_per_slot) +{ + int i; + + for (i = 0; i < slots; i++) { + int slot = MEMSTRESS_MEM_SLOT_INDEX + i; + + kvm_vm_clear_dirty_log(vm, slot, bitmaps[i], 0, pages_per_slot); + } +} + +unsigned long **memstress_alloc_bitmaps(int slots, uint64_t pages_per_slot) +{ + unsigned long **bitmaps; + int i; + + bitmaps = malloc(slots * sizeof(bitmaps[0])); + TEST_ASSERT(bitmaps, "Failed to allocate bitmaps array."); + + for (i = 0; i < slots; i++) { + bitmaps[i] = bitmap_zalloc(pages_per_slot); + TEST_ASSERT(bitmaps[i], "Failed to allocate slot bitmap."); + } + + return bitmaps; +} + +void memstress_free_bitmaps(unsigned long *bitmaps[], int slots) +{ + int i; + + for (i = 0; i < slots; i++) + free(bitmaps[i]); + + free(bitmaps); +} From patchwork Tue Jan 31 18:18:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardon X-Patchwork-Id: 50999 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp57804wrn; Tue, 31 Jan 2023 10:21:18 -0800 (PST) X-Google-Smtp-Source: AK7set9FBwqXh2iaPypmaKjoLcSM2rjOCvOiAnC3YFo1LztMa/cSKK4I4V462GyMqme5VLpnm7ai X-Received: by 2002:a05:6a20:429e:b0:be:22b4:9e6a with SMTP id o30-20020a056a20429e00b000be22b49e6amr9205004pzj.61.1675189277898; Tue, 31 Jan 2023 10:21:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675189277; cv=none; d=google.com; s=arc-20160816; b=QMAsvEDZJ8DqbXS8n6EocAlSA95DwzL9beCaZcRBlzKj3vYxZp1t7JVNOn2wzQuqNP e9GxGs/vjdTt/B4ZxIxhVRz37XmyaL/qYuNDUnz+C79seFvnB2TLQjHUqfIr+iBNjsDG n0CHHzZEeNzNCmzNJYcaY4PxLqfDNIBwBJA5xPyvJ3sWSokgpYbV6R3lfR8oJipggrgr UFG4riV1H4QezQF9Tzlgh9m086T0/coZ/h92GekQKYh5ZAq+rKx6HH0jez7vRXZE5loh HIU68FgAXIWJTgj9POfnoGwHf1ggGAQx3qZKZy1dxvYSCrAeqcthWg0VPNznm0nz2K0C jPJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=rJKWJ0gIh3iMmgA+SPQgOnOY9IIcpwxGu19jHnxwZCc=; b=uW5G0/u2ilL9rxyusEte6n0FfwXIN9PTrDMe4c1kE3UBwueux3u3Ez3hxcwHBQv9+E zuXsQQvU8b1+IijXzRfiD1DtUC4B9p2QsdnPGyKMGPwHT1JyCXQ8rR4AbPVWeBL8MxXL zcqqhl3NbUtayUmS2UQ2rD4WVIMlRLyo9mEcbYXvrUMmN+4qdBh3OKGgZHgIOK02E0Pm PVcdNvImHNa6HfWp5i5S66lidSWx/mdBiOm9/XTP5JtQn5rdOTVAk36W8dsDfbc9etx9 /p9f7s1dpA5S3GU7Jzn/PH3iRlAXLxPTdhOiycHisM0KbMIno3rXpj46q9J26S+27t+Q 91uQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=FgYMcXre; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id i191-20020a6387c8000000b0047811809072si12816574pge.92.2023.01.31.10.21.05; Tue, 31 Jan 2023 10:21:17 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=FgYMcXre; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230091AbjAaSSb (ORCPT + 99 others); Tue, 31 Jan 2023 13:18:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45058 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230244AbjAaSS3 (ORCPT ); Tue, 31 Jan 2023 13:18:29 -0500 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 777373CE0E for ; Tue, 31 Jan 2023 10:18:27 -0800 (PST) Received: by mail-pl1-x649.google.com with SMTP id w12-20020a170903310c00b0019663abbe88so5455718plc.20 for ; Tue, 31 Jan 2023 10:18:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=rJKWJ0gIh3iMmgA+SPQgOnOY9IIcpwxGu19jHnxwZCc=; b=FgYMcXreikzvCGMPZKzZMED5RK6aSNLx+ye9DVbLL5b+ixc/nKJnaggATCXAYHBlQn r3/nyKZx+Dab/oOEUBm5SnJ06fUyhBJe6IewfvXci0VMJ4xz41BQjGaEqpWLt2Dl9B2F zzzR42JnsVU74OWrUeiiKtISDriuEURJun7TOESBcawaYQwne+WwhoWsoH+dzFkRquOq BJkv387H449ZKS18G6Nr640dlOjClPxFVG4teePGW55RqfOXxNs8mHn64+1IXli9Q2L5 EIhOnXgIwyuHGoPzYJgkO9Rrflo1l7dE0Lg/C9LvPrVhm4ON9onffmsQUBs/9aFjSOMg pfww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=rJKWJ0gIh3iMmgA+SPQgOnOY9IIcpwxGu19jHnxwZCc=; b=ENnhy3nbVwrYdYxpsqacO2OpqCZQ+SY2p8yxJRBqpEOMUfnMh57o3FfTr7aSmLCNi7 F3TjM9fQsJEUyPVP1ErwmMP77fx9uOVDdkoePFWx5PbL91b+SVUm4nRmmkaHMGuN7Pev gPnD/ptLCfT2QAbYMhHNfByfl0HFqXTN8G77ThCKCHgx8YZMCSf9IDy5y508B7teILzz 91ncOFKMZQEU67lzjlc3JUq7p/zV5KDsDa1MWwQmJsZ0z8dAHXv+4LVWIMRVV+vLaD9h jgnYBJlH8jP8IVTU+wazLc3PdPrd676CI2W6kH6/WfQiJm9lfvvF5kz4KVPVTcIE1EEy mMIA== X-Gm-Message-State: AO0yUKXFhnFXw+kqh4tohh3QO3egP/vHLJmph1lwCb/gI1VN4w2TRcwp mN7DpLpExlyWRyeTsBr94I0eMkLDG465+9QVd+QsN1MYRsK5KtuCV4rPHm1wiXNzyWOemWxeiVN 1Ym9yxzHB8FxWCGKJq3TueDbsRtbF4ieyU+6553OrWja5vE1jAAZi+Z9vQCeFd6BhAqPJqKIO X-Received: from sweer.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:e45]) (user=bgardon job=sendgmr) by 2002:a62:1517:0:b0:592:d6b:4a5b with SMTP id 23-20020a621517000000b005920d6b4a5bmr3347538pfv.61.1675189106810; Tue, 31 Jan 2023 10:18:26 -0800 (PST) Date: Tue, 31 Jan 2023 18:18:20 +0000 In-Reply-To: <20230131181820.179033-1-bgardon@google.com> Mime-Version: 1.0 References: <20230131181820.179033-1-bgardon@google.com> X-Mailer: git-send-email 2.39.1.456.gfc5497dd1b-goog Message-ID: <20230131181820.179033-3-bgardon@google.com> Subject: [PATCH V5 2/2] selftests: KVM: Add dirty logging page splitting test From: Ben Gardon To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: Paolo Bonzini , Peter Xu , Sean Christopherson , David Matlack , Vipin Sharma , Ricardo Koller , Ben Gardon X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756563272351154198?= X-GMAIL-MSGID: =?utf-8?q?1756563272351154198?= Add a test for page splitting during dirty logging and for hugepage recovery after dirty logging. Page splitting represents non-trivial behavior, which is complicated by MANUAL_PROTECT mode, which causes pages to be split on the first clear, instead of when dirty logging is enabled. Add a test which makes assertions about page counts to help define the expected behavior of page splitting and to provide needed coverage of the behavior. This also helps ensure that a failure in eager page splitting is not covered up by splitting in the vCPU path. Tested by running the test on an Intel Haswell machine w/wo MANUAL_PROTECT. Reviewed-by: Vipin Sharma Signed-off-by: Ben Gardon --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/kvm_util_base.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 5 + .../x86_64/dirty_log_page_splitting_test.c | 260 ++++++++++++++++++ 4 files changed, 267 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 1750f91dd9362..9a8022918c3ea 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -61,6 +61,7 @@ TEST_PROGS_x86_64 += x86_64/nx_huge_pages_test.sh # Compiled test targets TEST_GEN_PROGS_x86_64 = x86_64/cpuid_test TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test +TEST_GEN_PROGS_x86_64 += x86_64/dirty_log_page_splitting_test TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features TEST_GEN_PROGS_x86_64 += x86_64/exit_on_emulation_failure_test TEST_GEN_PROGS_x86_64 += x86_64/fix_hypercall_test diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index fbc2a79369b8b..a089c356f354e 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -213,6 +213,7 @@ extern const struct vm_guest_mode_params vm_guest_mode_params[]; int open_path_or_exit(const char *path, int flags); int open_kvm_dev_path_or_exit(void); +bool get_kvm_param_bool(const char *param); bool get_kvm_intel_param_bool(const char *param); bool get_kvm_amd_param_bool(const char *param); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 56d5ea949cbbe..fa6d69f731990 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -80,6 +80,11 @@ static bool get_module_param_bool(const char *module_name, const char *param) TEST_FAIL("Unrecognized value '%c' for boolean module param", value); } +bool get_kvm_param_bool(const char *param) +{ + return get_module_param_bool("kvm", param); +} + bool get_kvm_intel_param_bool(const char *param) { return get_module_param_bool("kvm_intel", param); diff --git a/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c new file mode 100644 index 0000000000000..ed08c7ac3b2e3 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KVM dirty logging page splitting test + * + * Based on dirty_log_perf.c + * + * Copyright (C) 2018, Red Hat, Inc. + * Copyright (C) 2023, Google, Inc. + */ + +#include +#include +#include +#include + +#include "kvm_util.h" +#include "test_util.h" +#include "memstress.h" +#include "guest_modes.h" + +#define VCPUS 2 +#define SLOTS 2 +#define ITERATIONS 2 + +static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; + +static enum vm_mem_backing_src_type backing_src = VM_MEM_SRC_ANONYMOUS_HUGETLB; + +static u64 dirty_log_manual_caps; +static bool host_quit; +static int iteration; +static int vcpu_last_completed_iteration[KVM_MAX_VCPUS]; + +struct kvm_page_stats { + uint64_t pages_4k; + uint64_t pages_2m; + uint64_t pages_1g; + uint64_t hugepages; +}; + +static void get_page_stats(struct kvm_vm *vm, struct kvm_page_stats *stats, const char *stage) +{ + stats->pages_4k = vm_get_stat(vm, "pages_4k"); + stats->pages_2m = vm_get_stat(vm, "pages_2m"); + stats->pages_1g = vm_get_stat(vm, "pages_1g"); + stats->hugepages = stats->pages_2m + stats->pages_1g; + + pr_debug("\nPage stats after %s: 4K: %ld 2M: %ld 1G: %ld huge: %ld\n", + stage, stats->pages_4k, stats->pages_2m, stats->pages_1g, + stats->hugepages); +} + +static void run_vcpu_iteration(struct kvm_vm *vm) +{ + int i; + + iteration++; + for (i = 0; i < VCPUS; i++) { + while (READ_ONCE(vcpu_last_completed_iteration[i]) != + iteration) + ; + } +} + +static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) +{ + struct kvm_vcpu *vcpu = vcpu_args->vcpu; + int vcpu_idx = vcpu_args->vcpu_idx; + + while (!READ_ONCE(host_quit)) { + int current_iteration = READ_ONCE(iteration); + + vcpu_run(vcpu); + + ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_SYNC); + + vcpu_last_completed_iteration[vcpu_idx] = current_iteration; + + /* Wait for the start of the next iteration to be signaled. */ + while (current_iteration == READ_ONCE(iteration) && + READ_ONCE(iteration) >= 0 && + !READ_ONCE(host_quit)) + ; + } +} + +static void run_test(enum vm_guest_mode mode, void *unused) +{ + struct kvm_vm *vm; + unsigned long **bitmaps; + uint64_t guest_num_pages; + uint64_t host_num_pages; + uint64_t pages_per_slot; + int i; + uint64_t total_4k_pages; + struct kvm_page_stats stats_populated; + struct kvm_page_stats stats_dirty_logging_enabled; + struct kvm_page_stats stats_dirty_pass[ITERATIONS]; + struct kvm_page_stats stats_clear_pass[ITERATIONS]; + struct kvm_page_stats stats_dirty_logging_disabled; + struct kvm_page_stats stats_repopulated; + + vm = memstress_create_vm(mode, VCPUS, guest_percpu_mem_size, + SLOTS, backing_src, false); + + guest_num_pages = (VCPUS * guest_percpu_mem_size) >> vm->page_shift; + guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages); + host_num_pages = vm_num_host_pages(mode, guest_num_pages); + pages_per_slot = host_num_pages / SLOTS; + + bitmaps = memstress_alloc_bitmaps(SLOTS, pages_per_slot); + + if (dirty_log_manual_caps) + vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, + dirty_log_manual_caps); + + /* Start the iterations */ + iteration = -1; + host_quit = false; + + for (i = 0; i < VCPUS; i++) + vcpu_last_completed_iteration[i] = -1; + + memstress_start_vcpu_threads(VCPUS, vcpu_worker); + + run_vcpu_iteration(vm); + get_page_stats(vm, &stats_populated, "populating memory"); + + /* Enable dirty logging */ + memstress_enable_dirty_logging(vm, SLOTS); + + get_page_stats(vm, &stats_dirty_logging_enabled, "enabling dirty logging"); + + while (iteration < ITERATIONS) { + run_vcpu_iteration(vm); + get_page_stats(vm, &stats_dirty_pass[iteration - 1], + "dirtying memory"); + + memstress_get_dirty_log(vm, bitmaps, SLOTS); + + if (dirty_log_manual_caps) { + memstress_clear_dirty_log(vm, bitmaps, SLOTS, pages_per_slot); + + get_page_stats(vm, &stats_clear_pass[iteration - 1], "clearing dirty log"); + } + } + + /* Disable dirty logging */ + memstress_disable_dirty_logging(vm, SLOTS); + + get_page_stats(vm, &stats_dirty_logging_disabled, "disabling dirty logging"); + + /* Run vCPUs again to fault pages back in. */ + run_vcpu_iteration(vm); + get_page_stats(vm, &stats_repopulated, "repopulating memory"); + + /* + * Tell the vCPU threads to quit. No need to manually check that vCPUs + * have stopped running after disabling dirty logging, the join will + * wait for them to exit. + */ + host_quit = true; + memstress_join_vcpu_threads(VCPUS); + + memstress_free_bitmaps(bitmaps, SLOTS); + memstress_destroy_vm(vm); + + /* Make assertions about the page counts. */ + total_4k_pages = stats_populated.pages_4k; + total_4k_pages += stats_populated.pages_2m * 512; + total_4k_pages += stats_populated.pages_1g * 512 * 512; + + /* + * Check that all huge pages were split. Since large pages can only + * exist in the data slot, and the vCPUs should have dirtied all pages + * in the data slot, there should be no huge pages left after splitting. + * Splitting happens at dirty log enable time without + * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 and after the first clear pass + * with that capability. + */ + if (dirty_log_manual_caps) { + ASSERT_EQ(stats_clear_pass[0].hugepages, 0); + ASSERT_EQ(stats_clear_pass[0].pages_4k, total_4k_pages); + ASSERT_EQ(stats_dirty_logging_enabled.hugepages, stats_populated.hugepages); + } else { + ASSERT_EQ(stats_dirty_logging_enabled.hugepages, 0); + ASSERT_EQ(stats_dirty_logging_enabled.pages_4k, total_4k_pages); + } + + /* + * Once dirty logging is disabled and the vCPUs have touched all their + * memory again, the page counts should be the same as they were + * right after initial population of memory. + */ + ASSERT_EQ(stats_populated.pages_4k, stats_repopulated.pages_4k); + ASSERT_EQ(stats_populated.pages_2m, stats_repopulated.pages_2m); + ASSERT_EQ(stats_populated.pages_1g, stats_repopulated.pages_1g); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-b vcpu bytes] [-s mem type]\n", + name); + puts(""); + printf(" -b: specify the size of the memory region which should be\n" + " dirtied by each vCPU. e.g. 10M or 3G.\n" + " (default: 1G)\n"); + backing_src_help("-s"); + puts(""); +} + +int main(int argc, char *argv[]) +{ + int opt; + + TEST_REQUIRE(get_kvm_param_bool("eager_page_split")); + TEST_REQUIRE(get_kvm_param_bool("tdp_mmu")); + + while ((opt = getopt(argc, argv, "b:hs:")) != -1) { + switch (opt) { + case 'b': + guest_percpu_mem_size = parse_size(optarg); + break; + case 'h': + help(argv[0]); + exit(0); + case 's': + backing_src = parse_backing_src_type(optarg); + break; + default: + help(argv[0]); + exit(1); + } + } + + if (!is_backing_src_hugetlb(backing_src)) { + pr_info("This test will only work reliably with HugeTLB memory. " + "It can work with THP, but that is best effort."); + return KSFT_SKIP; + } + + guest_modes_append_default(); + + dirty_log_manual_caps = 0; + for_each_guest_mode(run_test, NULL); + + dirty_log_manual_caps = + kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); + + if (dirty_log_manual_caps) { + dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | + KVM_DIRTY_LOG_INITIALLY_SET); + for_each_guest_mode(run_test, NULL); + } else { + pr_info("Skipping testing with MANUAL_PROTECT as it is not supported"); + } + + return 0; +}