The branch main has been updated by tsoome:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=b6e28991bf3aadb74c54c7e6dfc2992b29abae5a

commit b6e28991bf3aadb74c54c7e6dfc2992b29abae5a
Author:     Aleksandr Rybalko <[email protected]>
AuthorDate: 2022-02-16 00:17:02 +0000
Commit:     Toomas Soome <[email protected]>
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,

Reply via email to