[RESEND PATCH v5 6/6] powerpc/kvm-hv-pmu: Add perf-events for Hostwide counters

2025-04-18 Thread Vaibhav Jain
Update 'kvm-hv-pmu.c' to add five new perf-events mapped to the five
Hostwide counters. Since these newly introduced perf events are at system
wide scope and can be read from any L1-Lpar CPU, 'kvmppc_pmu' scope and
capabilities are updated appropriately.

Also introduce two new helpers. First is kvmppc_update_l0_stats() that uses
the infrastructure introduced in previous patches to issues the
H_GUEST_GET_STATE hcall L0-PowerVM to fetch guest-state-buffer holding the
latest values of these counters which is then parsed and 'l0_stats'
variable updated.

Second helper is kvmppc_pmu_event_update() which is called from
'kvmppv_pmu' callbacks and uses kvmppc_update_l0_stats() to update
'l0_stats' and the update the 'struct perf_event's event-counter.

Some minor updates to kvmppc_pmu_{add, del, read}() to remove some debug
scaffolding code.

Signed-off-by: Vaibhav Jain 
Reviewed-by: Athira Rajeev 
---
Changelog

v5->resend:
* Rebase the patch to latest upstream kernel tree
* Added Athira's reviewed-by.

v4->v5:
* Call kvmppc_pmu_event_update() during pmu's 'del()' callback [ Athira ]

v3->v4:
* Minor tweaks to patch description and code as its now being built as a
separate kernel module.

v2->v3:
None

v1->v2:
None
---
 arch/powerpc/perf/kvm-hv-pmu.c | 92 +-
 1 file changed, 91 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/perf/kvm-hv-pmu.c b/arch/powerpc/perf/kvm-hv-pmu.c
index 705be24ccb43..ae264c9080ef 100644
--- a/arch/powerpc/perf/kvm-hv-pmu.c
+++ b/arch/powerpc/perf/kvm-hv-pmu.c
@@ -30,6 +30,11 @@
 #include "asm/guest-state-buffer.h"
 
 enum kvmppc_pmu_eventid {
+   KVMPPC_EVENT_HOST_HEAP,
+   KVMPPC_EVENT_HOST_HEAP_MAX,
+   KVMPPC_EVENT_HOST_PGTABLE,
+   KVMPPC_EVENT_HOST_PGTABLE_MAX,
+   KVMPPC_EVENT_HOST_PGTABLE_RECLAIM,
KVMPPC_EVENT_MAX,
 };
 
@@ -61,8 +66,14 @@ static DEFINE_SPINLOCK(lock_l0_stats);
 /* GSB related structs needed to talk to L0 */
 static struct kvmppc_gs_msg *gsm_l0_stats;
 static struct kvmppc_gs_buff *gsb_l0_stats;
+static struct kvmppc_gs_parser gsp_l0_stats;
 
 static struct attribute *kvmppc_pmu_events_attr[] = {
+   KVMPPC_PMU_EVENT_ATTR(host_heap, KVMPPC_EVENT_HOST_HEAP),
+   KVMPPC_PMU_EVENT_ATTR(host_heap_max, KVMPPC_EVENT_HOST_HEAP_MAX),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable, KVMPPC_EVENT_HOST_PGTABLE),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable_max, 
KVMPPC_EVENT_HOST_PGTABLE_MAX),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable_reclaim, 
KVMPPC_EVENT_HOST_PGTABLE_RECLAIM),
NULL,
 };
 
@@ -71,7 +82,7 @@ static const struct attribute_group kvmppc_pmu_events_group = 
{
.attrs = kvmppc_pmu_events_attr,
 };
 
-PMU_FORMAT_ATTR(event, "config:0");
+PMU_FORMAT_ATTR(event, "config:0-5");
 static struct attribute *kvmppc_pmu_format_attr[] = {
&format_attr_event.attr,
NULL,
@@ -88,6 +99,79 @@ static const struct attribute_group 
*kvmppc_pmu_attr_groups[] = {
NULL,
 };
 
+/*
+ * Issue the hcall to get the L0-host stats.
+ * Should be called with l0-stat lock held
+ */
+static int kvmppc_update_l0_stats(void)
+{
+   int rc;
+
+   /* With HOST_WIDE flags guestid and vcpuid will be ignored */
+   rc = kvmppc_gsb_recv(gsb_l0_stats, KVMPPC_GS_FLAGS_HOST_WIDE);
+   if (rc)
+   goto out;
+
+   /* Parse the guest state buffer is successful */
+   rc = kvmppc_gse_parse(&gsp_l0_stats, gsb_l0_stats);
+   if (rc)
+   goto out;
+
+   /* Update the l0 returned stats*/
+   memset(&l0_stats, 0, sizeof(l0_stats));
+   rc = kvmppc_gsm_refresh_info(gsm_l0_stats, gsb_l0_stats);
+
+out:
+   return rc;
+}
+
+/* Update the value of the given perf_event */
+static int kvmppc_pmu_event_update(struct perf_event *event)
+{
+   int rc;
+   u64 curr_val, prev_val;
+   unsigned long flags;
+   unsigned int config = event->attr.config;
+
+   /* Ensure no one else is modifying the l0_stats */
+   spin_lock_irqsave(&lock_l0_stats, flags);
+
+   rc = kvmppc_update_l0_stats();
+   if (!rc) {
+   switch (config) {
+   case KVMPPC_EVENT_HOST_HEAP:
+   curr_val = l0_stats.guest_heap;
+   break;
+   case KVMPPC_EVENT_HOST_HEAP_MAX:
+   curr_val = l0_stats.guest_heap_max;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE:
+   curr_val = l0_stats.guest_pgtable_size;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE_MAX:
+   curr_val = l0_stats.guest_pgtable_size_max;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE_RECLAIM:
+   curr_val = l0_stats.guest_pgtable_reclaim;
+   break;
+   default:
+   rc = -ENOENT;
+   break;
+   }
+   }
+
+   spin_unlock_irqrestore(&lock_l0_stats, 

Re: [PATCH v5 6/6] powerpc/kvm-hv-pmu: Add perf-events for Hostwide counters

2025-04-05 Thread Athira Rajeev



> On 17 Mar 2025, at 3:38 PM, Vaibhav Jain  wrote:
> 
> Update 'kvm-hv-pmu.c' to add five new perf-events mapped to the five
> Hostwide counters. Since these newly introduced perf events are at system
> wide scope and can be read from any L1-Lpar CPU, 'kvmppc_pmu' scope and
> capabilities are updated appropriately.
> 
> Also introduce two new helpers. First is kvmppc_update_l0_stats() that uses
> the infrastructure introduced in previous patches to issues the
> H_GUEST_GET_STATE hcall L0-PowerVM to fetch guest-state-buffer holding the
> latest values of these counters which is then parsed and 'l0_stats'
> variable updated.
> 
> Second helper is kvmppc_pmu_event_update() which is called from
> 'kvmppv_pmu' callbacks and uses kvmppc_update_l0_stats() to update
> 'l0_stats' and the update the 'struct perf_event's event-counter.
> 
> Some minor updates to kvmppc_pmu_{add, del, read}() to remove some debug
> scaffolding code.
> 
> Signed-off-by: Vaibhav Jain 

Thanks Vaibhav for including the changes in V5. Changes looks good to me in 
patches for perf events.

Reviewed-by: Athira Rajeev 

Thanks
Athira
> ---
> Changelog
> 
> v4->v5:
> * Call kvmppc_pmu_event_update() during pmu's 'del()' callback [ Atheera ]
> 
> v3->v4:
> * Minor tweaks to patch description and code as its now being built as a
> separate kernel module.
> 
> v2->v3:
> None
> 
> v1->v2:
> None
> ---
> arch/powerpc/perf/kvm-hv-pmu.c | 92 +-
> 1 file changed, 91 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/perf/kvm-hv-pmu.c b/arch/powerpc/perf/kvm-hv-pmu.c
> index 705be24ccb43..ae264c9080ef 100644
> --- a/arch/powerpc/perf/kvm-hv-pmu.c
> +++ b/arch/powerpc/perf/kvm-hv-pmu.c
> @@ -30,6 +30,11 @@
> #include "asm/guest-state-buffer.h"
> 
> enum kvmppc_pmu_eventid {
> + KVMPPC_EVENT_HOST_HEAP,
> + KVMPPC_EVENT_HOST_HEAP_MAX,
> + KVMPPC_EVENT_HOST_PGTABLE,
> + KVMPPC_EVENT_HOST_PGTABLE_MAX,
> + KVMPPC_EVENT_HOST_PGTABLE_RECLAIM,
> KVMPPC_EVENT_MAX,
> };
> 
> @@ -61,8 +66,14 @@ static DEFINE_SPINLOCK(lock_l0_stats);
> /* GSB related structs needed to talk to L0 */
> static struct kvmppc_gs_msg *gsm_l0_stats;
> static struct kvmppc_gs_buff *gsb_l0_stats;
> +static struct kvmppc_gs_parser gsp_l0_stats;
> 
> static struct attribute *kvmppc_pmu_events_attr[] = {
> + KVMPPC_PMU_EVENT_ATTR(host_heap, KVMPPC_EVENT_HOST_HEAP),
> + KVMPPC_PMU_EVENT_ATTR(host_heap_max, KVMPPC_EVENT_HOST_HEAP_MAX),
> + KVMPPC_PMU_EVENT_ATTR(host_pagetable, KVMPPC_EVENT_HOST_PGTABLE),
> + KVMPPC_PMU_EVENT_ATTR(host_pagetable_max, KVMPPC_EVENT_HOST_PGTABLE_MAX),
> + KVMPPC_PMU_EVENT_ATTR(host_pagetable_reclaim, 
> KVMPPC_EVENT_HOST_PGTABLE_RECLAIM),
> NULL,
> };
> 
> @@ -71,7 +82,7 @@ static const struct attribute_group kvmppc_pmu_events_group 
> = {
> .attrs = kvmppc_pmu_events_attr,
> };
> 
> -PMU_FORMAT_ATTR(event, "config:0");
> +PMU_FORMAT_ATTR(event, "config:0-5");
> static struct attribute *kvmppc_pmu_format_attr[] = {
> &format_attr_event.attr,
> NULL,
> @@ -88,6 +99,79 @@ static const struct attribute_group 
> *kvmppc_pmu_attr_groups[] = {
> NULL,
> };
> 
> +/*
> + * Issue the hcall to get the L0-host stats.
> + * Should be called with l0-stat lock held
> + */
> +static int kvmppc_update_l0_stats(void)
> +{
> + int rc;
> +
> + /* With HOST_WIDE flags guestid and vcpuid will be ignored */
> + rc = kvmppc_gsb_recv(gsb_l0_stats, KVMPPC_GS_FLAGS_HOST_WIDE);
> + if (rc)
> + goto out;
> +
> + /* Parse the guest state buffer is successful */
> + rc = kvmppc_gse_parse(&gsp_l0_stats, gsb_l0_stats);
> + if (rc)
> + goto out;
> +
> + /* Update the l0 returned stats*/
> + memset(&l0_stats, 0, sizeof(l0_stats));
> + rc = kvmppc_gsm_refresh_info(gsm_l0_stats, gsb_l0_stats);
> +
> +out:
> + return rc;
> +}
> +
> +/* Update the value of the given perf_event */
> +static int kvmppc_pmu_event_update(struct perf_event *event)
> +{
> + int rc;
> + u64 curr_val, prev_val;
> + unsigned long flags;
> + unsigned int config = event->attr.config;
> +
> + /* Ensure no one else is modifying the l0_stats */
> + spin_lock_irqsave(&lock_l0_stats, flags);
> +
> + rc = kvmppc_update_l0_stats();
> + if (!rc) {
> + switch (config) {
> + case KVMPPC_EVENT_HOST_HEAP:
> + curr_val = l0_stats.guest_heap;
> + break;
> + case KVMPPC_EVENT_HOST_HEAP_MAX:
> + curr_val = l0_stats.guest_heap_max;
> + break;
> + case KVMPPC_EVENT_HOST_PGTABLE:
> + curr_val = l0_stats.guest_pgtable_size;
> + break;
> + case KVMPPC_EVENT_HOST_PGTABLE_MAX:
> + curr_val = l0_stats.guest_pgtable_size_max;
> + break;
> + case KVMPPC_EVENT_HOST_PGTABLE_RECLAIM:
> + curr_val = l0_stats.guest_pgtable_reclaim;
> + break;
> + default:
> + rc = -ENOENT;
> + break;
> + }
> + }
> +
> + spin_unlock_irqrestore(&lock_l0_stats, flags);
> +
> + /* If no error than update the perf event */
> + if (!rc) {
> + prev_val = local64_xchg(&event->hw.prev_count, curr_val);
> + if (curr_val > prev_val)
> + local64_add(curr_val - prev_val, &event->count);
> + }
> +
> + return rc;
> +}
> +
> static int kvmppc_pmu_ev

[PATCH v5 6/6] powerpc/kvm-hv-pmu: Add perf-events for Hostwide counters

2025-03-17 Thread Vaibhav Jain
Update 'kvm-hv-pmu.c' to add five new perf-events mapped to the five
Hostwide counters. Since these newly introduced perf events are at system
wide scope and can be read from any L1-Lpar CPU, 'kvmppc_pmu' scope and
capabilities are updated appropriately.

Also introduce two new helpers. First is kvmppc_update_l0_stats() that uses
the infrastructure introduced in previous patches to issues the
H_GUEST_GET_STATE hcall L0-PowerVM to fetch guest-state-buffer holding the
latest values of these counters which is then parsed and 'l0_stats'
variable updated.

Second helper is kvmppc_pmu_event_update() which is called from
'kvmppv_pmu' callbacks and uses kvmppc_update_l0_stats() to update
'l0_stats' and the update the 'struct perf_event's event-counter.

Some minor updates to kvmppc_pmu_{add, del, read}() to remove some debug
scaffolding code.

Signed-off-by: Vaibhav Jain 
---
Changelog

v4->v5:
* Call kvmppc_pmu_event_update() during pmu's 'del()' callback [ Atheera ]

v3->v4:
* Minor tweaks to patch description and code as its now being built as a
separate kernel module.

v2->v3:
None

v1->v2:
None
---
 arch/powerpc/perf/kvm-hv-pmu.c | 92 +-
 1 file changed, 91 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/perf/kvm-hv-pmu.c b/arch/powerpc/perf/kvm-hv-pmu.c
index 705be24ccb43..ae264c9080ef 100644
--- a/arch/powerpc/perf/kvm-hv-pmu.c
+++ b/arch/powerpc/perf/kvm-hv-pmu.c
@@ -30,6 +30,11 @@
 #include "asm/guest-state-buffer.h"
 
 enum kvmppc_pmu_eventid {
+   KVMPPC_EVENT_HOST_HEAP,
+   KVMPPC_EVENT_HOST_HEAP_MAX,
+   KVMPPC_EVENT_HOST_PGTABLE,
+   KVMPPC_EVENT_HOST_PGTABLE_MAX,
+   KVMPPC_EVENT_HOST_PGTABLE_RECLAIM,
KVMPPC_EVENT_MAX,
 };
 
@@ -61,8 +66,14 @@ static DEFINE_SPINLOCK(lock_l0_stats);
 /* GSB related structs needed to talk to L0 */
 static struct kvmppc_gs_msg *gsm_l0_stats;
 static struct kvmppc_gs_buff *gsb_l0_stats;
+static struct kvmppc_gs_parser gsp_l0_stats;
 
 static struct attribute *kvmppc_pmu_events_attr[] = {
+   KVMPPC_PMU_EVENT_ATTR(host_heap, KVMPPC_EVENT_HOST_HEAP),
+   KVMPPC_PMU_EVENT_ATTR(host_heap_max, KVMPPC_EVENT_HOST_HEAP_MAX),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable, KVMPPC_EVENT_HOST_PGTABLE),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable_max, 
KVMPPC_EVENT_HOST_PGTABLE_MAX),
+   KVMPPC_PMU_EVENT_ATTR(host_pagetable_reclaim, 
KVMPPC_EVENT_HOST_PGTABLE_RECLAIM),
NULL,
 };
 
@@ -71,7 +82,7 @@ static const struct attribute_group kvmppc_pmu_events_group = 
{
.attrs = kvmppc_pmu_events_attr,
 };
 
-PMU_FORMAT_ATTR(event, "config:0");
+PMU_FORMAT_ATTR(event, "config:0-5");
 static struct attribute *kvmppc_pmu_format_attr[] = {
&format_attr_event.attr,
NULL,
@@ -88,6 +99,79 @@ static const struct attribute_group 
*kvmppc_pmu_attr_groups[] = {
NULL,
 };
 
+/*
+ * Issue the hcall to get the L0-host stats.
+ * Should be called with l0-stat lock held
+ */
+static int kvmppc_update_l0_stats(void)
+{
+   int rc;
+
+   /* With HOST_WIDE flags guestid and vcpuid will be ignored */
+   rc = kvmppc_gsb_recv(gsb_l0_stats, KVMPPC_GS_FLAGS_HOST_WIDE);
+   if (rc)
+   goto out;
+
+   /* Parse the guest state buffer is successful */
+   rc = kvmppc_gse_parse(&gsp_l0_stats, gsb_l0_stats);
+   if (rc)
+   goto out;
+
+   /* Update the l0 returned stats*/
+   memset(&l0_stats, 0, sizeof(l0_stats));
+   rc = kvmppc_gsm_refresh_info(gsm_l0_stats, gsb_l0_stats);
+
+out:
+   return rc;
+}
+
+/* Update the value of the given perf_event */
+static int kvmppc_pmu_event_update(struct perf_event *event)
+{
+   int rc;
+   u64 curr_val, prev_val;
+   unsigned long flags;
+   unsigned int config = event->attr.config;
+
+   /* Ensure no one else is modifying the l0_stats */
+   spin_lock_irqsave(&lock_l0_stats, flags);
+
+   rc = kvmppc_update_l0_stats();
+   if (!rc) {
+   switch (config) {
+   case KVMPPC_EVENT_HOST_HEAP:
+   curr_val = l0_stats.guest_heap;
+   break;
+   case KVMPPC_EVENT_HOST_HEAP_MAX:
+   curr_val = l0_stats.guest_heap_max;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE:
+   curr_val = l0_stats.guest_pgtable_size;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE_MAX:
+   curr_val = l0_stats.guest_pgtable_size_max;
+   break;
+   case KVMPPC_EVENT_HOST_PGTABLE_RECLAIM:
+   curr_val = l0_stats.guest_pgtable_reclaim;
+   break;
+   default:
+   rc = -ENOENT;
+   break;
+   }
+   }
+
+   spin_unlock_irqrestore(&lock_l0_stats, flags);
+
+   /* If no error than update the perf event */
+   if (!rc) {
+   prev_val = local64_xch