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/4433e746c8a4
branches: trunk
changeset: 352300:4433e746c8a4
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 ab192d173664 -r 4433e746c8a4 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