Date: Mon, 16 Mar 2026 23:39:46 +0000 From: Mitchell Horne <mhorne@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ali Mashtizadeh <mashti@uwaterloo.ca> Subject: git: 44a983d249d0 - main - libpmc: Query hwpmc for caps Message-ID: <69b894c2.226fd.416425cf@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by mhorne: URL: https://cgit.FreeBSD.org/src/commit/?id=44a983d249d05d932b6cff333f130baf70febc22 commit 44a983d249d05d932b6cff333f130baf70febc22 Author: Ali Mashtizadeh <mashti@uwaterloo.ca> AuthorDate: 2026-03-01 22:08:30 +0000 Commit: Mitchell Horne <mhorne@FreeBSD.org> CommitDate: 2026-03-16 23:31:15 +0000 libpmc: Query hwpmc for caps This change allows for fine-grained capabilities per counter index. This is particularly useful for AMD where subclasses are not exposed to the general PMC code, but other architectures also have asymmetric behaviors when it comes to specific counter indices. A new PMC_OP_GETCAPS op is added to the hwpmc(4) ioctl interface. Reviewed by: mhorne Sponsored by: Netflix Pull Request: https://github.com/freebsd/freebsd-src/pull/2058 --- lib/libpmc/libpmc.c | 19 +++++++++---------- share/man/man4/hwpmc.4 | 4 ++++ sys/dev/hwpmc/hwpmc_amd.c | 15 +++++++++++++++ sys/dev/hwpmc/hwpmc_mod.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ sys/sys/pmc.h | 15 ++++++++++++++- 5 files changed, 87 insertions(+), 11 deletions(-) diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c index 6be91a7501fe..ceba40aa7b39 100644 --- a/lib/libpmc/libpmc.c +++ b/lib/libpmc/libpmc.c @@ -1211,17 +1211,16 @@ pmc_attach(pmc_id_t pmc, pid_t pid) int pmc_capabilities(pmc_id_t pmcid, uint32_t *caps) { - unsigned int i; - enum pmc_class cl; + struct pmc_op_caps args; + int status; - cl = PMC_ID_TO_CLASS(pmcid); - for (i = 0; i < cpu_info.pm_nclass; i++) - if (cpu_info.pm_classes[i].pm_class == cl) { - *caps = cpu_info.pm_classes[i].pm_caps; - return (0); - } - errno = EINVAL; - return (-1); + args.pm_pmcid = pmcid; + args.pm_caps = 0; + + status = PMC_CALL(PMC_OP_GETCAPS, &args); + *caps = args.pm_caps; + + return (status); } int diff --git a/share/man/man4/hwpmc.4 b/share/man/man4/hwpmc.4 index 54a251dcca76..1ab690e5009c 100644 --- a/share/man/man4/hwpmc.4 +++ b/share/man/man4/hwpmc.4 @@ -325,6 +325,10 @@ This operation returns to the caller after the write operation has returned. The returned error code reflects any pending error state inside .Nm . +.It Dv PMC_OP_GETCAPS +Retrieve the capabilities associated with a specific PMC counter. +Some capabilities may be limited to specific indices (i.e., not available +across all counters within a class). .It Dv PMC_OP_GETCPUINFO Retrieve information about the highest possible CPU number for the system, and the number of hardware performance monitoring counters available per CPU. diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c index c27d93995d59..51505bfcff37 100644 --- a/sys/dev/hwpmc/hwpmc_amd.c +++ b/sys/dev/hwpmc/hwpmc_amd.c @@ -702,6 +702,20 @@ amd_get_msr(int ri, uint32_t *msr) return (0); } +/* + * Return the capabilities of the given PMC. + */ +static int +amd_get_caps(int ri, uint32_t *caps) +{ + KASSERT(ri >= 0 && ri < amd_npmcs, + ("[amd,%d] ri %d out of range", __LINE__, ri)); + + *caps = amd_pmcdesc[ri].pm_descr.pd_caps; + + return (0); +} + /* * Processor-dependent initialization. */ @@ -958,6 +972,7 @@ pmc_amd_initialize(void) pcd->pcd_start_pmc = amd_start_pmc; pcd->pcd_stop_pmc = amd_stop_pmc; pcd->pcd_write_pmc = amd_write_pmc; + pcd->pcd_get_caps = amd_get_caps; pmc_mdep->pmd_cputype = cputype; pmc_mdep->pmd_intr = amd_intr; diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index 1fa021429c5a..fb1fdf832398 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -4538,6 +4538,51 @@ pmc_syscall_handler(struct thread *td, void *syscall_args) } break; + /* + * Get the PMC capabilities + */ + + case PMC_OP_GETCAPS: + { + struct pmc_op_caps c; + struct pmc *pm; + struct pmc_classdep *pcd; + pmc_id_t pmcid; + int adjri, ri; + + PMC_DOWNGRADE_SX(); + + if ((error = copyin(arg, &c, sizeof(c))) != 0) + break; + + pmcid = c.pm_pmcid; + + if ((error = pmc_find_pmc(pmcid, &pm)) != 0) + break; + + KASSERT(pmcid == pm->pm_id, + ("[pmc,%d] pmc id %x != pmcid %x", __LINE__, + pm->pm_id, pmcid)); + + ri = PMC_TO_ROWINDEX(pm); + pcd = pmc_ri_to_classdep(md, ri, &adjri); + + /* + * If PMC class has no GETCAPS return the class capabilities + * otherwise get the per counter capabilities. + */ + if (pcd->pcd_get_caps == NULL) { + c.pm_caps = pcd->pcd_caps; + } else { + error = (*pcd->pcd_get_caps)(adjri, &c.pm_caps); + if (error < 0) + break; + } + + if ((error = copyout(&c, arg, sizeof(c))) < 0) + break; + } + break; default: error = EINVAL; diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index 7640a9b96c84..244a18e90c39 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -346,7 +346,8 @@ enum pmc_event { __PMC_OP(PMCSTOP, "Stop a PMC") \ __PMC_OP(WRITELOG, "Write a cookie to the log file") \ __PMC_OP(CLOSELOG, "Close log file") \ - __PMC_OP(GETDYNEVENTINFO, "Get dynamic events list") + __PMC_OP(GETDYNEVENTINFO, "Get dynamic events list") \ + __PMC_OP(GETCAPS, "Get capabilities") enum pmc_ops { #undef __PMC_OP @@ -638,6 +639,17 @@ struct pmc_op_getdyneventinfo { struct pmc_dyn_event_descr pm_events[PMC_EV_DYN_COUNT]; }; +/* + * OP GETCAPS + * + * Retrieve the PMC capabilties flags for this type of counter. + */ + +struct pmc_op_caps { + pmc_id_t pm_pmcid; /* allocated pmc id */ + uint32_t pm_caps; /* capabilities */ +}; + #ifdef _KERNEL #include <sys/malloc.h> @@ -1040,6 +1052,7 @@ struct pmc_classdep { /* description */ int (*pcd_describe)(int _cpu, int _ri, struct pmc_info *_pi, struct pmc **_ppmc); + int (*pcd_get_caps)(int _ri, uint32_t *_caps); /* class-dependent initialization & finalization */ int (*pcd_pcpu_init)(struct pmc_mdep *_md, int _cpu);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69b894c2.226fd.416425cf>
