Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Apr 2026 16:24:41 +0000
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Ali Mashtizadeh <ali@mashtizadeh.com>
Subject:   git: 70ae0c4524d2 - main - i386: Remove perfmon performance monitoring facility
Message-ID:  <69eb9949.3a5d2.72b91820@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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 ***


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69eb9949.3a5d2.72b91820>