Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Properly handle overflows, and take them into account in use...
details: https://anonhg.NetBSD.org/src/rev/511c3f170644
branches: trunk
changeset: 355089:511c3f170644
user: maxv <maxv%NetBSD.org@localhost>
date: Wed Jul 12 17:33:29 2017 +0000
description:
Properly handle overflows, and take them into account in userland.
diffstat:
sys/arch/x86/include/sysarch.h | 3 +-
sys/arch/x86/x86/pmc.c | 110 +++++++++++++++++++++++++++++++++-------
usr.bin/pmc/pmc.c | 14 ++++-
3 files changed, 104 insertions(+), 23 deletions(-)
diffs (truncated from 337 to 300 lines):
diff -r 8d040eaf6f76 -r 511c3f170644 sys/arch/x86/include/sysarch.h
--- a/sys/arch/x86/include/sysarch.h Wed Jul 12 17:32:51 2017 +0000
+++ b/sys/arch/x86/include/sysarch.h Wed Jul 12 17:33:29 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sysarch.h,v 1.11 2017/03/10 13:09:11 maxv Exp $ */
+/* $NetBSD: sysarch.h,v 1.12 2017/07/12 17:33:29 maxv Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -134,6 +134,7 @@
int vers;
int type;
uint32_t nctrs;
+ uint64_t nsamp;
};
#define PMC_VERSION 1
diff -r 8d040eaf6f76 -r 511c3f170644 sys/arch/x86/x86/pmc.c
--- a/sys/arch/x86/x86/pmc.c Wed Jul 12 17:32:51 2017 +0000
+++ b/sys/arch/x86/x86/pmc.c Wed Jul 12 17:33:29 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmc.c,v 1.9 2017/07/12 16:59:41 maxv Exp $ */
+/* $NetBSD: pmc.c,v 1.10 2017/07/12 17:33:29 maxv Exp $ */
/*
* Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -63,11 +63,17 @@
*/
/*
- * Interface to x86 CPU Performance Counters.
+ * Interface to x86 CPU Performance Counters. System-wide only, for now.
+ *
+ * For each PMC on each CPU, two pieces of information are returned to userland:
+ * the number of overflows, and the current value of the PMC. It means that the
+ * total number of events for the given PMC on the given CPU is computable the
+ * following way:
+ * tot_n_events = NEVENTS_SAMPLE * overfl + ctrval
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.9 2017/07/12 16:59:41 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmc.c,v 1.10 2017/07/12 17:33:29 maxv Exp $");
#include "opt_pmc.h"
@@ -83,7 +89,6 @@
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <machine/pmc.h>
-#include <machine/cpu_counter.h>
#include <machine/cputypes.h>
#include <machine/i82489reg.h>
#include <machine/i82489var.h>
@@ -92,8 +97,12 @@
#define NEVENTS_SAMPLE 500000
+/*
+ * Structure describing a PMC.
+ */
typedef struct {
bool running;
+ size_t n; /* pmc number */
uint32_t evtmsr; /* event selector MSR */
uint64_t evtval; /* event selector value */
uint32_t ctrmsr; /* counter MSR */
@@ -102,21 +111,36 @@
uint64_t ctrmask;
} pmc_state_t;
+/*
+ * Per-CPU structure that describes the values of each PMC, plus the state
+ * of the LAPIC before enabling PMCs.
+ */
+typedef struct {
+ x86_pmc_cpuval_t val[PMC_NCOUNTERS]; /* values returned to user */
+ uint64_t nmioverfl[PMC_NCOUNTERS]; /* incremented by NMI intr */
+ uint32_t lapic_image; /* saved content of LAPIC */
+} pmc_cpu_t;
+
+static pmc_state_t pmc_state[PMC_NCOUNTERS];
+static pmc_cpu_t pmc_cpu[MAXCPUS];
+
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;
-static pmc_state_t pmc_state[PMC_NCOUNTERS];
static uint32_t pmc_ncounters __read_mostly;
static int pmc_type __read_mostly;
+/*
+ * Handle PMC overflows. Called from NMI interrupt context, with interrupts
+ * disabled.
+ */
static int
pmc_nmi(const struct trapframe *tf, void *dummy)
{
struct cpu_info *ci = curcpu();
pmc_state_t *pmc;
+ pmc_cpu_t *cpu;
+ uint64_t ctr;
size_t i;
if (pmc_type == PMC_TYPE_NONE) {
@@ -127,7 +151,11 @@
if (!pmc->running) {
continue;
}
- /* XXX make sure it really comes from this PMC */
+ ctr = rdmsr(pmc->ctrmsr);
+ /* If the highest bit is zero, then it's this PMC */
+ if ((ctr & ((pmc->ctrmask + 1) >> 1)) != 0) {
+ continue;
+ }
break;
}
if (i == pmc_ncounters) {
@@ -135,7 +163,8 @@
}
/* Count the overflow, and restart the counter */
- pmc_val_cpus[cpu_index(ci)].overfl++;
+ cpu = &pmc_cpu[cpu_index(ci)];
+ cpu->nmioverfl[i]++;
wrmsr(pmc->ctrmsr, pmc->ctrinitval);
return 1;
@@ -146,9 +175,37 @@
{
pmc_state_t *pmc = (pmc_state_t *)arg1;
struct cpu_info *ci = curcpu();
+ pmc_cpu_t *cpu = &pmc_cpu[cpu_index(ci)];
+ uint64_t evtmsr, en;
- pmc_val_cpus[cpu_index(ci)].ctrval =
+ switch (pmc_type) {
+ case PMC_TYPE_I686:
+ en = PMC6_EVTSEL_EN;
+ break;
+
+ case PMC_TYPE_K7:
+ en = K7_EVTSEL_EN;
+ break;
+
+ case PMC_TYPE_F10H:
+ en = F10H_EVTSEL_EN;
+ break;
+ }
+
+ evtmsr = rdmsr(pmc->evtmsr);
+
+ /*
+ * Quickly disable the counter, to avoid getting an NMI after setting
+ * ctrval.
+ */
+ wrmsr(pmc->evtmsr, evtmsr & ~en);
+
+ cpu->val[pmc->n].ctrval =
(rdmsr(pmc->ctrmsr) & pmc->ctrmask) - pmc->ctrinitval;
+ cpu->val[pmc->n].overfl = cpu->nmioverfl[pmc->n];
+
+ /* Re-enable the counter */
+ wrmsr(pmc->evtmsr, evtmsr);
}
static void
@@ -157,9 +214,14 @@
pmc_state_t *pmc = (pmc_state_t *)arg1;
bool start = (bool)arg2;
struct cpu_info *ci = curcpu();
+ pmc_cpu_t *cpu = &pmc_cpu[cpu_index(ci)];
if (start) {
- pmc_lapic_image[cpu_index(ci)] = lapic_readreg(LAPIC_PCINT);
+ cpu->lapic_image = lapic_readreg(LAPIC_PCINT);
+ cpu->val[pmc->n].ctrval = 0;
+ cpu->val[pmc->n].overfl = 0;
+ cpu->nmioverfl[pmc->n] = 0;
+
lapic_writereg(LAPIC_PCINT, LAPIC_DLMODE_NMI);
}
@@ -172,11 +234,8 @@
break;
}
- pmc_val_cpus[cpu_index(ci)].ctrval = 0;
- pmc_val_cpus[cpu_index(ci)].overfl = 0;
-
if (!start) {
- lapic_writereg(LAPIC_PCINT, pmc_lapic_image[cpu_index(ci)]);
+ lapic_writereg(LAPIC_PCINT, cpu->lapic_image);
}
}
@@ -290,6 +349,7 @@
pmc_type = PMC_TYPE_I686;
pmc_ncounters = 2;
for (i = 0; i < pmc_ncounters; i++) {
+ pmc_state[i].n = i;
pmc_state[i].evtmsr = MSR_EVNTSEL0 + i;
pmc_state[i].ctrmsr = MSR_PERFCTR0 + i;
pmc_state[i].ctrmaxval = (UINT64_C(1) << 40) - 1;
@@ -300,6 +360,7 @@
pmc_type = PMC_TYPE_F10H;
pmc_ncounters = 4;
for (i = 0; i < pmc_ncounters; i++) {
+ pmc_state[i].n = i;
pmc_state[i].evtmsr = MSR_F10H_EVNTSEL0 + i;
pmc_state[i].ctrmsr = MSR_F10H_PERFCTR0 + i;
pmc_state[i].ctrmaxval =
@@ -311,6 +372,7 @@
pmc_type = PMC_TYPE_K7;
pmc_ncounters = 4;
for (i = 0; i < pmc_ncounters; i++) {
+ pmc_state[i].n = i;
pmc_state[i].evtmsr = MSR_K7_EVNTSEL0 + i;
pmc_state[i].ctrmsr = MSR_K7_PERFCTR0 + i;
pmc_state[i].ctrmaxval =
@@ -340,6 +402,7 @@
rv.vers = PMC_VERSION;
rv.type = pmc_type;
rv.nctrs = pmc_ncounters;
+ rv.nsamp = NEVENTS_SAMPLE;
return copyout(&rv, uargs, sizeof(rv));
}
@@ -397,7 +460,8 @@
{
struct x86_pmc_read_args args;
pmc_state_t *pmc;
- size_t nval;
+ pmc_cpu_t *cpu;
+ size_t i, nval;
int error;
error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_X86PMC,
@@ -424,8 +488,16 @@
if (pmc->running) {
pmc_read(pmc);
- error = copyout(&pmc_val_cpus, args.values,
- nval * sizeof(x86_pmc_cpuval_t));
+
+ for (i = 0; i < nval; i++) {
+ cpu = &pmc_cpu[i];
+
+ error = copyout(&cpu->val[pmc->n], args.values + i,
+ sizeof(x86_pmc_cpuval_t));
+ if (error)
+ break;
+ }
+
args.nval = nval;
} else {
error = ENOENT;
diff -r 8d040eaf6f76 -r 511c3f170644 usr.bin/pmc/pmc.c
--- a/usr.bin/pmc/pmc.c Wed Jul 12 17:32:51 2017 +0000
+++ b/usr.bin/pmc/pmc.c Wed Jul 12 17:33:29 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmc.c,v 1.24 2017/06/14 17:54:01 maxv Exp $ */
+/* $NetBSD: pmc.c,v 1.25 2017/07/12 17:33:29 maxv Exp $ */
/*
* Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: pmc.c,v 1.24 2017/06/14 17:54:01 maxv Exp $");
+__RCSID("$NetBSD: pmc.c,v 1.25 2017/07/12 17:33:29 maxv Exp $");
#endif
#include <inttypes.h>
@@ -379,6 +379,7 @@
static int x86_pmc_read(x86_pmc_read_args_t *);
static uint32_t pmc_ncounters;
+static size_t pmc_nsamples;
static struct cmdtab {
const char *label;
@@ -428,6 +429,7 @@
uint32_t flags;
size_t n, i;
+ /* Get the source for each counter (kernel or userland) */
for (n = 0; n < pmc_ncounters; n++) {
if (argv[n] == NULL)
break;
@@ -437,6 +439,7 @@
usage();
}
+ /* Initialize each pmcarg structure */
for (i = 0; i < n; i++) {
Home |
Main Index |
Thread Index |
Old Index