Module Name:    src
Committed By:   maxv
Date:           Fri Mar 24 19:21:07 UTC 2017

Modified Files:
        src/sys/arch/x86/x86: pmc.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/x86/x86/pmc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/pmc.c
diff -u src/sys/arch/x86/x86/pmc.c:1.4 src/sys/arch/x86/x86/pmc.c:1.5
--- src/sys/arch/x86/x86/pmc.c:1.4	Fri Mar 24 18:30:44 2017
+++ src/sys/arch/x86/x86/pmc.c	Fri Mar 24 19:21:06 2017
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.4 
 #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,31 +109,58 @@ static pmc_state_t pmc_state[PMC_NCOUNTE
 static int pmc_ncounters __read_mostly;
 static int pmc_type __read_mostly;
 
-static void
-pmc_read_cpu(void *arg1, void *arg2)
+static int
+pmc_nmi(const struct trapframe *tf, void *dummy)
 {
-	pmc_state_t *pmc = (pmc_state_t *)arg1;
 	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);
 
-	pmc_val_cpus[cpu_index(ci)].ctrval = rdmsr(pmc->ctrmsr) & pmc->ctrmask;
+	return 1;
 }
 
 static void
-pmc_read(pmc_state_t *pmc)
+pmc_read_cpu(void *arg1, void *arg2)
 {
-	uint64_t xc;
+	pmc_state_t *pmc = (pmc_state_t *)arg1;
+	struct cpu_info *ci = curcpu();
 
-	xc = xc_broadcast(0, pmc_read_cpu, pmc, NULL);
-	xc_wait(xc);
+	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();
 
-	wrmsr(pmc->ctrmsr, pmc->ctrval);
+	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:
@@ -135,15 +171,30 @@ pmc_apply_cpu(void *arg1, void *arg2)
 
 	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
+pmc_read(pmc_state_t *pmc)
+{
+	uint64_t xc;
+
+	xc = xc_broadcast(0, pmc_read_cpu, pmc, NULL);
+	xc_wait(xc);
 }
 
 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 @@ pmc_start(pmc_state_t *pmc, struct x86_p
 {
 	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 @@ pmc_start(pmc_state_t *pmc, struct x86_p
 		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 @@ pmc_start(pmc_state_t *pmc, struct x86_p
 		     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 @@ pmc_start(pmc_state_t *pmc, struct x86_p
 	/*
 	 * 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_init(void)
 		}
 	}
 
+	pmc_nmi_handle = nmi_establish(pmc_nmi, NULL);
 	mutex_init(&pmc_lock, MUTEX_DEFAULT, IPL_NONE);
 }
 

Reply via email to