2022-09-19 09:51:01

by Like Xu

[permalink] [raw]
Subject: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

From: Like Xu <[email protected]>

The AMD PerfMonV2 defines three registers similar to part of the
Intel v2 PMU registers, including the GLOBAL_CTRL, GLOBAL_STATUS
and GLOBAL_OVF_CTRL MSRs. For better code reuse, this specific
part of the handling can be extracted to make it generic for X86.

The new non-prefix pmc_is_enabled() works well as legacy AMD vPMU
version is indexeqd as 1. Note that the specific *_is_valid_msr will
continue to be used to avoid cross-vendor msr access.

Signed-off-by: Like Xu <[email protected]>
---
arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 -
arch/x86/kvm/pmu.c | 55 +++++++++++++++++++++---
arch/x86/kvm/pmu.h | 30 ++++++++++++-
arch/x86/kvm/svm/pmu.c | 9 ----
arch/x86/kvm/vmx/pmu_intel.c | 58 +-------------------------
5 files changed, 80 insertions(+), 73 deletions(-)

diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
index c17e3e96fc1d..6c98f4bb4228 100644
--- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
+++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
@@ -13,7 +13,6 @@ BUILD_BUG_ON(1)
* at the call sites.
*/
KVM_X86_PMU_OP(hw_event_available)
-KVM_X86_PMU_OP(pmc_is_enabled)
KVM_X86_PMU_OP(pmc_idx_to_pmc)
KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
KVM_X86_PMU_OP(msr_idx_to_pmc)
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index fabbc43031b3..2643a3994624 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -83,11 +83,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
#undef __KVM_X86_PMU_OP
}

-static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
-{
- return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc);
-}
-
static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
{
struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
@@ -455,11 +450,61 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr)

int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ u32 msr = msr_info->index;
+
+ switch (msr) {
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ msr_info->data = pmu->global_status;
+ return 0;
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ msr_info->data = pmu->global_ctrl;
+ return 0;
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ msr_info->data = 0;
+ return 0;
+ default:
+ break;
+ }
+
return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
}

int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ u32 msr = msr_info->index;
+ u64 data = msr_info->data;
+ u64 diff;
+
+ switch (msr) {
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ if (msr_info->host_initiated) {
+ pmu->global_status = data;
+ return 0;
+ }
+ break; /* RO MSR */
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ if (pmu->global_ctrl == data)
+ return 0;
+ if (kvm_valid_perf_global_ctrl(pmu, data)) {
+ diff = pmu->global_ctrl ^ data;
+ pmu->global_ctrl = data;
+ reprogram_counters(pmu, diff);
+ return 0;
+ }
+ break;
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ if (!(data & pmu->global_ovf_ctrl_mask)) {
+ if (!msr_info->host_initiated)
+ pmu->global_status &= ~data;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 847e7112a5d3..0275f1bff5ea 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -26,7 +26,6 @@ struct kvm_event_hw_type_mapping {

struct kvm_pmu_ops {
bool (*hw_event_available)(struct kvm_pmc *pmc);
- bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
unsigned int idx, u64 *mask);
@@ -189,6 +188,35 @@ static inline void kvm_pmu_request_counter_reprogam(struct kvm_pmc *pmc)
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
}

+/*
+ * Check if a PMC is enabled by comparing it against global_ctrl bits.
+ *
+ * If the current version of vPMU doesn't have global_ctrl MSR,
+ * all vPMCs are enabled (return TRUE).
+ */
+static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
+{
+ struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+
+ if (pmu->version < 2)
+ return true;
+
+ return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
+}
+
+static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
+{
+ int bit;
+
+ if (!diff)
+ return;
+
+ for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
+ __set_bit(bit, pmu->reprogram_pmi);
+
+ kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
+}
+
void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index f99f2c869664..3a20972e9f1a 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -76,14 +76,6 @@ static bool amd_hw_event_available(struct kvm_pmc *pmc)
return true;
}

-/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
- * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
- */
-static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
-{
- return true;
-}
-
static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -218,7 +210,6 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)

struct kvm_pmu_ops amd_pmu_ops __initdata = {
.hw_event_available = amd_hw_event_available,
- .pmc_is_enabled = amd_pmc_is_enabled,
.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
.msr_idx_to_pmc = amd_msr_idx_to_pmc,
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 612c89ef5398..12eb2edfe9bc 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -68,18 +68,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
}
}

-static void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
-{
- int bit;
- struct kvm_pmc *pmc;
-
- for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
- pmc = intel_pmc_idx_to_pmc(pmu, bit);
- if (pmc)
- kvm_pmu_request_counter_reprogam(pmc);
- }
-}
-
static bool intel_hw_event_available(struct kvm_pmc *pmc)
{
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -102,17 +90,6 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc)
return true;
}

-/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
-static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
-{
- struct kvm_pmu *pmu = pmc_to_pmu(pmc);
-
- if (!intel_pmu_has_perf_global_ctrl(pmu))
- return true;
-
- return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
-}
-
static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -347,15 +324,6 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_CORE_PERF_FIXED_CTR_CTRL:
msr_info->data = pmu->fixed_ctr_ctrl;
return 0;
- case MSR_CORE_PERF_GLOBAL_STATUS:
- msr_info->data = pmu->global_status;
- return 0;
- case MSR_CORE_PERF_GLOBAL_CTRL:
- msr_info->data = pmu->global_ctrl;
- return 0;
- case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- msr_info->data = 0;
- return 0;
case MSR_IA32_PEBS_ENABLE:
msr_info->data = pmu->pebs_enable;
return 0;
@@ -404,29 +372,6 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 0;
}
break;
- case MSR_CORE_PERF_GLOBAL_STATUS:
- if (msr_info->host_initiated) {
- pmu->global_status = data;
- return 0;
- }
- break; /* RO MSR */
- case MSR_CORE_PERF_GLOBAL_CTRL:
- if (pmu->global_ctrl == data)
- return 0;
- if (kvm_valid_perf_global_ctrl(pmu, data)) {
- diff = pmu->global_ctrl ^ data;
- pmu->global_ctrl = data;
- reprogram_counters(pmu, diff);
- return 0;
- }
- break;
- case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- if (!(data & pmu->global_ovf_ctrl_mask)) {
- if (!msr_info->host_initiated)
- pmu->global_status &= ~data;
- return 0;
- }
- break;
case MSR_IA32_PEBS_ENABLE:
if (pmu->pebs_enable == data)
return 0;
@@ -783,7 +728,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
pmc = intel_pmc_idx_to_pmc(pmu, bit);

if (!pmc || !pmc_speculative_in_use(pmc) ||
- !intel_pmc_is_enabled(pmc) || !pmc->perf_event)
+ !pmc_is_enabled(pmc) || !pmc->perf_event)
continue;

hw_idx = pmc->perf_event->hw.idx;
@@ -795,7 +740,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)

struct kvm_pmu_ops intel_pmu_ops __initdata = {
.hw_event_available = intel_hw_event_available,
- .pmc_is_enabled = intel_pmc_is_enabled,
.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
.msr_idx_to_pmc = intel_msr_idx_to_pmc,
--
2.37.3


2022-09-22 00:42:04

by Jim Mattson

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On Mon, Sep 19, 2022 at 2:35 AM Like Xu <[email protected]> wrote:
>
> From: Like Xu <[email protected]>
>
> The AMD PerfMonV2 defines three registers similar to part of the
> Intel v2 PMU registers, including the GLOBAL_CTRL, GLOBAL_STATUS
> and GLOBAL_OVF_CTRL MSRs. For better code reuse, this specific
> part of the handling can be extracted to make it generic for X86.
>
> The new non-prefix pmc_is_enabled() works well as legacy AMD vPMU
> version is indexeqd as 1. Note that the specific *_is_valid_msr will
Nit: indexed
> continue to be used to avoid cross-vendor msr access.
>
> Signed-off-by: Like Xu <[email protected]>
> ---
> arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 -
> arch/x86/kvm/pmu.c | 55 +++++++++++++++++++++---
> arch/x86/kvm/pmu.h | 30 ++++++++++++-
> arch/x86/kvm/svm/pmu.c | 9 ----
> arch/x86/kvm/vmx/pmu_intel.c | 58 +-------------------------
> 5 files changed, 80 insertions(+), 73 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
> index c17e3e96fc1d..6c98f4bb4228 100644
> --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
> +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
> @@ -13,7 +13,6 @@ BUILD_BUG_ON(1)
> * at the call sites.
> */
> KVM_X86_PMU_OP(hw_event_available)
> -KVM_X86_PMU_OP(pmc_is_enabled)
> KVM_X86_PMU_OP(pmc_idx_to_pmc)
> KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
> KVM_X86_PMU_OP(msr_idx_to_pmc)
> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> index fabbc43031b3..2643a3994624 100644
> --- a/arch/x86/kvm/pmu.c
> +++ b/arch/x86/kvm/pmu.c
> @@ -83,11 +83,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
> #undef __KVM_X86_PMU_OP
> }
>
> -static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
> -{
> - return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc);
> -}
> -
> static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
> {
> struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
> @@ -455,11 +450,61 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr)
>
> int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> {
> + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> + u32 msr = msr_info->index;
> +
> + switch (msr) {
> + case MSR_CORE_PERF_GLOBAL_STATUS:
> + msr_info->data = pmu->global_status;
> + return 0;
> + case MSR_CORE_PERF_GLOBAL_CTRL:
> + msr_info->data = pmu->global_ctrl;
> + return 0;
> + case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> + msr_info->data = 0;
> + return 0;
> + default:
> + break;
> + }
> +
> return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
> }
>
> int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> {
> + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> + u32 msr = msr_info->index;
> + u64 data = msr_info->data;
> + u64 diff;
> +
> + switch (msr) {
> + case MSR_CORE_PERF_GLOBAL_STATUS:
> + if (msr_info->host_initiated) {
> + pmu->global_status = data;
> + return 0;
> + }
> + break; /* RO MSR */
Perhaps 'return 1'?
> + case MSR_CORE_PERF_GLOBAL_CTRL:
> + if (pmu->global_ctrl == data)
> + return 0;
> + if (kvm_valid_perf_global_ctrl(pmu, data)) {
> + diff = pmu->global_ctrl ^ data;
> + pmu->global_ctrl = data;
> + reprogram_counters(pmu, diff);
> + return 0;
> + }
> + break;
Perhaps 'return 1'?
> + case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> + if (!(data & pmu->global_ovf_ctrl_mask)) {
> + if (!msr_info->host_initiated)
> + pmu->global_status &= ~data;
> + return 0;
> + }
> + break;
Perhaps 'return 1'?
> + default:
> + break;
> + }
> +
> kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
> return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
> }
> diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
> index 847e7112a5d3..0275f1bff5ea 100644
> --- a/arch/x86/kvm/pmu.h
> +++ b/arch/x86/kvm/pmu.h
> @@ -26,7 +26,6 @@ struct kvm_event_hw_type_mapping {
>
> struct kvm_pmu_ops {
> bool (*hw_event_available)(struct kvm_pmc *pmc);
> - bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
> struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
> struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
> unsigned int idx, u64 *mask);
> @@ -189,6 +188,35 @@ static inline void kvm_pmu_request_counter_reprogam(struct kvm_pmc *pmc)
> kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
> }
>
> +/*
> + * Check if a PMC is enabled by comparing it against global_ctrl bits.
> + *
> + * If the current version of vPMU doesn't have global_ctrl MSR,
> + * all vPMCs are enabled (return TRUE).

The name of this function is a bit misleading. A PMC can be disabled
either by PERF_CLOBAL_CTRL or by its corresponding EVTSEL.

> + */
> +static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
> +{
> + struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> +
> + if (pmu->version < 2)
> + return true;
> +
> + return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
> +}
> +
> +static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
> +{
> + int bit;
> +
> + if (!diff)
> + return;
> +
> + for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
> + __set_bit(bit, pmu->reprogram_pmi);

I see that you've dropped the index to pmc conversion and the test for
a valid pmc. Maybe this is okay, but I'm not sure what the caller
looks like, since this is all in global_ctrl_changed() upstream.
What's your diff base?

> +
> + kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));

Why this new request? It's not in the Intel-specific version of these
function that you elide below.

Perhaps you could split up the semantic changes from the simple renamings?

> +}
> +
> void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
> void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
> int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
> diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
> index f99f2c869664..3a20972e9f1a 100644
> --- a/arch/x86/kvm/svm/pmu.c
> +++ b/arch/x86/kvm/svm/pmu.c
> @@ -76,14 +76,6 @@ static bool amd_hw_event_available(struct kvm_pmc *pmc)
> return true;
> }
>
> -/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
> - * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
> - */
> -static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
> -{
> - return true;
> -}
> -
> static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> @@ -218,7 +210,6 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
>
> struct kvm_pmu_ops amd_pmu_ops __initdata = {
> .hw_event_available = amd_hw_event_available,
> - .pmc_is_enabled = amd_pmc_is_enabled,
> .pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
> .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
> .msr_idx_to_pmc = amd_msr_idx_to_pmc,
> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
> index 612c89ef5398..12eb2edfe9bc 100644
> --- a/arch/x86/kvm/vmx/pmu_intel.c
> +++ b/arch/x86/kvm/vmx/pmu_intel.c
> @@ -68,18 +68,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
> }
> }
>
> -static void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
> -{
> - int bit;
> - struct kvm_pmc *pmc;
> -
> - for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
> - pmc = intel_pmc_idx_to_pmc(pmu, bit);
> - if (pmc)
> - kvm_pmu_request_counter_reprogam(pmc);
> - }
> -}
> -
> static bool intel_hw_event_available(struct kvm_pmc *pmc)
> {
> struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> @@ -102,17 +90,6 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc)
> return true;
> }
>
> -/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
> -static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
> -{
> - struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> -
> - if (!intel_pmu_has_perf_global_ctrl(pmu))
> - return true;
> -
> - return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
> -}
> -
> static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> @@ -347,15 +324,6 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> case MSR_CORE_PERF_FIXED_CTR_CTRL:
> msr_info->data = pmu->fixed_ctr_ctrl;
> return 0;
> - case MSR_CORE_PERF_GLOBAL_STATUS:
> - msr_info->data = pmu->global_status;
> - return 0;
> - case MSR_CORE_PERF_GLOBAL_CTRL:
> - msr_info->data = pmu->global_ctrl;
> - return 0;
> - case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> - msr_info->data = 0;
> - return 0;
> case MSR_IA32_PEBS_ENABLE:
> msr_info->data = pmu->pebs_enable;
> return 0;
> @@ -404,29 +372,6 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> return 0;
> }
> break;
> - case MSR_CORE_PERF_GLOBAL_STATUS:
> - if (msr_info->host_initiated) {
> - pmu->global_status = data;
> - return 0;
> - }
> - break; /* RO MSR */
> - case MSR_CORE_PERF_GLOBAL_CTRL:
> - if (pmu->global_ctrl == data)
> - return 0;
> - if (kvm_valid_perf_global_ctrl(pmu, data)) {
> - diff = pmu->global_ctrl ^ data;
> - pmu->global_ctrl = data;
> - reprogram_counters(pmu, diff);
> - return 0;
> - }
> - break;
> - case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> - if (!(data & pmu->global_ovf_ctrl_mask)) {
> - if (!msr_info->host_initiated)
> - pmu->global_status &= ~data;
> - return 0;
> - }
> - break;
> case MSR_IA32_PEBS_ENABLE:
> if (pmu->pebs_enable == data)
> return 0;
> @@ -783,7 +728,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
> pmc = intel_pmc_idx_to_pmc(pmu, bit);
>
> if (!pmc || !pmc_speculative_in_use(pmc) ||
> - !intel_pmc_is_enabled(pmc) || !pmc->perf_event)
> + !pmc_is_enabled(pmc) || !pmc->perf_event)
> continue;
>
> hw_idx = pmc->perf_event->hw.idx;
> @@ -795,7 +740,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
>
> struct kvm_pmu_ops intel_pmu_ops __initdata = {
> .hw_event_available = intel_hw_event_available,
> - .pmc_is_enabled = intel_pmc_is_enabled,
> .pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
> .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
> .msr_idx_to_pmc = intel_msr_idx_to_pmc,
> --
> 2.37.3
>

2022-09-22 06:08:27

by Like Xu

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On 22/9/2022 8:20 am, Jim Mattson wrote:
> On Mon, Sep 19, 2022 at 2:35 AM Like Xu <[email protected]> wrote:
>>
>> From: Like Xu <[email protected]>
>>
>> The AMD PerfMonV2 defines three registers similar to part of the
>> Intel v2 PMU registers, including the GLOBAL_CTRL, GLOBAL_STATUS
>> and GLOBAL_OVF_CTRL MSRs. For better code reuse, this specific
>> part of the handling can be extracted to make it generic for X86.
>>
>> The new non-prefix pmc_is_enabled() works well as legacy AMD vPMU
>> version is indexeqd as 1. Note that the specific *_is_valid_msr will
> Nit: indexed
>> continue to be used to avoid cross-vendor msr access.
>>
>> Signed-off-by: Like Xu <[email protected]>
>> ---
>> arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 -
>> arch/x86/kvm/pmu.c | 55 +++++++++++++++++++++---
>> arch/x86/kvm/pmu.h | 30 ++++++++++++-
>> arch/x86/kvm/svm/pmu.c | 9 ----
>> arch/x86/kvm/vmx/pmu_intel.c | 58 +-------------------------
>> 5 files changed, 80 insertions(+), 73 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
>> index c17e3e96fc1d..6c98f4bb4228 100644
>> --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
>> +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
>> @@ -13,7 +13,6 @@ BUILD_BUG_ON(1)
>> * at the call sites.
>> */
>> KVM_X86_PMU_OP(hw_event_available)
>> -KVM_X86_PMU_OP(pmc_is_enabled)
>> KVM_X86_PMU_OP(pmc_idx_to_pmc)
>> KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
>> KVM_X86_PMU_OP(msr_idx_to_pmc)
>> diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
>> index fabbc43031b3..2643a3994624 100644
>> --- a/arch/x86/kvm/pmu.c
>> +++ b/arch/x86/kvm/pmu.c
>> @@ -83,11 +83,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
>> #undef __KVM_X86_PMU_OP
>> }
>>
>> -static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
>> -{
>> - return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc);
>> -}
>> -
>> static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
>> {
>> struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
>> @@ -455,11 +450,61 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr)
>>
>> int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> {
>> + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>> + u32 msr = msr_info->index;
>> +
>> + switch (msr) {
>> + case MSR_CORE_PERF_GLOBAL_STATUS:
>> + msr_info->data = pmu->global_status;
>> + return 0;
>> + case MSR_CORE_PERF_GLOBAL_CTRL:
>> + msr_info->data = pmu->global_ctrl;
>> + return 0;
>> + case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
>> + msr_info->data = 0;
>> + return 0;
>> + default:
>> + break;
>> + }
>> +
>> return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
>> }
>>
>> int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> {
>> + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>> + u32 msr = msr_info->index;
>> + u64 data = msr_info->data;
>> + u64 diff;
>> +
>> + switch (msr) {
>> + case MSR_CORE_PERF_GLOBAL_STATUS:
>> + if (msr_info->host_initiated) {
>> + pmu->global_status = data;
>> + return 0;
>> + }
>> + break; /* RO MSR */
> Perhaps 'return 1'?
>> + case MSR_CORE_PERF_GLOBAL_CTRL:
>> + if (pmu->global_ctrl == data)
>> + return 0;
>> + if (kvm_valid_perf_global_ctrl(pmu, data)) {
>> + diff = pmu->global_ctrl ^ data;
>> + pmu->global_ctrl = data;
>> + reprogram_counters(pmu, diff);
>> + return 0;
>> + }
>> + break;
> Perhaps 'return 1'?
>> + case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
>> + if (!(data & pmu->global_ovf_ctrl_mask)) {
>> + if (!msr_info->host_initiated)
>> + pmu->global_status &= ~data;
>> + return 0;
>> + }
>> + break;
> Perhaps 'return 1'?

All above applied.

>> + default:
>> + break;
>> + }
>> +
>> kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
>> return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
>> }
>> diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
>> index 847e7112a5d3..0275f1bff5ea 100644
>> --- a/arch/x86/kvm/pmu.h
>> +++ b/arch/x86/kvm/pmu.h
>> @@ -26,7 +26,6 @@ struct kvm_event_hw_type_mapping {
>>
>> struct kvm_pmu_ops {
>> bool (*hw_event_available)(struct kvm_pmc *pmc);
>> - bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
>> struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
>> struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
>> unsigned int idx, u64 *mask);
>> @@ -189,6 +188,35 @@ static inline void kvm_pmu_request_counter_reprogam(struct kvm_pmc *pmc)
>> kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
>> }
>>
>> +/*
>> + * Check if a PMC is enabled by comparing it against global_ctrl bits.
>> + *
>> + * If the current version of vPMU doesn't have global_ctrl MSR,
>> + * all vPMCs are enabled (return TRUE).
>
> The name of this function is a bit misleading. A PMC can be disabled
> either by PERF_CLOBAL_CTRL or by its corresponding EVTSEL.

The name of this function is indeed very legacy.
How about rename it to pmc_is_enabled_globally() in a separate patch?

>
>> + */
>> +static inline bool pmc_is_enabled(struct kvm_pmc *pmc)
>> +{
>> + struct kvm_pmu *pmu = pmc_to_pmu(pmc);
>> +
>> + if (pmu->version < 2)
>> + return true;
>> +
>> + return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
>> +}
>> +
>> +static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
>> +{
>> + int bit;
>> +
>> + if (!diff)
>> + return;
>> +
>> + for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
>> + __set_bit(bit, pmu->reprogram_pmi);
>
> I see that you've dropped the index to pmc conversion and the test for
> a valid pmc. Maybe this is okay, but I'm not sure what the caller
> looks like, since this is all in global_ctrl_changed() upstream.
> What's your diff base?

As the cover letter says, the diff base is:
https://lore.kernel.org/kvm/[email protected]/.

Based on that, the reprogram_counters() can be reused
when either global_ctrl or pebs_enable is changed.

>
>> +
>> + kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
>
> Why this new request? It's not in the Intel-specific version of these
> function that you elide below.
>
> Perhaps you could split up the semantic changes from the simple renamings?

The creation of perf_event is delayed to the last step,
https://lore.kernel.org/kvm/[email protected]/

Based on the new code base, no semantic changes I assume.

>
>> +}
>> +
>> void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
>> void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
>> int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
>> diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
>> index f99f2c869664..3a20972e9f1a 100644
>> --- a/arch/x86/kvm/svm/pmu.c
>> +++ b/arch/x86/kvm/svm/pmu.c
>> @@ -76,14 +76,6 @@ static bool amd_hw_event_available(struct kvm_pmc *pmc)
>> return true;
>> }
>>
>> -/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
>> - * AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
>> - */
>> -static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
>> -{
>> - return true;
>> -}
>> -
>> static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
>> {
>> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>> @@ -218,7 +210,6 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
>>
>> struct kvm_pmu_ops amd_pmu_ops __initdata = {
>> .hw_event_available = amd_hw_event_available,
>> - .pmc_is_enabled = amd_pmc_is_enabled,
>> .pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
>> .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
>> .msr_idx_to_pmc = amd_msr_idx_to_pmc,
>> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
>> index 612c89ef5398..12eb2edfe9bc 100644
>> --- a/arch/x86/kvm/vmx/pmu_intel.c
>> +++ b/arch/x86/kvm/vmx/pmu_intel.c
>> @@ -68,18 +68,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
>> }
>> }
>>
>> -static void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
>> -{
>> - int bit;
>> - struct kvm_pmc *pmc;
>> -
>> - for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
>> - pmc = intel_pmc_idx_to_pmc(pmu, bit);
>> - if (pmc)
>> - kvm_pmu_request_counter_reprogam(pmc);
>> - }
>> -}
>> -
>> static bool intel_hw_event_available(struct kvm_pmc *pmc)
>> {
>> struct kvm_pmu *pmu = pmc_to_pmu(pmc);
>> @@ -102,17 +90,6 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc)
>> return true;
>> }
>>
>> -/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
>> -static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
>> -{
>> - struct kvm_pmu *pmu = pmc_to_pmu(pmc);
>> -
>> - if (!intel_pmu_has_perf_global_ctrl(pmu))
>> - return true;
>> -
>> - return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
>> -}
>> -
>> static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
>> {
>> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>> @@ -347,15 +324,6 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> case MSR_CORE_PERF_FIXED_CTR_CTRL:
>> msr_info->data = pmu->fixed_ctr_ctrl;
>> return 0;
>> - case MSR_CORE_PERF_GLOBAL_STATUS:
>> - msr_info->data = pmu->global_status;
>> - return 0;
>> - case MSR_CORE_PERF_GLOBAL_CTRL:
>> - msr_info->data = pmu->global_ctrl;
>> - return 0;
>> - case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
>> - msr_info->data = 0;
>> - return 0;
>> case MSR_IA32_PEBS_ENABLE:
>> msr_info->data = pmu->pebs_enable;
>> return 0;
>> @@ -404,29 +372,6 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>> return 0;
>> }
>> break;
>> - case MSR_CORE_PERF_GLOBAL_STATUS:
>> - if (msr_info->host_initiated) {
>> - pmu->global_status = data;
>> - return 0;
>> - }
>> - break; /* RO MSR */
>> - case MSR_CORE_PERF_GLOBAL_CTRL:
>> - if (pmu->global_ctrl == data)
>> - return 0;
>> - if (kvm_valid_perf_global_ctrl(pmu, data)) {
>> - diff = pmu->global_ctrl ^ data;
>> - pmu->global_ctrl = data;
>> - reprogram_counters(pmu, diff);
>> - return 0;
>> - }
>> - break;
>> - case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
>> - if (!(data & pmu->global_ovf_ctrl_mask)) {
>> - if (!msr_info->host_initiated)
>> - pmu->global_status &= ~data;
>> - return 0;
>> - }
>> - break;
>> case MSR_IA32_PEBS_ENABLE:
>> if (pmu->pebs_enable == data)
>> return 0;
>> @@ -783,7 +728,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
>> pmc = intel_pmc_idx_to_pmc(pmu, bit);
>>
>> if (!pmc || !pmc_speculative_in_use(pmc) ||
>> - !intel_pmc_is_enabled(pmc) || !pmc->perf_event)
>> + !pmc_is_enabled(pmc) || !pmc->perf_event)
>> continue;
>>
>> hw_idx = pmc->perf_event->hw.idx;
>> @@ -795,7 +740,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
>>
>> struct kvm_pmu_ops intel_pmu_ops __initdata = {
>> .hw_event_available = intel_hw_event_available,
>> - .pmc_is_enabled = intel_pmc_is_enabled,
>> .pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
>> .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
>> .msr_idx_to_pmc = intel_msr_idx_to_pmc,
>> --
>> 2.37.3
>>

2022-09-22 06:30:28

by Like Xu

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On 22/9/2022 1:47 pm, Like Xu wrote:
>> Why this new request? It's not in the Intel-specific version of these
>> function that you elide below.
>>
>> Perhaps you could split up the semantic changes from the simple renamings?
>
> The creation of perf_event is delayed to the last step,
> https://lore.kernel.org/kvm/[email protected]/
>
> Based on the new code base, no semantic changes I assume.

Sorry, I think we do need one more clear commit like this:

---

From e08b2d03a652e5ec226d8907c7648bff57f31d3b Mon Sep 17 00:00:00 2001
From: Like Xu <[email protected]>
Date: Thu, 22 Sep 2022 14:15:18 +0800
Subject: [PATCH] KVM: x86/pmu: Rewrite reprogram_counters() to improve
performance

Before using pmu->reprogram_pmi, the test for a valid pmc is always
applied. This part of the redundancy could be removed by setting the
counters' bitmask directly, and furthermore triggering KVM_REQ_PMU
only once to save more cycles.

Signed-off-by: Like Xu <[email protected]>
---
arch/x86/kvm/pmu.h | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index fb8040854f4d..9b8e74ccd18a 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -204,15 +204,11 @@ static inline bool pmc_is_enabled_globally(struct kvm_pmc
*pmc)
return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
}

-static void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
+static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
{
- int bit;
- struct kvm_pmc *pmc;
-
- for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) {
- pmc = intel_pmc_idx_to_pmc(pmu, bit);
- if (pmc)
- kvm_pmu_request_counter_reprogam(pmc);
+ if (diff) {
+ pmu->reprogram_pmi |= diff;
+ kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
}
}

--
2.37.3

2022-10-07 22:24:59

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On Thu, Sep 22, 2022, Like Xu wrote:
> On 22/9/2022 8:20 am, Jim Mattson wrote:
> > > int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> > > {
> > > + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> > > + u32 msr = msr_info->index;
> > > + u64 data = msr_info->data;
> > > + u64 diff;
> > > +
> > > + switch (msr) {
> > > + case MSR_CORE_PERF_GLOBAL_STATUS:
> > > + if (msr_info->host_initiated) {
> > > + pmu->global_status = data;
> > > + return 0;
> > > + }
> > > + break; /* RO MSR */
> > Perhaps 'return 1'?
> > > + case MSR_CORE_PERF_GLOBAL_CTRL:
> > > + if (pmu->global_ctrl == data)
> > > + return 0;
> > > + if (kvm_valid_perf_global_ctrl(pmu, data)) {
> > > + diff = pmu->global_ctrl ^ data;
> > > + pmu->global_ctrl = data;
> > > + reprogram_counters(pmu, diff);
> > > + return 0;
> > > + }
> > > + break;
> > Perhaps 'return 1'?
> > > + case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> > > + if (!(data & pmu->global_ovf_ctrl_mask)) {
> > > + if (!msr_info->host_initiated)
> > > + pmu->global_status &= ~data;

Pre-existing code question: why are writes from host userspace dropped? Is the
intent to avoid clearing the status register when the VM is migrated?

> > > + return 0;
> > > + }
> > > + break;
> > Perhaps 'return 1'?

Assuming the code is inverted, I'd prefer to keep the "break" to be consistent
with the other set_msr() helpers.

> All above applied.

I realize the code is pre-existing, but as opportunistic refactoring this should
be cleaned up to align with pretty much every other set_msr() helper, and with
respect to how the kernel typically handles errors. The preferred pattern is to do:

if (xyz)
return <error>

<commit change>

return <success>

I.e. intel_pmu_set_msr() is backwards, and having "default" statement silently
fallthrough is a bit nasty.

Cases like MSR_PEBS_DATA_CFG have also needlessly copied the "do check iff the
value is changing".

Can you add fold in the below (lightly tested) prep patch to fix intel_pmu_set_msr()?
Then this patch becomes a straight code movement.

--
From: Sean Christopherson <[email protected]>
Date: Fri, 7 Oct 2022 14:40:49 -0700
Subject: [PATCH] KVM: VMX: Refactor intel_pmu_set_msr() to align with other
set_msr() helpers

Invert the flows in intel_pmu_set_msr()'s case statements so that they
follow the kernel's preferred style of:

if (<not valid>)
return <error>

<commit change>
return <success>

which is also the style used by every other set_msr() helper (except
AMD's PMU variant, which doesn't use a switch statement).

Opportunstically move the "val == current" checks below the validity
checks. Except for the one-off case for MSR_P6_EVNTSEL2, the reserved
bit checks are extremely cheap, and the guest is unlikely to frequently
write the current value, i.e. avoiding the reserved bit checks doesn't
add much (any?) value.

No functional change intended.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/vmx/pmu_intel.c | 78 ++++++++++++++++++------------------
1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 25b70a85bef5..3031baa6742b 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -397,44 +397,43 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)

switch (msr) {
case MSR_CORE_PERF_FIXED_CTR_CTRL:
- if (pmu->fixed_ctr_ctrl == data)
- return 0;
- if (!(data & pmu->fixed_ctr_ctrl_mask)) {
+ if (data & pmu->fixed_ctr_ctrl_mask)
+ return 1;
+
+ if (pmu->fixed_ctr_ctrl != data)
reprogram_fixed_counters(pmu, data);
- return 0;
- }
break;
case MSR_CORE_PERF_GLOBAL_STATUS:
- if (msr_info->host_initiated) {
- pmu->global_status = data;
- return 0;
- }
- break; /* RO MSR */
+ if (!msr_info->host_initiated)
+ return 1;
+
+ pmu->global_status = data;
+ break;
case MSR_CORE_PERF_GLOBAL_CTRL:
- if (pmu->global_ctrl == data)
- return 0;
- if (kvm_valid_perf_global_ctrl(pmu, data)) {
+ if (!kvm_valid_perf_global_ctrl(pmu, data))
+ return 1;
+
+ if (pmu->global_ctrl != data) {
diff = pmu->global_ctrl ^ data;
pmu->global_ctrl = data;
reprogram_counters(pmu, diff);
- return 0;
}
break;
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- if (!(data & pmu->global_ovf_ctrl_mask)) {
- if (!msr_info->host_initiated)
- pmu->global_status &= ~data;
- return 0;
- }
+ if (data & pmu->global_ovf_ctrl_mask)
+ return 1;
+
+ if (!msr_info->host_initiated)
+ pmu->global_status &= ~data;
break;
case MSR_IA32_PEBS_ENABLE:
- if (pmu->pebs_enable == data)
- return 0;
- if (!(data & pmu->pebs_enable_mask)) {
+ if (data & pmu->pebs_enable_mask)
+ return 1;
+
+ if (pmu->pebs_enable != data) {
diff = pmu->pebs_enable ^ data;
pmu->pebs_enable = data;
reprogram_counters(pmu, diff);
- return 0;
}
break;
case MSR_IA32_DS_AREA:
@@ -443,14 +442,11 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (is_noncanonical_address(data, vcpu))
return 1;
pmu->ds_area = data;
- return 0;
+ break;
case MSR_PEBS_DATA_CFG:
- if (pmu->pebs_data_cfg == data)
- return 0;
- if (!(data & pmu->pebs_data_cfg_mask)) {
- pmu->pebs_data_cfg = data;
- return 0;
- }
+ if (data & pmu->pebs_data_cfg_mask)
+ return 1;
+ pmu->pebs_data_cfg = data;
break;
default:
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
@@ -463,28 +459,32 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
data = (s64)(s32)data;
pmc->counter += data - pmc_read_counter(pmc);
pmc_update_sample_period(pmc);
- return 0;
+ break;
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
pmc->counter += data - pmc_read_counter(pmc);
pmc_update_sample_period(pmc);
- return 0;
+ break;
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
- if (data == pmc->eventsel)
- return 0;
reserved_bits = pmu->reserved_bits;
if ((pmc->idx == 2) &&
(pmu->raw_event_mask & HSW_IN_TX_CHECKPOINTED))
reserved_bits ^= HSW_IN_TX_CHECKPOINTED;
- if (!(data & reserved_bits)) {
+ if (data & reserved_bits)
+ return 1;
+
+ if (data != pmc->eventsel) {
pmc->eventsel = data;
reprogram_counter(pmc);
- return 0;
}
- } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false))
- return 0;
+ break;
+ } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) {
+ break;
+ }
+ /* Not a known PMU MSR. */
+ return 1;
}

- return 1;
+ return 0;
}

static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu)

base-commit: e18d6152ff0f41b7f01f9817372022df04e0d354
--


2022-10-27 22:26:00

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On Thu, Sep 22, 2022, Like Xu wrote:
> Subject: [PATCH] KVM: x86/pmu: Rewrite reprogram_counters() to improve
> performance
>
> Before using pmu->reprogram_pmi, the test for a valid pmc is always
> applied. This part of the redundancy could be removed by setting the
> counters' bitmask directly, and furthermore triggering KVM_REQ_PMU
> only once to save more cycles.

Assuming you plan on posting this, please explicitly state what the patch does.
"This part of the redundancy could" only says what _could_ be done, not what is
actually done. Oftentimes, a changelog will say something "could" be done when
talking about alternative solutions. So when I see "could", I think "this is
what the patch _isn't_ doing".

2022-10-27 23:09:41

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] KVM: x86/pmu: Make part of the Intel v2 PMU MSRs handling x86 generic

On Mon, Sep 19, 2022, Like Xu wrote:
> From: Like Xu <[email protected]>
>
> The AMD PerfMonV2 defines three registers similar to part of the
> Intel v2 PMU registers, including the GLOBAL_CTRL, GLOBAL_STATUS
> and GLOBAL_OVF_CTRL MSRs. For better code reuse, this specific
> part of the handling can be extracted to make it generic for X86.
>
> The new non-prefix pmc_is_enabled() works well as legacy AMD vPMU
> version is indexeqd as 1. Note that the specific *_is_valid_msr will
> continue to be used to avoid cross-vendor msr access.

Please state what the patch is doing and why. The above provides a small part of
the "why", and alludes to the "what", but never actually states what is being done.