Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp172857rwd; Wed, 24 May 2023 16:11:08 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4I4B7/o/G0QfAmwiECsVObfd1vpMEbj6XxieH2U0lVfAvtkjQUU7LqPLZsKn5DHYHzZUID X-Received: by 2002:a17:903:2793:b0:1ae:62a6:fe61 with SMTP id jw19-20020a170903279300b001ae62a6fe61mr18714869plb.54.1684969868431; Wed, 24 May 2023 16:11:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684969868; cv=none; d=google.com; s=arc-20160816; b=TqwZE3VOTVX4k2/MZB4pC5y1cNaxSTMBeY+fyP7TIdUTIuSff5kbOymu0gbs+yrmmw uZkseqx9DvPklDfL+aRkabjTFbW4fmWdTuEPS+5WbD5BCeRlGFZMdzmUAfdIsZtvAE9B xt0gvY4L0rn31S/KBj6XO+OAEXR+5D1JzCVuRJ7V1oTHzMHeN6h048iSL+iuzCMb7nKR fZBquFKYOVFVj0ghBcmDnPtCV92YzwNOHTgQRAEeo7sigoLeOik4NC3YdrkKMd3u7k8O 22jxp3WdOiVo8I/pLwG4VjxnqdRSMAcHLwd+8Z9XqQBJTKnZ/SGkSVdCcrCEwkx/Caus IZ9g== 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=McTAZz5TDM/wNA+pFvseGWR8u1z//QTBMfmw5hfPpfs=; b=mK+3H8ewszSD2cGWiXE4aEYpUiBAdr1i5+7UKx7SLTai10s+alScX7jL9dxcbvlh0i rzrZcpJLNKQT0g6pdD7/74+FVRLnNEP2HMuMnCe0oOWXckw6/CM5r7/z2TImyozFPj4j NpenZygRzwAhIdb+flJGDCrJwPr6v1sC5aHPcUNwft82SZRk6nTLgt9PmOS7jamjKRjc 9dMgSuBXxmvXFz3TmmKIhDGj99Y1XepASIcEAdRhvylsuNnK93XQGkwIvA8FzVHcvtmc UiF/OEN4ResSzZ5QUNzcRSQETogrHWQmrNJ2+XSxBFnefCQbhmXDmKx3uwOU6a20xHP9 943w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="g/ZKhO12"; 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 Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j190-20020a636ec7000000b00534769ac796si9816894pgc.495.2023.05.24.16.10.51; Wed, 24 May 2023 16:11:08 -0700 (PDT) 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=20221208 header.b="g/ZKhO12"; 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 S238062AbjEXWdR (ORCPT + 99 others); Wed, 24 May 2023 18:33:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232967AbjEXWdP (ORCPT ); Wed, 24 May 2023 18:33:15 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2CC27E4D for ; Wed, 24 May 2023 15:32:37 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id d2e1a72fcca58-64d1c53cad8so1475507b3a.3 for ; Wed, 24 May 2023 15:32:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684967536; x=1687559536; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=McTAZz5TDM/wNA+pFvseGWR8u1z//QTBMfmw5hfPpfs=; b=g/ZKhO12ISoI6HFD5/SS5tOhIqWpz2FWh4HPlVxaTZGw7NmkIFwsi5FxFUd/K4uls1 8Vh29qUaC2GO9JKUQAwGb0nroHcRbcZ5poXwf4VmVf2MYaF1lY8K9cz9x/QsfRZr+DaF 1RDf8Av4ZO2V363lBGXzfhby/bxWw1SKD+fHrOQyqLqSq2cd5/TsiHEM1uwfRj9Pbzvw xsfn6jobUSUO3Uvtna6zmnkGas+IO4c7JTWAJPTqFun18rP3d6aoFmyBo5UGQ8f8n3nG pXhDHy6OPPuiDWb80jffsRF4npsc03SjuGvD/IbDxxDSH76Es0C9zj+ISHxvMbSdW/GN zBpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684967536; x=1687559536; 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=McTAZz5TDM/wNA+pFvseGWR8u1z//QTBMfmw5hfPpfs=; b=DxkIAMyNiDStvaL0FvWrdg27pzvcha/bmXAvL0z+rab8+0F07ZO/PcPxCCsUlzmiic Yy+pK/pOaJT37krBq0uv+qARW8BdzfxcY2godITgIf5CabhpThVu3abpWWkFF6mEmgDk iF+OO/UxQNIGmDFGN2yYn+VKYpJkIjTViN6Cix+ReTBIWHrZEq9kCZZfJW27qww7iFY+ kYEsj3hEkrg/tjIutPvumtrNS65yNEEchsgMVIhIEb2ezNz/DgQsZg2LG8AtxXKyPsjs tsBHaNO6Fi2kne7KKeXso47z6uP57awJKvs6WwkTeEsZPNVJ1RIMdloEUUHI3LLnqxUr 0GxQ== X-Gm-Message-State: AC+VfDwR9fR3owyvMPU4rAueo+JpKJsnGTmV0qLMyVzaJ9nFLX7g60sk mG904YBOMihwpxWclqchdpVuoHvQOsU= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a05:6a00:390c:b0:647:5400:a7cb with SMTP id fh12-20020a056a00390c00b006475400a7cbmr1699653pfb.3.1684967536684; Wed, 24 May 2023 15:32:16 -0700 (PDT) Date: Wed, 24 May 2023 15:32:14 -0700 In-Reply-To: <20230323072714.82289-2-likexu@tencent.com> Mime-Version: 1.0 References: <20230323072714.82289-1-likexu@tencent.com> <20230323072714.82289-2-likexu@tencent.com> Message-ID: Subject: Re: [PATCH 1/7] KVM: selftests: Test Intel PMU architectural events on gp counters From: Sean Christopherson To: Like Xu Cc: Paolo Bonzini , Jinrong Liang , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Content-Type: text/plain; charset="us-ascii" 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,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=ham 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 On Thu, Mar 23, 2023, Like Xu wrote: > From: Like Xu > > Add test cases to check if different Architectural events are available > after it's marked as unavailable via CPUID. It covers vPMU event filtering > logic based on Intel CPUID, which is a complement to pmu_event_filter. > > According to Intel SDM, the number of architectural events is reported > through CPUID.0AH:EAX[31:24] and the architectural event x is > supported if EBX[x]=0 && EAX[31:24]>x. > > Co-developed-by: Jinrong Liang > Signed-off-by: Jinrong Liang > Signed-off-by: Like Xu > --- > tools/testing/selftests/kvm/Makefile | 1 + > .../selftests/kvm/x86_64/pmu_cpuid_test.c | 202 ++++++++++++++++++ "cpuid" is a rather confusing name, e.g. I was half expecting tests where the guest is executing CPUID. IIUC, this is really just a basic functionality test, for a somewhat loose definition of "basic". Maybe something like pmu_basic_functionality_test? Or pmu_functional_test? > 2 files changed, 203 insertions(+) > create mode 100644 tools/testing/selftests/kvm/x86_64/pmu_cpuid_test.c ... > +#define EVENTSEL_OS BIT_ULL(17) > +#define EVENTSEL_EN BIT_ULL(22) > +#define PMU_CAP_FW_WRITES BIT_ULL(13) > +#define EVENTS_MASK GENMASK_ULL(7, 0) > +#define PMU_VERSION_MASK GENMASK_ULL(7, 0) > +#define GP_CTR_NUM_OFS_BIT 8 > +#define GP_CTR_NUM_MASK GENMASK_ULL(15, GP_CTR_NUM_OFS_BIT) > +#define EVT_LEN_OFS_BIT 24 > +#define EVT_LEN_MASK GENMASK_ULL(31, EVT_LEN_OFS_BIT) > + > +#define ARCH_EVENT(select, umask) (((select) & 0xff) | ((umask) & 0xff) << 8) > + > +/* > + * Intel Pre-defined Architectural Performance Events. Note some events > + * are skipped for testing due to difficulties in stable reproduction. > + */ > +static const uint64_t arch_events[] = { > + [0] = ARCH_EVENT(0x3c, 0x0), > + [1] = ARCH_EVENT(0xc0, 0x0), > + [2] = ARCH_EVENT(0x3c, 0x1), > + [3] = ARCH_EVENT(0x2e, 0x4f), /* LLC Reference */ > + [4] = ARCH_EVENT(0x2e, 0x41), /* LLC Misses */ > + [5] = ARCH_EVENT(0xc4, 0x0), > + [6] = ARCH_EVENT(0xc5, 0x0), /* Branch Misses Retired */ > + [7] = ARCH_EVENT(0xa4, 0x1), /* Topdown Slots */ > +}; All of these definitions belong in library code. Probably something like tools/testing/selftests/kvm/include/x86_64/pmu.h, or maybe intel_pmu.h? > +static struct kvm_vcpu *new_vcpu(void *guest_code) Assuming the next version is sent before the aforementioned cleanup, how about defining this as static struct kvm_vm *pmu_vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, void *guest_code) so that the cleanup can be a more straightforward replacement. That should also make the free_vcpu() wrapper completely unnecessary. > +{ > + struct kvm_vm *vm; > + struct kvm_vcpu *vcpu; > + > + vm = vm_create_with_one_vcpu(&vcpu, guest_code); > + vm_init_descriptor_tables(vm); > + vcpu_init_descriptor_tables(vcpu); Ugh, I really need to put together that series to clean up the descriptor table mess. https://lore.kernel.org/all/Y8hCBOndYMD9zsDL@google.com > + > + return vcpu; > +} > + > +static void free_vcpu(struct kvm_vcpu *vcpu) > +{ > + kvm_vm_free(vcpu->vm); Just call kvm_vm_free(). Adding layers of unnecessary helpers just to provide symmetry is not a good tradeoff. As above, tweak the name/prototyp of new_vcpu() if you really want something approaching symmetry. > +static void run_vcpu(struct kvm_vcpu *vcpu, const char *msg, > + bool (*check_ucall)(struct ucall *uc, void *data), > + void *expect_args) > +{ > + struct ucall uc; > + > + for (;;) { > + vcpu_run(vcpu); > + switch (get_ucall(vcpu, &uc)) { > + case UCALL_SYNC: > + TEST_ASSERT(check_ucall(&uc, expect_args), "%s", msg); A callback is both overkill and debug hostile. If the assert fails, it will report this common code and not the caller. Since all uses grab the first ucall param, just "return" that from the run_vcpu() wrapper as out param. Callers will need to define their own loop, but that's one line of code, and it has the advantage of making the code much more self-documenting E.g. static uint64_t run_vcpu(struct kvm_vcpu *vcpu, uint64_t *ucall_arg) { struct ucall uc; vcpu_run(vcpu); switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: ucall_arg = uc->args[1]; break; case UCALL_DONE: break; default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); } return uc.cmd; } and in intel_test_fixed_counters() as an example: while (run_vcpu(vcpu, &val) != UCALL_DONE) TEST_ASSERT(val, "One or more fixed counters not counting"); > +static void test_arch_events_setup(struct kvm_vcpu *vcpu, uint8_t evt_vector, > + uint8_t unavl_mask, uint8_t idx) > +{ > + struct kvm_cpuid_entry2 *entry; > + uint32_t ctr_msr = MSR_IA32_PERFCTR0; > + bool is_supported; > + > + entry = vcpu_get_cpuid_entry(vcpu, 0xa); > + entry->eax = (entry->eax & ~EVT_LEN_MASK) | > + (evt_vector << EVT_LEN_OFS_BIT); > + entry->ebx = (entry->ebx & ~EVENTS_MASK) | unavl_mask; > + vcpu_set_cpuid(vcpu); > + > + if (vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES) > + ctr_msr = MSR_IA32_PMC0; > + > + /* Arch event x is supported if EBX[x]=0 && EAX[31:24]>x */ > + is_supported = !(entry->ebx & BIT_ULL(idx)) && > + (((entry->eax & EVT_LEN_MASK) >> EVT_LEN_OFS_BIT) > idx); > + > + vcpu_args_set(vcpu, 5, entry->eax & PMU_VERSION_MASK, > + (entry->eax & GP_CTR_NUM_MASK) >> GP_CTR_NUM_OFS_BIT, > + is_supported, ctr_msr, arch_events[idx]); Why pass all this stuff in as params? Wouldn't it be easier to query CPUID from the guest side? And define KVM_X86_CPU_PROPERTY macros where possible to avoid having to open code things in multiple places. > +static void intel_check_arch_event_is_unavl(uint8_t idx) > +{ > + const char *msg = "Unavailable arch event is counting."; > + uint8_t eax_evt_vec, ebx_unavl_mask, i, j; > + struct kvm_vcpu *vcpu; > + > + /* > + * A brute force iteration of all combinations of values is likely to > + * exhaust the limit of the single-threaded thread fd nums, so it's > + * tested here by iterating through all valid values on a single bit. > + */ > + for (i = 0; i < ARRAY_SIZE(arch_events); i++) { > + eax_evt_vec = BIT_ULL(i); > + for (j = 0; j < ARRAY_SIZE(arch_events); j++) { > + ebx_unavl_mask = BIT_ULL(j); > + > + vcpu = new_vcpu(intel_guest_run_arch_event); > + test_arch_events_setup(vcpu, eax_evt_vec, > + ebx_unavl_mask, idx); > + run_vcpu(vcpu, msg, first_uc_arg_non_zero, NULL); Oof, this is super confusing. At first, second, and third glances, it looks like this is asserting that the counter _is_ counting. It took me a while to find this code in the guest: GUEST_SYNC(supported == !!_rdpmc(RDPMC_FIXED_BASE | i)); Either have the guest do GUEST_ASSERT() directly and process the output in the common run_vcpu(), or just have the guest return the counter value and do the assert here. My vote would be the latter, e.g. while (run_vcpu(vcpu, &counter_val) != UCALL_DONE) TEST_ASSERT(is_supported == !!counter_val, "blah blah blah"); That'd also likely avoid having to plumb the "supported" info into the guest.