diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index 3c30d0045d8db0..1fc63ad55cf3b4 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -19,6 +19,10 @@ #include "perf_test_util.h" #include "guest_modes.h" +#ifdef __x86_64__ +#include "processor.h" +#endif + /* How many host loops to run by default (one KVM_GET_DIRTY_LOG for each loop)*/ #define TEST_HOST_LOOP_N 2UL @@ -166,6 +170,18 @@ static void run_test(enum vm_guest_mode mode, void *arg) vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, p->slots, p->backing_src); +#ifdef __x86_64__ + /* + * No vCPUs have been started yet, so KVM should not have created any + * mapping at this moment. + */ + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_4K) == 0, + "4K page is non zero"); + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_2M) == 0, + "2M page is non zero"); + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_1G) == 0, + "1G page is non zero"); +#endif perf_test_args.wr_fract = p->wr_fract; guest_num_pages = (nr_vcpus * guest_percpu_mem_size) >> vm_get_page_shift(vm); @@ -211,6 +227,22 @@ static void run_test(enum vm_guest_mode mode, void *arg) pr_info("Populate memory time: %ld.%.9lds\n", ts_diff.tv_sec, ts_diff.tv_nsec); +#ifdef __x86_64__ + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_4K) != 0, + "4K page is zero"); + /* Ensure THP page stats is non-zero to minimize the flakiness. */ + if (p->backing_src == VM_MEM_SRC_ANONYMOUS_THP) + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_2M) > 0 + "2M page number is zero"); + else if (p->backing_src == VM_MEM_SRC_ANONYMOUS_HUGETLB_2MB) + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_2M) == + (guest_percpu_mem_size * nr_vcpus) >> X86_PAGE_2M_SHIFT, + "2M page number does not match"); + else if (p->backing_src == VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB) + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_1G) == + (guest_percpu_mem_size * nr_vcpus) >> X86_PAGE_1G_SHIFT, + "1G page number does not match"); +#endif /* Enable dirty logging */ clock_gettime(CLOCK_MONOTONIC, &start); enable_dirty_logging(vm, p->slots); @@ -256,6 +288,18 @@ static void run_test(enum vm_guest_mode mode, void *arg) iteration, ts_diff.tv_sec, ts_diff.tv_nsec); } } +#ifdef __x86_64__ + /* + * When vCPUs writes to all memory again with dirty logging enabled, we + * should see only 4K page mappings exist in KVM mmu. + */ + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_4K) != 0, + "4K page is zero after dirtying memory"); + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_2M) == 0, + "2M page is non-zero after dirtying memory"); + TEST_ASSERT(get_page_stats(X86_PAGE_SIZE_1G) == 0, + "1G page is non-zero after dirtying memory"); +#endif /* Disable dirty logging */ clock_gettime(CLOCK_MONOTONIC, &start); diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index d79be15dd3d204..dca5fcf7aa87ff 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -102,6 +102,7 @@ const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i); size_t get_backing_src_pagesz(uint32_t i); void backing_src_help(void); enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name); +size_t get_page_stats(uint32_t page_level); /* * Whether or not the given source type is shared memory (as opposed to diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 242ae8e09a653a..9749319821a3a8 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -39,6 +39,13 @@ #define X86_CR4_SMAP (1ul << 21) #define X86_CR4_PKE (1ul << 22) +#define X86_PAGE_4K_SHIFT 12 +#define X86_PAGE_4K (1ul << X86_PAGE_4K_SHIFT) +#define X86_PAGE_2M_SHIFT 21 +#define X86_PAGE_2M (1ul << X86_PAGE_2M_SHIFT) +#define X86_PAGE_1G_SHIFT 30 +#define X86_PAGE_1G (1ul << X86_PAGE_1G_SHIFT) + /* CPUID.1.ECX */ #define CPUID_VMX (1ul << 5) #define CPUID_SMX (1ul << 6) diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c index af1031fed97f7d..07eb6b5c125ea1 100644 --- a/tools/testing/selftests/kvm/lib/test_util.c +++ b/tools/testing/selftests/kvm/lib/test_util.c @@ -15,6 +15,13 @@ #include "linux/kernel.h" #include "test_util.h" +#include "processor.h" + +static const char * const pagestat_filepaths[] = { + "/sys/kernel/debug/kvm/pages_4k", + "/sys/kernel/debug/kvm/pages_2m", + "/sys/kernel/debug/kvm/pages_1g", +}; /* * Parses "[0-9]+[kmgt]?". @@ -141,6 +148,28 @@ size_t get_trans_hugepagesz(void) return size; } +#ifdef __x86_64__ +size_t get_stats_from_file(const char *path) +{ + size_t value; + FILE *f; + + f = fopen(path, "r"); + TEST_ASSERT(f != NULL, "Error in opening file: %s\n", path); + + fscanf(f, "%ld", &value); + fclose(f); + + return value; +} + +size_t get_page_stats(uint32_t page_level) +{ + TEST_ASSERT(page_level <= X86_PAGE_SIZE_1G, "page type error."); + return get_stats_from_file(pagestat_filepaths[page_level]); +} +#endif + size_t get_def_hugetlb_pagesz(void) { char buf[64];