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
This commit is contained in:
Ali Mashtizadeh
2026-04-20 15:06:30 -07:00
committed by Warner Losh
parent 576c6e9620
commit 70ae0c4524
15 changed files with 8 additions and 1120 deletions
+8
View File
@@ -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
-2
View File
@@ -346,8 +346,6 @@
..
netgraph
..
perfmon
..
pf
..
ppi
-7
View File
@@ -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"
-8
View File
@@ -1,8 +0,0 @@
PACKAGE=examples
FILESDIR=${SHAREDIR}/examples/${PROG}
PROG= perfmon
MAN=
install:
.include <bsd.prog.mk>
-23
View File
@@ -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).
-191
View File
@@ -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);
}
-1
View File
@@ -6,7 +6,6 @@ MAN= apm.4 \
npx.4 \
pae.4 \
pbio.4 \
perfmon.4 \
pnp.4 \
pnpbios.4 \
sbni.4 \
-211
View File
@@ -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.
-4
View File
@@ -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.
-1
View File
@@ -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
-6
View File
@@ -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"
-7
View File
@@ -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.
-402
View File
@@ -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;
rv = perfmon_setup(pmc->pmc_num, pmc->pmc_val);
if (!rv) {
writerpmc |= (1 << pmc->pmc_num);
}
break;
case PMIOGET:
pmc = (struct pmc *)param;
rv = perfmon_get(pmc->pmc_num, &pmc->pmc_val);
break;
case PMIOSTART:
if (!(flags & FWRITE))
return EPERM;
ip = (int *)param;
rv = perfmon_start(*ip);
break;
case PMIOSTOP:
if (!(flags & FWRITE))
return EPERM;
ip = (int *)param;
rv = perfmon_stop(*ip);
break;
case PMIORESET:
if (!(flags & FWRITE))
return EPERM;
ip = (int *)param;
rv = perfmon_reset(*ip);
break;
case PMIOREAD:
pmcd = (struct pmc_data *)param;
rv = perfmon_read(pmcd->pmcd_num, &pmcd->pmcd_value);
break;
case PMIOTSTAMP:
freq = atomic_load_acq_64(&tsc_freq);
if (freq == 0) {
rv = ENOTTY;
break;
}
pmct = (struct pmc_tstamp *)param;
/* XXX interface loses precision. */
pmct->pmct_rate = freq / 1000000;
pmct->pmct_value = rdtsc();
rv = 0;
break;
default:
rv = ENOTTY;
}
return rv;
}
-253
View File
@@ -1,253 +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.
*/
/*
* Interface to performance-monitoring counters for Intel Pentium and
* Pentium Pro CPUs.
*/
#ifndef _MACHINE_PERFMON_H_
#define _MACHINE_PERFMON_H_
#ifndef _KERNEL
#include <sys/types.h>
#endif
#include <sys/ioccom.h>
#define NPMC 2
#define PMIOSETUP _IOW('5', 1, struct pmc)
#define PMIOGET _IOWR('5', 7, struct pmc)
#define PMIOSTART _IOW('5', 2, int)
#define PMIOSTOP _IOW('5', 3, int)
#define PMIOREAD _IOWR('5', 4, struct pmc_data)
#define PMIORESET _IOW('5', 5, int)
#define PMIOTSTAMP _IOR('5', 6, struct pmc_tstamp)
struct pmc {
int pmc_num;
union {
struct {
unsigned char pmcus_event;
unsigned char pmcus_unit;
unsigned char pmcus_flags;
unsigned char pmcus_mask;
} pmcu_s;
unsigned int pmcu_val;
} pmc_pmcu;
};
#define PMC_ALL (-1)
#define pmc_event pmc_pmcu.pmcu_s.pmcus_event
#define pmc_unit pmc_pmcu.pmcu_s.pmcus_unit
#define pmc_flags pmc_pmcu.pmcu_s.pmcus_flags
#define pmc_mask pmc_pmcu.pmcu_s.pmcus_mask
#define pmc_val pmc_pmcu.pmcu_val
#define PMCF_USR 0x01 /* count events in user mode */
#define PMCF_OS 0x02 /* count events in kernel mode */
#define PMCF_E 0x04 /* use edge-detection mode */
#define PMCF_PC 0x08 /* PMx output pin control */
#define PMCF_INT 0x10 /* APIC interrupt enable (do not use) */
#define PMCF_EN 0x40 /* enable counters */
#define PMCF_INV 0x80 /* invert counter mask comparison */
#define PMCF_SYS_FLAGS (PMCF_INT | PMCF_EN) /* user cannot set */
struct pmc_data {
int pmcd_num;
quad_t pmcd_value;
};
struct pmc_tstamp {
int pmct_rate;
quad_t pmct_value;
};
#ifndef _KERNEL
#define _PATH_PERFMON "/dev/perfmon"
#else
/*
* Intra-kernel interface to performance monitoring counters
*/
void perfmon_init(void);
int perfmon_avail(void);
int perfmon_setup(int, unsigned int);
int perfmon_get(int, unsigned int *);
int perfmon_fini(int);
int perfmon_start(int);
int perfmon_stop(int);
int perfmon_read(int, quad_t *);
int perfmon_reset(int);
#endif /* _KERNEL */
/*
* Pentium Pro performance counters, from Appendix B.
*/
/* Data Cache Unit */
#define PMC6_DATA_MEM_REFS 0x43
#define PMC6_DCU_LINES_IN 0x45
#define PMC6_DCU_M_LINES_IN 0x46
#define PMC6_DCU_M_LINES_OUT 0x47
#define PMC6_DCU_MISS_OUTSTANDING 0x48
/* Instruction Fetch Unit */
#define PMC6_IFU_IFETCH 0x80
#define PMC6_IFU_IFETCH_MISS 0x81
#define PMC6_ITLB_MISS 0x85
#define PMC6_IFU_MEM_STALL 0x86
#define PMC6_ILD_STALL 0x87
/* L2 Cache */
#define PMC6_L2_IFETCH 0x28 /* MESI */
#define PMC6_L2_LD 0x29 /* MESI */
#define PMC6_L2_ST 0x2a /* MESI */
#define PMC6_L2_LINES_IN 0x24
#define PMC6_L2_LINES_OUT 0x26
#define PMC6_L2_M_LINES_INM 0x25
#define PMC6_L2_M_LINES_OUTM 0x27
#define PMC6_L2_RQSTS 0x2e /* MESI */
#define PMC6_L2_ADS 0x21
#define PMC6_L2_DBUS_BUSY 0x22
#define PMC6_L2_DBUS_BUSY_RD 0x23
/* External Bus Logic */
#define PMC6_BUS_DRDY_CLOCKS 0x62
#define PMC6_BUS_LOCK_CLOCKS 0x63
#define PMC6_BUS_REQ_OUTSTANDING 0x60
#define PMC6_BUS_TRAN_BRD 0x65
#define PMC6_BUS_TRAN_RFO 0x66
#define PMC6_BUS_TRAN_WB 0x67
#define PMC6_BUS_TRAN_IFETCH 0x68
#define PMC6_BUS_TRAN_INVAL 0x69
#define PMC6_BUS_TRAN_PWR 0x6a
#define PMC6_BUS_TRAN_P 0x6b
#define PMC6_BUS_TRAN_IO 0x6c
#define PMC6_BUS_TRAN_DEF 0x6d
#define PMC6_BUS_TRAN_BURST 0x6e
#define PMC6_BUS_TRAN_ANY 0x70
#define PMC6_BUS_TRAN_MEM 0x6f
#define PMC6_BUS_DATA_RCV 0x64
#define PMC6_BUS_BNR_DRV 0x61
#define PMC6_BUS_HIT_DRV 0x7a
#define PMC6_BUS_HITM_DRV 0x7b
#define PMC6_BUS_SNOOP_STALL 0x7e
/* Floating Point Unit */
#define PMC6_FLOPS 0xc1 /* counter 0 only */
#define PMC6_FP_COMP_OPS_EXE 0x10 /* counter 0 only */
#define PMC6_FP_ASSIST 0x11 /* counter 1 only */
#define PMC6_MUL 0x12 /* counter 1 only */
#define PMC6_DIV 0x13 /* counter 1 only */
#define PMC6_CYCLES_DIV_BUSY 0x14 /* counter 0 only */
/* Memory Ordering */
#define PMC6_LD_BLOCKS 0x03
#define PMC6_SB_DRAINS 0x04
#define PMC6_MISALIGN_MEM_REF 0x05
/* Instruction Decoding and Retirement */
#define PMC6_INST_RETIRED 0xc0
#define PMC6_UOPS_RETIRED 0xc2
#define PMC6_INST_DECODER 0xd0 /* (sic) */
/* Interrupts */
#define PMC6_HW_INT_RX 0xc8
#define PMC6_CYCLES_INT_MASKED 0xc6
#define PMC6_CYCLES_INT_PENDING_AND_MASKED 0xc7
/* Branches */
#define PMC6_BR_INST_RETIRED 0xc4
#define PMC6_BR_MISS_PRED_RETIRED 0xc5
#define PMC6_BR_TAKEN_RETIRED 0xc9
#define PMC6_BR_MISS_PRED_TAKEN_RET 0xca
#define PMC6_BR_INST_DECODED 0xe0
#define PMC6_BTB_MISSES 0xe2
#define PMC6_BR_BOGUS 0xe4
#define PMC6_BACLEARS 0xe6
/* Stalls */
#define PMC6_RESOURCE_STALLS 0xa2
#define PMC6_PARTIAL_RAT_STALLS 0xd2
/* Segment Register Loads */
#define PMC6_SEGMENT_REG_LOADS 0x06
/* Clocks */
#define PMC6_CPU_CLK_UNHALTED 0x79
/*
* Pentium Performance Counters
* This list comes from the Harvard people, not Intel.
*/
#define PMC5_DATA_READ 0
#define PMC5_DATA_WRITE 1
#define PMC5_DATA_TLB_MISS 2
#define PMC5_DATA_READ_MISS 3
#define PMC5_DATA_WRITE_MISS 4
#define PMC5_WRITE_M_E 5
#define PMC5_DATA_LINES_WBACK 6
#define PMC5_DATA_CACHE_SNOOP 7
#define PMC5_DATA_CACHE_SNOOP_HIT 8
#define PMC5_MEM_ACCESS_BOTH 9
#define PMC5_BANK_CONFLICTS 10
#define PMC5_MISALIGNED_DATA 11
#define PMC5_INST_READ 12
#define PMC5_INST_TLB_MISS 13
#define PMC5_INST_CACHE_MISS 14
#define PMC5_SEGMENT_REG_LOAD 15
#define PMC5_BRANCHES 18
#define PMC5_BTB_HITS 19
#define PMC5_BRANCH_TAKEN 20
#define PMC5_PIPELINE_FLUSH 21
#define PMC5_INST_EXECUTED 22
#define PMC5_INST_EXECUTED_V 23
#define PMC5_BUS_UTILIZATION 24
#define PMC5_WRITE_BACKUP_STALL 25
#define PMC5_DATA_READ_STALL 26
#define PMC5_WRITE_E_M_STALL 27
#define PMC5_LOCKED_BUS 28
#define PMC5_IO_CYCLE 29
#define PMC5_NONCACHE_MEMORY 30
#define PMC5_ADDR_GEN_INTERLOCK 31
#define PMC5_FLOPS 34
#define PMC5_BP0_MATCH 35
#define PMC5_BP1_MATCH 36
#define PMC5_BP2_MATCH 37
#define PMC5_BP3_MATCH 38
#define PMC5_HW_INTR 39
#define PMC5_DATA_RW 40
#define PMC5_DATA_RW_MISS 41
#endif /* !_MACHINE_PERFMON_H_ */
-4
View File
@@ -1822,9 +1822,6 @@ OLD_FILES+=usr/share/examples/netgraph/virtual.chain
OLD_FILES+=usr/share/examples/netgraph/virtual.lan
OLD_FILES+=usr/share/examples/oci/Containerfile.pkg
OLD_FILES+=usr/share/examples/oci/README
OLD_FILES+=usr/share/examples/perfmon/Makefile
OLD_FILES+=usr/share/examples/perfmon/README
OLD_FILES+=usr/share/examples/perfmon/perfmon.c
OLD_FILES+=usr/share/examples/pf/ackpri
OLD_FILES+=usr/share/examples/pf/faq-example1
OLD_FILES+=usr/share/examples/pf/faq-example2
@@ -1991,7 +1988,6 @@ OLD_DIRS+=usr/share/examples/libvgl
OLD_DIRS+=usr/share/examples/mdoc
OLD_DIRS+=usr/share/examples/netgraph
OLD_DIRS+=usr/share/examples/oci
OLD_DIRS+=usr/share/examples/perfmon
OLD_DIRS+=usr/share/examples/pf
OLD_DIRS+=usr/share/examples/ppi
OLD_DIRS+=usr/share/examples/ppp