Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86/x86 Handle counter overflows, and sample with 5...



details:   https://anonhg.NetBSD.org/src/rev/a4205cdeba29
branches:  trunk
changeset: 822551:a4205cdeba29
user:      maxv <maxv%NetBSD.org@localhost>
date:      Fri Mar 24 19:21:06 2017 +0000

description:
Handle counter overflows, and sample with 500000 events per interrupt.
It's a pre-requisite for real sampling. Overflows are not yet displayed by
pmc(1), but will be soon.

diffstat:

 sys/arch/x86/x86/pmc.c |  119 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 84 insertions(+), 35 deletions(-)

diffs (224 lines):

diff -r 0340cfec8805 -r a4205cdeba29 sys/arch/x86/x86/pmc.c
--- a/sys/arch/x86/x86/pmc.c    Fri Mar 24 18:30:44 2017 +0000
+++ b/sys/arch/x86/x86/pmc.c    Fri Mar 24 19:21:06 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmc.c,v 1.4 2017/03/24 18:30:44 maxv Exp $     */
+/*     $NetBSD: pmc.c,v 1.5 2017/03/24 19:21:06 maxv Exp $     */
 
 /*
  * Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.4 2017/03/24 18:30:44 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.5 2017/03/24 19:21:06 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -82,17 +82,26 @@
 #include <machine/pmc.h>
 #include <machine/cpu_counter.h>
 #include <machine/cputypes.h>
+#include <machine/i82489reg.h>
+#include <machine/i82489var.h>
+
+#include <x86/nmi.h>
+
+#define NEVENTS_SAMPLE 500000
 
 typedef struct {
        bool running;
        uint32_t evtmsr;        /* event selector MSR */
        uint64_t evtval;        /* event selector value */
        uint32_t ctrmsr;        /* counter MSR */
-       uint64_t ctrval;        /* initial counter value */
+       uint64_t ctrinitval;    /* initial counter value */
        uint64_t ctrmaxval;     /* maximal counter value */
        uint64_t ctrmask;
 } pmc_state_t;
 
+static nmi_handler_t *pmc_nmi_handle;
+static uint32_t pmc_lapic_image[MAXCPUS];
+
 static x86_pmc_cpuval_t pmc_val_cpus[MAXCPUS] __aligned(CACHE_LINE_SIZE);
 static kmutex_t pmc_lock;
 
@@ -100,13 +109,72 @@
 static int pmc_ncounters __read_mostly;
 static int pmc_type __read_mostly;
 
+static int
+pmc_nmi(const struct trapframe *tf, void *dummy)
+{
+       struct cpu_info *ci = curcpu();
+       pmc_state_t *pmc;
+       size_t i;
+
+       if (pmc_type == PMC_TYPE_NONE) {
+               return 0;
+       }
+       for (i = 0; i < pmc_ncounters; i++) {
+               pmc = &pmc_state[i];
+               if (!pmc->running) {
+                       continue;
+               }
+               /* XXX make sure it really comes from this PMC */
+               break;
+       }
+       if (i == pmc_ncounters) {
+               return 0;
+       }
+
+       /* Count the overflow, and restart the counter */
+       pmc_val_cpus[cpu_index(ci)].overfl++;
+       wrmsr(pmc->ctrmsr, pmc->ctrinitval);
+
+       return 1;
+}
+
 static void
 pmc_read_cpu(void *arg1, void *arg2)
 {
        pmc_state_t *pmc = (pmc_state_t *)arg1;
        struct cpu_info *ci = curcpu();
 
-       pmc_val_cpus[cpu_index(ci)].ctrval = rdmsr(pmc->ctrmsr) & pmc->ctrmask;
+       pmc_val_cpus[cpu_index(ci)].ctrval =
+           (rdmsr(pmc->ctrmsr) & pmc->ctrmask) - pmc->ctrinitval;
+}
+
+static void
+pmc_apply_cpu(void *arg1, void *arg2)
+{
+       pmc_state_t *pmc = (pmc_state_t *)arg1;
+       bool start = (bool)arg2;
+       struct cpu_info *ci = curcpu();
+
+       if (start) {
+               pmc_lapic_image[cpu_index(ci)] = i82489_readreg(LAPIC_PCINT);
+               i82489_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI);
+       }
+
+       wrmsr(pmc->ctrmsr, pmc->ctrinitval);
+       switch (pmc_type) {
+       case PMC_TYPE_I686:
+       case PMC_TYPE_K7:
+       case PMC_TYPE_F10H:
+               wrmsr(pmc->evtmsr, pmc->evtval);
+               break;
+       }
+
+       pmc_val_cpus[cpu_index(ci)].ctrval = 0;
+       pmc_val_cpus[cpu_index(ci)].overfl = 0;
+
+       if (!start) {
+               i82489_writereg(LAPIC_PCINT, pmc_lapic_image[cpu_index(ci)]);
+       }
 }
 
 static void
@@ -119,31 +187,14 @@
 }
 
 static void
-pmc_apply_cpu(void *arg1, void *arg2)
-{
-       pmc_state_t *pmc = (pmc_state_t *)arg1;
-       struct cpu_info *ci = curcpu();
-
-       wrmsr(pmc->ctrmsr, pmc->ctrval);
-       switch (pmc_type) {
-       case PMC_TYPE_I686:
-       case PMC_TYPE_K7:
-       case PMC_TYPE_F10H:
-               wrmsr(pmc->evtmsr, pmc->evtval);
-               break;
-       }
-
-       pmc_val_cpus[cpu_index(ci)].ctrval = 0;
-       pmc_val_cpus[cpu_index(ci)].overfl = 0;
-}
-
-static void
-pmc_apply(pmc_state_t *pmc)
+pmc_apply(pmc_state_t *pmc, bool start)
 {
        uint64_t xc;
 
-       xc = xc_broadcast(0, pmc_apply_cpu, pmc, NULL);
+       xc = xc_broadcast(0, pmc_apply_cpu, pmc, (void *)start);
        xc_wait(xc);
+
+       pmc->running = start;
 }
 
 static void
@@ -151,19 +202,17 @@
 {
        uint64_t event, unit;
 
-       pmc->running = true;
-
        /*
         * Initialize the counter MSR.
         */
-       pmc->ctrval = args->val;
+       pmc->ctrinitval = pmc->ctrmaxval - NEVENTS_SAMPLE;
 
        /*
         * Initialize the event MSR.
         */
        switch (pmc_type) {
        case PMC_TYPE_I686:
-               pmc->evtval = args->event | PMC6_EVTSEL_EN |
+               pmc->evtval = args->event | PMC6_EVTSEL_EN | PMC6_EVTSEL_INT |
                    (args->unit << PMC6_EVTSEL_UNIT_SHIFT) |
                    ((args->flags & PMC_SETUP_KERNEL) ? PMC6_EVTSEL_OS : 0) |
                    ((args->flags & PMC_SETUP_USER) ? PMC6_EVTSEL_USR : 0) |
@@ -176,7 +225,7 @@
                event = (args->event & K7_EVTSEL_EVENT);
                unit = (args->unit << K7_EVTSEL_UNIT_SHIFT) &
                    K7_EVTSEL_UNIT;
-               pmc->evtval = event | unit | K7_EVTSEL_EN |
+               pmc->evtval = event | unit | K7_EVTSEL_EN | K7_EVTSEL_INT |
                    ((args->flags & PMC_SETUP_KERNEL) ? K7_EVTSEL_OS : 0) |
                    ((args->flags & PMC_SETUP_USER) ? K7_EVTSEL_USR : 0) |
                    ((args->flags & PMC_SETUP_EDGE) ? K7_EVTSEL_E : 0) |
@@ -192,7 +241,7 @@
                     F10H_EVTSEL_EVENT_SHIFT_HIGH);
                unit = (args->unit << F10H_EVTSEL_UNIT_SHIFT) &
                    F10H_EVTSEL_UNIT_MASK;
-               pmc->evtval = event | unit | F10H_EVTSEL_EN |
+               pmc->evtval = event | unit | F10H_EVTSEL_EN | F10H_EVTSEL_INT |
                    ((args->flags & PMC_SETUP_KERNEL) ? F10H_EVTSEL_OS : 0) |
                    ((args->flags & PMC_SETUP_USER) ? F10H_EVTSEL_USR : 0) |
                    ((args->flags & PMC_SETUP_EDGE) ? F10H_EVTSEL_EDGE : 0) |
@@ -204,16 +253,15 @@
        /*
         * Apply the changes.
         */
-       pmc_apply(pmc);
+       pmc_apply(pmc, true);
 }
 
 static void
 pmc_stop(pmc_state_t *pmc, struct x86_pmc_startstop_args *args)
 {
-       pmc->running = false;
        pmc->evtval = 0;
-       pmc->ctrval = 0;
-       pmc_apply(pmc);
+       pmc->ctrinitval = 0;
+       pmc_apply(pmc, false);
 }
 
 void
@@ -269,6 +317,7 @@
                }
        }
 
+       pmc_nmi_handle = nmi_establish(pmc_nmi, NULL);
        mutex_init(&pmc_lock, MUTEX_DEFAULT, IPL_NONE);
 }
 



Home | Main Index | Thread Index | Old Index