git: b6e28991bf3a - main - System wide and NUMA domain wide counters support. PMC classes for ARM DMC-620 and CMN-600.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 26 Jun 2022 09:12:04 UTC
The branch main has been updated by tsoome: URL: https://cgit.FreeBSD.org/src/commit/?id=b6e28991bf3aadb74c54c7e6dfc2992b29abae5a commit b6e28991bf3aadb74c54c7e6dfc2992b29abae5a Author: Aleksandr Rybalko <ray@freebsd.org> AuthorDate: 2022-02-16 00:17:02 +0000 Commit: Toomas Soome <tsoome@FreeBSD.org> CommitDate: 2022-06-26 05:31:03 +0000 System wide and NUMA domain wide counters support. PMC classes for ARM DMC-620 and CMN-600. Add support for system wide and NUMA domain wide counters support. Add 3 new PMC classes for ARM DMC-620 and CMN-600 controllers PMU. Reviewed by: mhorne Sponsored By: ARM Sponsored By: Ampere Computing Differential Revision: https://reviews.freebsd.org/D35342 --- lib/libpmc/pmc.3 | 6 +++- sys/sys/pmc.h | 13 ++++--- usr.sbin/pmcstat/pmcstat.c | 84 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/lib/libpmc/pmc.3 b/lib/libpmc/pmc.3 index 3325cb1e3d40..abe9f3208030 100644 --- a/lib/libpmc/pmc.3 +++ b/lib/libpmc/pmc.3 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 10, 2021 +.Dd May 28, 2022 .Dt PMC 3 .Os .Sh NAME @@ -200,6 +200,8 @@ Supported capabilities include: .Bl -tag -width "Li PMC_CAP_INTERRUPT" -compact .It Li PMC_CAP_CASCADE The ability to cascade counters. +.It Li PMC_CAP_DOMWIDE +Separate counters tied to each NUMA domain. .It Li PMC_CAP_EDGE The ability to count negated to asserted transitions of the hardware conditions being probed for. @@ -218,6 +220,8 @@ The ability to read from performance counters. .It Li PMC_CAP_SYSTEM The ability to restrict counting of hardware events to when the CPU is running privileged code. +.It Li PMC_CAP_SYSWIDE +A single counter aggregating events for the whole system. .It Li PMC_CAP_THRESHOLD The ability to ignore simultaneous hardware events below a programmable threshold. diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index 18c38ca36659..5465d0532a2a 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -171,7 +171,10 @@ enum pmc_cputype { __PMC_CLASS(MIPS74K, 0x12, "MIPS 74K") \ __PMC_CLASS(E500, 0x13, "Freescale e500 class") \ __PMC_CLASS(BERI, 0x14, "MIPS BERI") \ - __PMC_CLASS(POWER8, 0x15, "IBM POWER8 class") + __PMC_CLASS(POWER8, 0x15, "IBM POWER8 class") \ + __PMC_CLASS(DMC620_PMU_CD2, 0x16, "ARM DMC620 Memory Controller PMU CLKDIV2") \ + __PMC_CLASS(DMC620_PMU_C, 0x17, "ARM DMC620 Memory Controller PMU CLK") \ + __PMC_CLASS(CMN600_PMU, 0x18, "Arm CoreLink CMN600 Coherent Mesh Network PMU") enum pmc_class { #undef __PMC_CLASS @@ -180,7 +183,7 @@ enum pmc_class { }; #define PMC_CLASS_FIRST PMC_CLASS_TSC -#define PMC_CLASS_LAST PMC_CLASS_POWER8 +#define PMC_CLASS_LAST PMC_CLASS_CMN600_PMU /* * A PMC can be in the following states: @@ -308,7 +311,9 @@ enum pmc_disp { __PMC_CAP(QUALIFIER, 8, "further qualify monitored events") \ __PMC_CAP(PRECISE, 9, "perform precise sampling") \ __PMC_CAP(TAGGING, 10, "tag upstream events") \ - __PMC_CAP(CASCADE, 11, "cascade counters") + __PMC_CAP(CASCADE, 11, "cascade counters") \ + __PMC_CAP(SYSWIDE, 12, "system wide counter") \ + __PMC_CAP(DOMWIDE, 13, "NUMA domain wide counter") enum pmc_caps { @@ -318,7 +323,7 @@ enum pmc_caps }; #define PMC_CAP_FIRST PMC_CAP_INTERRUPT -#define PMC_CAP_LAST PMC_CAP_CASCADE +#define PMC_CAP_LAST PMC_CAP_DOMWIDE /* * PMC Event Numbers diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c index 3e2d101ab113..08e43d5d446a 100644 --- a/usr.sbin/pmcstat/pmcstat.c +++ b/usr.sbin/pmcstat/pmcstat.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include <regex.h> #include <signal.h> #include <stdarg.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -116,6 +117,7 @@ static int pmcstat_kq; static kvm_t *pmcstat_kvm; static struct kinfo_proc *pmcstat_plist; struct pmcstat_args args; +static bool libpmc_initialized = false; static void pmcstat_get_cpumask(const char *cpuspec, cpuset_t *cpumask) @@ -419,6 +421,22 @@ pmcstat_topexit(void) endwin(); } +static inline void +libpmc_initialize(int *npmc) +{ + + if (libpmc_initialized) + return; + if (pmc_init() < 0) + err(EX_UNAVAILABLE, "ERROR: Initialization of the pmc(3)" + " library failed"); + + /* assume all CPUs are identical */ + if ((*npmc = pmc_npmc(0)) < 0) + err(EX_OSERR, "ERROR: Cannot determine the number of PMCs on " + "CPU %d", 0); + libpmc_initialized = true; +} /* * Main */ @@ -426,14 +444,14 @@ pmcstat_topexit(void) int main(int argc, char **argv) { - cpuset_t cpumask, rootmask; + cpuset_t cpumask, dommask, rootmask; double interval; double duration; int option, npmc; int c, check_driver_stats; int do_callchain, do_descendants, do_logproccsw, do_logprocexit; - int do_print, do_read, do_listcounters, do_descr; - int do_userspace; + int do_print, do_read, do_listcounters, do_descr, domains; + int do_userspace, i; size_t len; int graphdepth; int pipefd[2], rfd; @@ -450,6 +468,7 @@ main(int argc, char **argv) struct winsize ws; struct stat sb; char buffer[PATH_MAX]; + uint32_t caps; check_driver_stats = 0; current_sampling_count = 0; @@ -460,6 +479,7 @@ main(int argc, char **argv) do_logproccsw = 0; do_logprocexit = 0; do_listcounters = 0; + domains = 0; use_cumulative_counts = 0; graphfilename = "-"; args.pa_required = 0; @@ -489,8 +509,10 @@ main(int argc, char **argv) bzero(&ds_end, sizeof(ds_end)); ev = NULL; event = NULL; + caps = 0; CPU_ZERO(&cpumask); + /* Default to using the running system kernel. */ len = 0; if (sysctlbyname("kern.bootfile", NULL, &len, NULL, 0) == -1) @@ -500,6 +522,9 @@ main(int argc, char **argv) errx(EX_SOFTWARE, "ERROR: Out of memory."); if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1) err(EX_OSERR, "ERROR: Cannot determine path of running kernel"); + len = sizeof(domains); + if (sysctlbyname("vm.ndomains", &domains, &len, NULL, 0) == -1) + err(EX_OSERR, "ERROR: Cannot get number of domains"); /* * The initial CPU mask specifies the root mask of this process @@ -640,6 +665,7 @@ main(int argc, char **argv) case 's': /* system-wide counting PMC */ case 'P': /* process virtual sampling PMC */ case 'S': /* system-wide sampling PMC */ + caps = 0; if ((ev = malloc(sizeof(*ev))) == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory."); @@ -707,12 +733,48 @@ main(int argc, char **argv) errx(EX_SOFTWARE, "ERROR: Out of memory."); (void) strncpy(ev->ev_name, optarg, c); *(ev->ev_name + c) = '\0'; + libpmc_initialize(&npmc); + if (args.pa_flags & FLAG_HAS_SYSTEM_PMCS) { + if (pmc_allocate(ev->ev_spec, ev->ev_mode, + ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid, + ev->ev_count) < 0) + err(EX_OSERR, "ERROR: Cannot allocate " + "system-mode pmc with specification" + " \"%s\"", ev->ev_spec); + if (pmc_capabilities(ev->ev_pmcid, &caps)) { + pmc_release(ev->ev_pmcid); + err(EX_OSERR, "ERROR: Cannot get pmc " + "capabilities"); + } + } + STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next); + if ((caps & PMC_CAP_SYSWIDE) == PMC_CAP_SYSWIDE) + break; + if ((caps & PMC_CAP_DOMWIDE) == PMC_CAP_DOMWIDE) { + CPU_ZERO(&cpumask); + /* + * Get number of domains and allocate one + * counter in each. + * First already allocated. + */ + for (i = 1; i < domains; i++) { + CPU_ZERO(&dommask); + cpuset_getaffinity(CPU_LEVEL_WHICH, + CPU_WHICH_DOMAIN, i, sizeof(dommask), + &dommask); + CPU_SET(CPU_FFS(&dommask) - 1, &cpumask); + } + args.pa_flags |= FLAGS_HAS_CPUMASK; + } if (option == 's' || option == 'S') { CPU_CLR(ev->ev_cpu, &cpumask); + pmc_id_t saved_pmcid = ev->ev_pmcid; + ev->ev_pmcid = PMC_ID_INVALID; pmcstat_clone_event_descriptor(ev, &cpumask, &args); + ev->ev_pmcid = saved_pmcid; CPU_SET(ev->ev_cpu, &cpumask); } @@ -1050,17 +1112,8 @@ main(int argc, char **argv) } /* if we've been asked to process a log file, skip init */ - if ((args.pa_flags & FLAG_READ_LOGFILE) == 0) { - if (pmc_init() < 0) - err(EX_UNAVAILABLE, - "ERROR: Initialization of the pmc(3) library failed" - ); - - if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */ - err(EX_OSERR, -"ERROR: Cannot determine the number of PMCs on CPU %d", - 0); - } + if ((args.pa_flags & FLAG_READ_LOGFILE) == 0) + libpmc_initialize(&npmc); /* Allocate a kqueue */ if ((pmcstat_kq = kqueue()) < 0) @@ -1134,7 +1187,8 @@ main(int argc, char **argv) */ STAILQ_FOREACH(ev, &args.pa_events, ev_next) { - if (pmc_allocate(ev->ev_spec, ev->ev_mode, + if (ev->ev_pmcid == PMC_ID_INVALID && + pmc_allocate(ev->ev_spec, ev->ev_mode, ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid, ev->ev_count) < 0) err(EX_OSERR,