git: 70ae0c4524d2 - main - i386: Remove perfmon performance monitoring facility
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 24 Apr 2026 16:24:41 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=70ae0c4524d2c5d0aae3339e95f6bd4f3c480b6e
commit 70ae0c4524d2c5d0aae3339e95f6bd4f3c480b6e
Author: Ali Mashtizadeh <ali@mashtizadeh.com>
AuthorDate: 2026-04-20 22:06:30 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-04-24 16:23:05 +0000
i386: Remove perfmon performance monitoring facility
Remove the perfmon performance monitoring facility that was for Intel
Pentium and Pentium Pro processors.
Reviewed by: imp,mhorne,emaste
Pull Request: https://github.com/freebsd/freebsd-src/pull/2155
---
ObsoleteFiles.inc | 8 +
etc/mtree/BSD.usr.dist | 2 -
share/examples/Makefile | 7 -
share/examples/perfmon/Makefile | 8 -
share/examples/perfmon/README | 23 --
share/examples/perfmon/perfmon.c | 191 ---------------
share/man/man4/man4.i386/Makefile | 1 -
share/man/man4/man4.i386/perfmon.4 | 211 ----------------
share/man/man7/clocks.7 | 4 -
sys/conf/files.i386 | 1 -
sys/i386/conf/NOTES | 6 -
sys/i386/i386/machdep.c | 7 -
sys/i386/i386/perfmon.c | 402 -------------------------------
sys/i386/include/perfmon.h | 253 -------------------
tools/build/mk/OptionalObsoleteFiles.inc | 4 -
15 files changed, 8 insertions(+), 1120 deletions(-)
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index a4fdac95bf5a..465508bf40a3 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,14 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20260420: remove perfmon
+OLD_FILES+=boot/kernel/perfmon.ko
+OLD_FILES+=usr/share/man/man4/perfmon.4.gz
+OLD_FILES+=usr/share/examples/perfmon/Makefile
+OLD_FILES+=usr/share/examples/perfmon/README
+OLD_FILES+=usr/share/examples/perfmon/perfmon.c
+OLD_DIRS+=usr/share/examples/perfmon
+
# 20260402: posix_spawn_file_actions_addchdir lost _np suffix
OLD_FILES+=usr/share/man/man3/posix_spawn_file_actions_addchdir_np.3.gz
OLD_FILES+=usr/share/man/man3/posix_spawn_file_actions_addfchdir_np.3.gz
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index b281a368861d..120b961d230c 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -346,8 +346,6 @@
..
netgraph
..
- perfmon
- ..
pf
..
ppi
diff --git a/share/examples/Makefile b/share/examples/Makefile
index d977f2e5a0da..dae84f27d9dc 100644
--- a/share/examples/Makefile
+++ b/share/examples/Makefile
@@ -22,7 +22,6 @@ LDIRS= BSD_daemon \
mdoc \
netgraph \
oci \
- perfmon \
ppi \
ppp \
ses \
@@ -202,12 +201,6 @@ SE_OCI= \
README \
Containerfile.pkg
-SE_DIRS+= perfmon
-SE_PERFMON= \
- Makefile \
- README \
- perfmon.c \
-
.if ${MK_PF} != "no"
SE_DIRS+= pf
.if ${MK_STAGING} == "no"
diff --git a/share/examples/perfmon/Makefile b/share/examples/perfmon/Makefile
deleted file mode 100644
index 96712dee88e3..000000000000
--- a/share/examples/perfmon/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-PACKAGE=examples
-FILESDIR=${SHAREDIR}/examples/${PROG}
-PROG= perfmon
-MAN=
-
-install:
-
-.include <bsd.prog.mk>
diff --git a/share/examples/perfmon/README b/share/examples/perfmon/README
deleted file mode 100644
index 25452813f3db..000000000000
--- a/share/examples/perfmon/README
+++ /dev/null
@@ -1,23 +0,0 @@
-`perfmon' is a sample program to access the performance-monitoring
-counters on Pentium and Pentium Pro CPUs. See perfmon(4) for a
-description of this facility.
-
-The program takes the following options:
-
- -u count events in user mode
- -o count events in kernel mode
- (these two can be combined)
-
- -e count events, not duration
- -l n run `n' loops (default 50)
- -s n sleep `n' seconds between loop iterations (default 0)
-
-The following options are not implemented on Pentium CPUs:
-
- -m n use count mask `n'
- -i invert sense of count mask comparison
- -U n use unit mask `n'
-
-There is one mandatory argument, which is the event number to be
-monitored, defined in <machine/perfmon.h>. All numbers can be
-specified in any format acceptable to strtol(3).
diff --git a/share/examples/perfmon/perfmon.c b/share/examples/perfmon/perfmon.c
deleted file mode 100644
index 1b7afad9d69e..000000000000
--- a/share/examples/perfmon/perfmon.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 1996 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that both the above copyright notice and this
- * permission notice appear in all copies, that both the above
- * copyright notice and this permission notice appear in all
- * supporting documentation, and that the name of M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission. M.I.T. makes
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied
- * warranty.
- *
- * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
- * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
- * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-
-#include <machine/cpu.h>
-#include <machine/perfmon.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <err.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <errno.h>
-
-static int getnum(const char *, int, int);
-static void usage(const char *) __dead2;
-
-int
-main(int argc, char **argv)
-{
- int c, fd, num;
- int loops, i, sleeptime;
- char *cmd;
- struct pmc pmc;
- struct pmc_tstamp then, now;
- struct pmc_data value;
- quad_t *buf;
- double total;
-
- pmc.pmc_num = 0;
- pmc.pmc_event = 0;
- pmc.pmc_unit = 0;
- pmc.pmc_flags = 0;
- pmc.pmc_mask = 0;
- cmd = NULL;
- loops = 50;
- sleeptime = 0;
-
- while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) {
- switch(c) {
- case 'u':
- pmc.pmc_flags |= PMCF_USR;
- break;
- case 'o':
- pmc.pmc_flags |= PMCF_OS;
- break;
- case 'e':
- pmc.pmc_flags |= PMCF_E;
- break;
- case 'i':
- pmc.pmc_flags |= PMCF_INV;
- break;
- case 'U':
- pmc.pmc_unit = getnum(optarg, 0, 256);
- break;
- case 'm':
- pmc.pmc_mask = getnum(optarg, 0, 256);
- break;
- case 'l':
- loops = getnum(optarg, 1, INT_MAX - 1);
- break;
- case 's':
- sleeptime = getnum(optarg, 0, INT_MAX - 1);
- break;
- case 'c':
- cmd = optarg;
- break;
- default:
- usage(argv[0]);
- }
- }
-
- if (argc - optind != 1)
- usage(argv[0]);
-
- pmc.pmc_event = getnum(argv[optind], 0, 255);
-
- buf = malloc((loops + 1) * sizeof *buf);
- if (!buf)
- err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
-
- fd = open(_PATH_PERFMON, O_RDWR, 0);
- if (fd < 0)
- err(1, "open: " _PATH_PERFMON);
-
- if (ioctl(fd, PMIOSETUP, &pmc) < 0)
- err(1, "ioctl(PMIOSETUP)");
-
- if (ioctl(fd, PMIOTSTAMP, &then) < 0)
- err(1, "ioctl(PMIOTSTAMP)");
-
- num = 0;
- if (ioctl(fd, PMIOSTART, &num) < 0)
- err(1, "ioctl(PMIOSTART)");
-
- value.pmcd_num = 0;
- for (i = 0; i < loops; i++) {
- if (ioctl(fd, PMIOSTOP, &num) < 0)
- err(1, "ioctl(PMIOSTOP)");
- if (ioctl(fd, PMIOREAD, &value) < 0)
- err(1, "ioctl(PMIOREAD)");
- buf[i] = value.pmcd_value;
- if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
- err(1, "ioctl(PMIORESET)");
- if (ioctl(fd, PMIOSTART, &num) < 0)
- err(1, "ioctl(PMIOSTART)");
- if (sleeptime)
- sleep(sleeptime);
- if (cmd)
- system(cmd);
- }
-
- if (ioctl(fd, PMIOSTOP, &num) < 0)
- err(1, "ioctl(PMIOSTOP)");
- if (ioctl(fd, PMIOREAD, &value) < 0)
- err(1, "ioctl(PMIOREAD)");
- buf[i] = value.pmcd_value;
- if (ioctl(fd, PMIOTSTAMP, &now) < 0)
- err(1, "ioctl(PMIOTSTAMP)");
-
- total = 0;
- for (i = 1; i <= loops; i++) {
- printf("%d: %qd\n", i, buf[i]);
- total += buf[i];
- }
- printf("total: %f\nmean: %f\n", total, total / loops);
-
- printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
- now.pmct_value - then.pmct_value);
-
- return 0;
-}
-
-static int
-getnum(const char *buf, int min, int max)
-{
- char *ep;
- long l;
-
- errno = 0;
- l = strtol(buf, &ep, 0);
- if (*buf && !*ep && !errno) {
- if (l < min || l > max) {
- errx(1, "%s: must be between %d and %d",
- buf, min, max);
- }
- return (int)l;
- }
-
- errx(1, "%s: parameter must be an integer", buf);
-}
-
-static void
-usage(const char *pname)
-{
- fprintf(stderr,
- "usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n"
- " [-U unit] counter\n",
- pname);
- exit(1);
-}
diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile
index ad9b3a01828c..1136de341947 100644
--- a/share/man/man4/man4.i386/Makefile
+++ b/share/man/man4/man4.i386/Makefile
@@ -6,7 +6,6 @@ MAN= apm.4 \
npx.4 \
pae.4 \
pbio.4 \
- perfmon.4 \
pnp.4 \
pnpbios.4 \
sbni.4 \
diff --git a/share/man/man4/man4.i386/perfmon.4 b/share/man/man4/man4.i386/perfmon.4
deleted file mode 100644
index 7a899e863f1b..000000000000
--- a/share/man/man4/man4.i386/perfmon.4
+++ /dev/null
@@ -1,211 +0,0 @@
-.\"
-.\" Copyright 1996 Massachusetts Institute of Technology
-.\"
-.\" Permission to use, copy, modify, and distribute this software and
-.\" its documentation for any purpose and without fee is hereby
-.\" granted, provided that both the above copyright notice and this
-.\" permission notice appear in all copies, that both the above
-.\" copyright notice and this permission notice appear in all
-.\" supporting documentation, and that the name of M.I.T. not be used
-.\" in advertising or publicity pertaining to distribution of the
-.\" software without specific, written prior permission. M.I.T. makes
-.\" no representations about the suitability of this software for any
-.\" purpose. It is provided "as is" without express or implied
-.\" warranty.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
-.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
-.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.Dd March 26, 1996
-.Dt PERFMON 4 i386
-.Os
-.Sh NAME
-.Nm perfmon
-.Nd CPU performance-monitoring interface
-.Sh SYNOPSIS
-.Cd cpu I586_CPU
-.Cd cpu I686_CPU
-.Cd options PERFMON
-.Sh DESCRIPTION
-The
-.Nm
-driver provides access to the internal performance-monitoring
-capabilities of the
-.Tn Intel
-.Tn Pentium
-and
-.Tn "Pentium Pro"
-CPUs.
-These processors implement two internal counters which can be
-configured to measure a variety of events for either count or duration
-(in CPU cycles), as well as a cycle counter which counts clock cycles.
-The
-.Nm
-driver provides a device-style interface to these capabilities.
-.Pp
-All access to the performance-monitoring counters is performed through
-the special device file
-.Dq Pa /dev/perfmon .
-This device supports a number of
-.Xr ioctl 2
-requests, defined in
-.In machine/perfmon.h
-along with the definitions of the various counters for both
-.Tn Pentium
-and
-.Tn "Pentium Pro"
-processors.
-.Pp
-.Sy NOTA BENE :
-The set of available events differs from processor to processor.
-It
-is the responsibility of the programmer to ensure that the event
-numbers used are the correct ones for the CPU type being measured.
-.Pp
-The following
-.Xr ioctl 2
-requests are defined:
-.Bl -tag -width PMIOTSTAMP
-.It Dv PMIOSETUP
-.Pq Li "struct pmc"
-Set up a counter with parameters and flags defined in the structure.
-The following fields are defined in
-.Li struct pmc :
-.Bl -tag -width "u_char pmc_eventx"
-.It Li "int pmc_num"
-the number of the counter in question; must be less than
-.Dv NPMC
-(currently 2).
-.It Li "u_char pmc_event"
-the particular event number to be monitored, as defined in
-.In machine/perfmon.h .
-.It Li "u_char pmc_unit"
-the unit mask value, specific to the event type (see the
-.Tn Intel
-documentation).
-.It Li "u_char pmc_flags"
-flags modifying the operation of the counter (see below).
-.It Li "u_char pmc_mask"
-the counter mask value; essentially, this is a threshold used to
-restrict the count to events lasting more (or less) than the specified
-number of clocks.
-.El
-.Pp
-The following
-.Li pmc_flags
-values are defined:
-.Bl -tag -compact -width PMCF_USRxx
-.It Dv PMCF_USR
-count events in user mode
-.It Dv PMCF_OS
-count events in kernel mode
-.It Dv PMCF_E
-count number of events rather than their duration
-.It Dv PMCF_INV
-invert the sense of the counter mask comparison
-.El
-.It Dv PMIOGET
-.Pq Li "struct pmc"
-returns the current configuration of the specified counter.
-.It Dv PMIOSTART
-.It Dv PMIOSTOP
-.Pq Li int
-starts (stops) the specified counter.
-Due to hardware deficiencies,
-counters must be started and stopped in numerical order.
-(That is to
-say, counter 0 can never be stopped without first stopping counter 1.)
-The driver will
-.Em not
-enforce this restriction (since it may not be present in future CPUs).
-.It Dv PMIORESET
-.Pq Li int
-reset the specified counter to zero.
-The counter should be stopped
-with
-.Dv PMIOSTOP
-before it is reset.
-All counters are automatically reset by
-.Dv PMIOSETUP .
-.It Dv PMIOREAD
-.Pq Li "struct pmc_data"
-get the current value of the counter.
-The
-.Li pmc_data
-structure defines two fields:
-.Pp
-.Bl -tag -compact -width "quad_t pmcd_value"
-.It Li "int pmcd_num"
-the number of the counter to read
-.It Li "quad_t pmcd_value"
-the resulting value as a 64-bit signed integer
-.El
-.Pp
-In the future, it may be possible to use the
-.Li RDPMC
-instruction on
-.Tn "Pentium Pro"
-processors to read the counters directly.
-.It Dv PMIOTSTAMP
-.Pq Li "struct pmc_tstamp"
-read the time stamp counter.
-The
-.Li pmc_tstamp
-structure defines two fields:
-.Pp
-.Bl -tag -compact -width "quad_t pmct_value"
-.It Li "int pmct_rate"
-the approximate rate of the counter, in MHz
-.It Li "quad_t pmct_value"
-the current value of the counter as a 64-bit integer
-.El
-.Pp
-It is important to note that the counter rate, as provided in the
-.Li pmct_rate
-field, is often incorrect because of calibration difficulties and
-non-integral clock rates.
-This field should be considered more of a
-hint or sanity-check than an actual representation of the rate of
-clock ticks.
-.El
-.Sh FILES
-.Bl -tag -compact -width "/usr/include/machine/perfmon.h"
-.It Pa /dev/perfmon
-character device interface to counters
-.It Pa /usr/include/machine/perfmon.h
-include file with definitions of structures and event types
-.It Pa /usr/share/examples/perfmon
-sample source code demonstrating use of all the
-.Fn ioctl
-commands
-.El
-.Sh SEE ALSO
-.Xr ioctl 2 ,
-.Xr hwpmc 4
-.Rs
-.%A Intel Corporation
-.%B Pentium Pro Family Developer's Manual
-.%D January 1996
-.%V vol. 3
-.%O Operating System Writer's Manual
-.Re
-.Sh HISTORY
-The
-.Nm
-device first appeared in
-.Fx 2.2 .
-.Sh AUTHORS
-The
-.Nm
-driver was written by
-.An Garrett A. Wollman ,
-MIT Laboratory for Computer Science.
diff --git a/share/man/man7/clocks.7 b/share/man/man7/clocks.7
index 3a218f844450..26283909f06d 100644
--- a/share/man/man7/clocks.7
+++ b/share/man/man7/clocks.7
@@ -141,10 +141,6 @@ Its frequency can be found using the
.Va machdep.tsc_freq
sysctl, if it is available.
It is used to interpolate between values of the scheduling clock.
-It can be accessed using the
-.Dv PMIOTSTAMP
-request of
-.Xr perfmon 4 .
.It
The ACPI clock.
This is a real clock/timer with a nominal frequency of 3579545.
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index e6c2089e2c1e..0e7a1f24be7e 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -91,7 +91,6 @@ i386/i386/mp_clock.c optional smp
i386/i386/mp_machdep.c optional smp
i386/i386/mpboot.S optional smp
i386/i386/npx.c standard
-i386/i386/perfmon.c optional perfmon
i386/i386/pmap_base.c standard
i386/i386/pmap_nopae.c standard
i386/i386/pmap_pae.c standard
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index fbcea76527db..25bfb99c1fef 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -177,12 +177,6 @@ options CYRIX_CACHE_REALLY_WORKS
# Debug options
options NPX_DEBUG # enable npx debugging
-#
-# PERFMON causes the driver for Pentium/Pentium Pro performance counters
-# to be compiled. See perfmon(4) for more information.
-#
-options PERFMON
-
#
# Hints for the non-optional Numeric Processing eXtension driver.
envvar hint.npx.0.flags="0x0"
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 7dbaded419e6..f9afb9afe45f 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -50,7 +50,6 @@
#include "opt_isa.h"
#include "opt_kstack_pages.h"
#include "opt_maxmem.h"
-#include "opt_perfmon.h"
#include "opt_platform.h"
#include <sys/param.h>
@@ -133,9 +132,6 @@
#include <x86/ucode.h>
#include <machine/vm86.h>
#include <x86/init.h>
-#ifdef PERFMON
-#include <machine/perfmon.h>
-#endif
#ifdef SMP
#include <machine/smp.h>
#endif
@@ -245,9 +241,6 @@ cpu_startup(void *dummy)
startrtclock();
printcpuinfo();
panicifcpuunsupported();
-#ifdef PERFMON
- perfmon_init();
-#endif
/*
* Display physical memory if SMBIOS reports reasonable amount.
diff --git a/sys/i386/i386/perfmon.c b/sys/i386/i386/perfmon.c
deleted file mode 100644
index 5e6d37d7f5ed..000000000000
--- a/sys/i386/i386/perfmon.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*-
- * Copyright 1996 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that both the above copyright notice and this
- * permission notice appear in all copies, that both the above
- * copyright notice and this permission notice appear in all
- * supporting documentation, and that the name of M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission. M.I.T. makes
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied
- * warranty.
- *
- * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
- * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
- * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/kernel.h>
-
-#ifndef SMP
-#include <machine/cputypes.h>
-#endif
-#include <machine/clock.h>
-#include <machine/perfmon.h>
-#include <machine/specialreg.h>
-
-static int perfmon_inuse;
-static int perfmon_cpuok;
-#ifndef SMP
-static int msr_ctl[NPMC];
-#endif
-static int msr_pmc[NPMC];
-static unsigned int ctl_shadow[NPMC];
-static quad_t pmc_shadow[NPMC]; /* used when ctr is stopped on P5 */
-static int (*writectl)(int);
-#ifndef SMP
-static int writectl5(int);
-static int writectl6(int);
-#endif
-
-static d_close_t perfmon_close;
-static d_open_t perfmon_open;
-static d_ioctl_t perfmon_ioctl;
-
-/*
- * XXX perfmon_init_dev(void *) is a split from the perfmon_init() function.
- * This solves a problem for DEVFS users. It loads the "perfmon" driver after
- * the DEVFS subsystem has been kicked into action. The SI_ORDER_ANY is to
- * assure that it is the most lowest priority task which, guarantees the
- * above.
- */
-static void perfmon_init_dev(void *);
-SYSINIT(cpu, SI_SUB_DRIVERS, SI_ORDER_ANY, perfmon_init_dev, NULL);
-
-static struct cdevsw perfmon_cdevsw = {
- .d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
- .d_open = perfmon_open,
- .d_close = perfmon_close,
- .d_ioctl = perfmon_ioctl,
- .d_name = "perfmon",
-};
-
-/*
- * Must be called after cpu_class is set up.
- */
-void
-perfmon_init(void)
-{
-#ifndef SMP
- switch(cpu_class) {
- case CPUCLASS_586:
- perfmon_cpuok = 1;
- msr_ctl[0] = MSR_P5_CESR;
- msr_ctl[1] = MSR_P5_CESR;
- msr_pmc[0] = MSR_P5_CTR0;
- msr_pmc[1] = MSR_P5_CTR1;
- writectl = writectl5;
- break;
- case CPUCLASS_686:
- perfmon_cpuok = 1;
- msr_ctl[0] = MSR_EVNTSEL0;
- msr_ctl[1] = MSR_EVNTSEL1;
- msr_pmc[0] = MSR_PERFCTR0;
- msr_pmc[1] = MSR_PERFCTR1;
- writectl = writectl6;
- break;
-
- default:
- perfmon_cpuok = 0;
- break;
- }
-#endif /* SMP */
-}
-
-static void
-perfmon_init_dev(void *dummy)
-{
- make_dev(&perfmon_cdevsw, 32, UID_ROOT, GID_KMEM, 0640, "perfmon");
-}
-
-int
-perfmon_avail(void)
-{
- return perfmon_cpuok;
-}
-
-int
-perfmon_setup(int pmc, unsigned int control)
-{
- register_t saveintr;
-
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- perfmon_inuse |= (1 << pmc);
- control &= ~(PMCF_SYS_FLAGS << 16);
- saveintr = intr_disable();
- ctl_shadow[pmc] = control;
- writectl(pmc);
- wrmsr(msr_pmc[pmc], pmc_shadow[pmc] = 0);
- intr_restore(saveintr);
- return 0;
-}
-
-int
-perfmon_get(int pmc, unsigned int *control)
-{
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- *control = ctl_shadow[pmc];
- return 0;
- }
- return EBUSY; /* XXX reversed sense */
-}
-
-int
-perfmon_fini(int pmc)
-{
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- perfmon_stop(pmc);
- ctl_shadow[pmc] = 0;
- perfmon_inuse &= ~(1 << pmc);
- return 0;
- }
- return EBUSY; /* XXX reversed sense */
-}
-
-int
-perfmon_start(int pmc)
-{
- register_t saveintr;
-
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- saveintr = intr_disable();
- ctl_shadow[pmc] |= (PMCF_EN << 16);
- wrmsr(msr_pmc[pmc], pmc_shadow[pmc]);
- writectl(pmc);
- intr_restore(saveintr);
- return 0;
- }
- return EBUSY;
-}
-
-int
-perfmon_stop(int pmc)
-{
- register_t saveintr;
-
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- saveintr = intr_disable();
- pmc_shadow[pmc] = rdmsr(msr_pmc[pmc]) & 0xffffffffffULL;
- ctl_shadow[pmc] &= ~(PMCF_EN << 16);
- writectl(pmc);
- intr_restore(saveintr);
- return 0;
- }
- return EBUSY;
-}
-
-int
-perfmon_read(int pmc, quad_t *val)
-{
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- if (ctl_shadow[pmc] & (PMCF_EN << 16))
- *val = rdmsr(msr_pmc[pmc]) & 0xffffffffffULL;
- else
- *val = pmc_shadow[pmc];
- return 0;
- }
-
- return EBUSY;
-}
-
-int
-perfmon_reset(int pmc)
-{
- if (pmc < 0 || pmc >= NPMC)
- return EINVAL;
-
- if (perfmon_inuse & (1 << pmc)) {
- wrmsr(msr_pmc[pmc], pmc_shadow[pmc] = 0);
- return 0;
- }
- return EBUSY;
-}
-
-#ifndef SMP
-/*
- * Unfortunately, the performance-monitoring registers are laid out
- * differently in the P5 and P6. We keep everything in P6 format
- * internally (except for the event code), and convert to P5
- * format as needed on those CPUs. The writectl function pointer
- * is set up to point to one of these functions by perfmon_init().
- */
-int
-writectl6(int pmc)
-{
- if (pmc > 0 && !(ctl_shadow[pmc] & (PMCF_EN << 16))) {
- wrmsr(msr_ctl[pmc], 0);
- } else {
- wrmsr(msr_ctl[pmc], ctl_shadow[pmc]);
- }
- return 0;
-}
-
-#define P5FLAG_P 0x200
-#define P5FLAG_E 0x100
-#define P5FLAG_USR 0x80
-#define P5FLAG_OS 0x40
-
-int
-writectl5(int pmc)
-{
- quad_t newval = 0;
-
- if (ctl_shadow[1] & (PMCF_EN << 16)) {
- if (ctl_shadow[1] & (PMCF_USR << 16))
- newval |= P5FLAG_USR << 16;
- if (ctl_shadow[1] & (PMCF_OS << 16))
- newval |= P5FLAG_OS << 16;
- if (!(ctl_shadow[1] & (PMCF_E << 16)))
- newval |= P5FLAG_E << 16;
- newval |= (ctl_shadow[1] & 0x3f) << 16;
- }
- if (ctl_shadow[0] & (PMCF_EN << 16)) {
- if (ctl_shadow[0] & (PMCF_USR << 16))
- newval |= P5FLAG_USR;
- if (ctl_shadow[0] & (PMCF_OS << 16))
- newval |= P5FLAG_OS;
- if (!(ctl_shadow[0] & (PMCF_E << 16)))
- newval |= P5FLAG_E;
- newval |= ctl_shadow[0] & 0x3f;
- }
-
- wrmsr(msr_ctl[0], newval);
- return 0; /* XXX should check for unimplemented bits */
-}
-#endif /* !SMP */
-
-/*
- * Now the user-mode interface, called from a subdevice of mem.c.
- */
-static int writer;
-static int writerpmc;
-
-static int
-perfmon_open(struct cdev *dev, int flags, int fmt, struct thread *td)
-{
- if (!perfmon_cpuok)
- return ENXIO;
-
- if (flags & FWRITE) {
- if (writer) {
- return EBUSY;
- } else {
- writer = 1;
- writerpmc = 0;
- }
- }
- return 0;
-}
-
-static int
-perfmon_close(struct cdev *dev, int flags, int fmt, struct thread *td)
-{
- if (flags & FWRITE) {
- int i;
-
- for (i = 0; i < NPMC; i++) {
- if (writerpmc & (1 << i))
- perfmon_fini(i);
- }
- writer = 0;
- }
- return 0;
-}
-
-static int
-perfmon_ioctl(struct cdev *dev, u_long cmd, caddr_t param, int flags, struct thread *td)
-{
- struct pmc *pmc;
- struct pmc_data *pmcd;
- struct pmc_tstamp *pmct;
- uint64_t freq;
- int *ip;
- int rv;
-
- switch(cmd) {
- case PMIOSETUP:
- if (!(flags & FWRITE))
- return EPERM;
- pmc = (struct pmc *)param;
*** 340 LINES SKIPPED ***