Index: lib/libpmc/pmc.3 =================================================================== --- lib/libpmc/pmc.3 +++ 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 @@ .Bl -tag -width "Li PMC_CAP_INTERRUPT" -compact .It Li PMC_CAP_CASCADE The ability to cascade counters. +.It Li PMC_CAP_DOMWIDE +One counter in 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 @@ .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 +System wide counter. .It Li PMC_CAP_THRESHOLD The ability to ignore simultaneous hardware events below a programmable threshold. Index: sys/sys/pmc.h =================================================================== --- sys/sys/pmc.h +++ sys/sys/pmc.h @@ -168,7 +168,10 @@ __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 @@ -177,7 +180,7 @@ }; #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: @@ -305,7 +308,9 @@ __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 { @@ -315,7 +320,7 @@ }; #define PMC_CAP_FIRST PMC_CAP_INTERRUPT -#define PMC_CAP_LAST PMC_CAP_CASCADE +#define PMC_CAP_LAST PMC_CAP_DOMWIDE /* * PMC Event Numbers Index: usr.sbin/pmcstat/pmcstat.c =================================================================== --- usr.sbin/pmcstat/pmcstat.c +++ usr.sbin/pmcstat/pmcstat.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -116,6 +117,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ do_logproccsw = 0; do_logprocexit = 0; do_listcounters = 0; + domains = 0; use_cumulative_counts = 0; graphfilename = "-"; args.pa_required = 0; @@ -489,8 +509,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ } /* 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 @@ */ 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,