Re: [PATCH v4 6/6] powerpc/kvm-hv-pmu: Add perf-events for Hostwide counters
Athira Rajeev <[email protected]> Tue, 11 Mar 2025 15:24:26 +0530
| Newsgroups | org.kernel.vger.kvm-ppc,org.kernel.vger.kvm,org.ozlabs.lists.linuxppc-dev |
|---|---|
| Message-ID | <[email protected]> |
> On 11 Mar 2025, at 3:02=E2=80=AFPM, Vaibhav Jain = <[email protected]> wrote: >=20 > Athira Rajeev <[email protected]> writes: >=20 >>> On 24 Feb 2025, at 6:45=E2=80=AFPM, Vaibhav Jain = <[email protected]> wrote: >>>=20 >>> 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. >>>=20 >>> 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. >>>=20 >>> 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. >>>=20 >>> Some minor updates to kvmppc_pmu_{add, del, read}() to remove some = debug >>> scaffolding code. >>>=20 >>> Signed-off-by: Vaibhav Jain <[email protected]> >>> --- >>> Changelog >>>=20 >>> v3->v4: >>> * Minor tweaks to patch description and code as its now being built = as a >>> separate kernel module. >>>=20 >>> v2->v3: >>> None >>>=20 >>> v1->v2: >>> None >>> --- >>> arch/powerpc/perf/kvm-hv-pmu.c | 92 = +++++++++++++++++++++++++++++++++- >>> 1 file changed, 91 insertions(+), 1 deletion(-) >>>=20 >>> diff --git a/arch/powerpc/perf/kvm-hv-pmu.c = b/arch/powerpc/perf/kvm-hv-pmu.c >>> index ed371454f7b5..274459bb32d6 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" >>>=20 >>> 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, >>> }; >>>=20 >>> @@ -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; >>>=20 >>> static struct attribute *kvmppc_pmu_events_attr[] =3D { >>> + 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, >>> }; >>>=20 >>> @@ -71,7 +82,7 @@ static const struct attribute_group = kvmppc_pmu_events_group =3D { >>> .attrs =3D kvmppc_pmu_events_attr, >>> }; >>>=20 >>> -PMU_FORMAT_ATTR(event, "config:0"); >>> +PMU_FORMAT_ATTR(event, "config:0-5"); >>> static struct attribute *kvmppc_pmu_format_attr[] =3D { >>> &format_attr_event.attr, >>> NULL, >>> @@ -88,6 +99,79 @@ static const struct attribute_group = *kvmppc_pmu_attr_groups[] =3D { >>> NULL, >>> }; >>>=20 >>> +/* >>> + * 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 =3D kvmppc_gsb_recv(gsb_l0_stats, KVMPPC_GS_FLAGS_HOST_WIDE); >>> + if (rc) >>> + goto out; >>> + >>> + /* Parse the guest state buffer is successful */ >>> + rc =3D 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 =3D 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 =3D event->attr.config; >>> + >>> + /* Ensure no one else is modifying the l0_stats */ >>> + spin_lock_irqsave(&lock_l0_stats, flags); >>> + >>> + rc =3D kvmppc_update_l0_stats(); >>> + if (!rc) { >>> + switch (config) { >>> + case KVMPPC_EVENT_HOST_HEAP: >>> + curr_val =3D l0_stats.guest_heap; >>> + break; >>> + case KVMPPC_EVENT_HOST_HEAP_MAX: >>> + curr_val =3D l0_stats.guest_heap_max; >>> + break; >>> + case KVMPPC_EVENT_HOST_PGTABLE: >>> + curr_val =3D l0_stats.guest_pgtable_size; >>> + break; >>> + case KVMPPC_EVENT_HOST_PGTABLE_MAX: >>> + curr_val =3D l0_stats.guest_pgtable_size_max; >>> + break; >>> + case KVMPPC_EVENT_HOST_PGTABLE_RECLAIM: >>> + curr_val =3D l0_stats.guest_pgtable_reclaim; >>> + break; >>> + default: >>> + rc =3D -ENOENT; >>> + break; >>> + } >>> + } >>> + >>> + spin_unlock_irqrestore(&lock_l0_stats, flags); >>> + >>> + /* If no error than update the perf event */ >>> + if (!rc) { >>> + prev_val =3D 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_event_init(struct perf_event *event) >>> { >>> unsigned int config =3D event->attr.config; >>> @@ -110,15 +194,19 @@ static int kvmppc_pmu_event_init(struct = perf_event *event) >>>=20 >>> static void kvmppc_pmu_del(struct perf_event *event, int flags) >>> { >>> + /* Do nothing */ >>> } >>=20 >> If we don=E2=80=99t read the counter stats in =E2=80=9Cdel=E2=80=9D = call back, we will loose the final count getting updated, right ? >> Del callback needs to call kvmppc_pmu_read. Can you check the = difference in count stats by calling kvmppc_pmu_read here ? >>=20 >=20 > Yes, agreed. Will address this in next version of the patch series >=20 Sure thanks ! Athira >> Thanks >> Athira >>=20 >>>=20 >>> static int kvmppc_pmu_add(struct perf_event *event, int flags) >>> { >>> + if (flags & PERF_EF_START) >>> + return kvmppc_pmu_event_update(event); >>> return 0; >>> } >>>=20 >>> static void kvmppc_pmu_read(struct perf_event *event) >>> { >>> + kvmppc_pmu_event_update(event); >>> } >>>=20 >>> /* Return the size of the needed guest state buffer */ >>> @@ -302,6 +390,8 @@ static struct pmu kvmppc_pmu =3D { >>> .read =3D kvmppc_pmu_read, >>> .attr_groups =3D kvmppc_pmu_attr_groups, >>> .type =3D -1, >>> + .scope =3D PERF_PMU_SCOPE_SYS_WIDE, >>> + .capabilities =3D PERF_PMU_CAP_NO_EXCLUDE | = PERF_PMU_CAP_NO_INTERRUPT, >>> }; >>>=20 >>> static int __init kvmppc_register_pmu(void) >>> --=20 >>> 2.48.1 >>>=20 >>>=20 >>>=20 >>=20 >>=20 >=20 > --=20 > Cheers > ~ Vaibhav