summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/etc.i386/MAKEDEV11
-rw-r--r--sys/arch/i386/conf/files.i3866
-rw-r--r--sys/arch/i386/i386/conf.c5
-rw-r--r--sys/arch/i386/i386/locore.s14
-rw-r--r--sys/arch/i386/i386/microtime.s13
-rw-r--r--sys/arch/i386/i386/pctr.c123
-rw-r--r--sys/arch/i386/include/cpu.h40
-rw-r--r--sys/arch/i386/include/pctr.h34
-rw-r--r--usr.bin/Makefile6
-rw-r--r--usr.bin/pctrctl/Makefile7
-rw-r--r--usr.bin/pctrctl/pctrctl.c198
11 files changed, 425 insertions, 32 deletions
diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV
index dd95cc80781..2e0f26e030f 100644
--- a/etc/etc.i386/MAKEDEV
+++ b/etc/etc.i386/MAKEDEV
@@ -1,6 +1,6 @@
#!/bin/sh -
#
-# $OpenBSD: MAKEDEV,v 1.15 1996/07/23 06:32:55 etheisen Exp $
+# $OpenBSD: MAKEDEV,v 1.16 1996/08/08 18:47:15 dm Exp $
# $NetBSD: MAKEDEV,v 1.40 1996/03/31 00:50:47 perry Exp $
#
# Copyright (c) 1990 The Regents of the University of California.
@@ -95,7 +95,7 @@ all)
sh MAKEDEV mcd0 acd0 vnd0 vnd1 lpa0 lpa1 ccd0 ccd1 ccd2 ccd3
sh MAKEDEV lpt0 lpt1 lpt2 ttyv0 bpf0 bpf1 bpf2 bpf3 ipl tun0 tun1 tun2
sh MAKEDEV speaker lkm mms0 lms0 pms0 audio joy0 joy1 apm pcmcia local
- sh MAKEDEV rnd uk0 uk1
+ sh MAKEDEV rnd uk0 uk1 pctr
# MISSING:
# sh MAKEDEV mouse-?
;;
@@ -447,6 +447,13 @@ uk*)
chown root.operator uk$unit
chmod 640 uk$unit
;;
+
+pctr)
+ rm -f pctr;
+ mknod pctr c 46 0
+ chown root.wheel pctr
+ chmod 0644 pctr
+ ;;
local)
umask 0
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index c285061d812..d7350735095 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.22 1996/07/28 05:07:04 downsj Exp $
+# $OpenBSD: files.i386,v 1.23 1996/08/08 18:47:13 dm Exp $
# $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $
#
# new style config file for i386 architecture
@@ -167,6 +167,10 @@ device joy
attach joy at isa
file arch/i386/isa/joy.c joy needs-flag
+# Pentium performance counters
+pseudo-device pctr
+file arch/i386/i386/pctr.c pctr needs-flag
+
#
# EISA-only drivers
#
diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c
index 7e88c0d1d3d..53d4b57cc9d 100644
--- a/sys/arch/i386/i386/conf.c
+++ b/sys/arch/i386/i386/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.20 1996/07/28 05:07:05 downsj Exp $ */
+/* $OpenBSD: conf.c,v 1.21 1996/08/08 18:47:10 dm Exp $ */
/* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */
/*
@@ -187,6 +187,8 @@ cdev_decl(joy);
cdev_decl(apm);
#include "rnd.h"
cdev_decl(rnd);
+#include "pctr.h"
+cdev_decl(pctr);
cdev_decl(ipl);
#ifdef IPFILTER
@@ -256,6 +258,7 @@ struct cdevsw cdevsw[] =
#endif
cdev_gen_ipf(NIPF,ipl), /* 44 ip filtering */
cdev_rnd_init(NRND,rnd), /* 45 random data source */
+ cdev_uk_init(NPCTR,pctr), /* 46: pentium performance counters */
};
int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s
index 756110246d9..88cfc64db8c 100644
--- a/sys/arch/i386/i386/locore.s
+++ b/sys/arch/i386/i386/locore.s
@@ -42,6 +42,7 @@
#include "npx.h"
#include "assym.h"
#include "apm.h"
+#include "pctr.h"
#include <sys/errno.h>
#include <sys/syscall.h>
@@ -1636,14 +1637,19 @@ ENTRY(idle)
sti
#if NAPM > 0
call _apm_cpu_idle
-#endif
hlt
-#if NAPM > 0
cmpl $0,_apm_dobusy
je 1f
call _apm_cpu_busy
-1:
-#endif
+1:
+#else /* NAPM == 0 */
+#if NPCTR > 0
+ addl $1,_pctr_idlcnt
+ adcl $0,_pctr_idlcnt+4
+#else /* NPCTR == 0 */
+ hlt
+#endif /* NPCTR == 0 */
+#endif /* NAPM == 0 */
jmp _idle
#ifdef DIAGNOSTIC
diff --git a/sys/arch/i386/i386/microtime.s b/sys/arch/i386/i386/microtime.s
index eca576bf46c..05cf6c53fde 100644
--- a/sys/arch/i386/i386/microtime.s
+++ b/sys/arch/i386/i386/microtime.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: microtime.s,v 1.7 1996/04/29 00:42:25 mickey Exp $ */
+/* $OpenBSD: microtime.s,v 1.8 1996/08/08 18:47:11 dm Exp $ */
/* $NetBSD: microtime.s,v 1.16 1995/04/17 12:06:47 cgd Exp $ */
/*-
@@ -138,13 +138,22 @@ common_microtime:
ret
-#if defined(I586_CPU) && defined(NTP)
+#if defined(I586_CPU)
+ .data
+ .globl _pentium_base_tsc
+ .comm _pentium_base_tsc,8
+ .text
+
+#if defined (NTP)
.align 2, 0x90
pentium_microtime:
cli
.byte 0x0f, 0x31 # RDTSC
+ subl _pentium_base_tsc,%eax
+ sbbl _pentium_base_tsc+4,%edx
divl %ecx # convert to usec
jmp common_microtime
#endif
+#endif
#endif
diff --git a/sys/arch/i386/i386/pctr.c b/sys/arch/i386/i386/pctr.c
new file mode 100644
index 00000000000..9724f62aad9
--- /dev/null
+++ b/sys/arch/i386/i386/pctr.c
@@ -0,0 +1,123 @@
+/* $OpenBSD: pctr.c,v 1.1 1996/08/08 18:47:07 dm Exp $ */
+
+/*
+ * Pentium performance counter driver for OpenBSD.
+ * Author: David Mazieres <dm@lcs.mit.edu>
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/ioccom.h>
+
+#include <machine/cputypes.h>
+#include <machine/psl.h>
+#include <machine/pctr.h>
+#include <machine/cpu.h>
+
+pctrval pctr_idlcnt; /* Gets incremented in locore.s */
+
+#define rdtsc() \
+({ \
+ pctrval v; \
+ __asm __volatile (".byte 0xf, 0x31" : "=A" (v)); \
+ v; \
+})
+
+#define rdmsr(msr) \
+({ \
+ pctrval v; \
+ __asm __volatile (".byte 0xf, 0x32" : "=A" (v) : "c" (msr)); \
+ v; \
+})
+
+#define wrmsr(msr, v) \
+ __asm __volatile (".byte 0xf, 0x30" :: "A" (v), "c" (msr));
+
+void
+pctrattach (int num)
+{
+ if (num > 1)
+ panic ("no more than one pctr device");
+}
+
+int
+pctropen (dev_t dev, int oflags, int devtype, struct proc *p)
+{
+ if (minor (dev) || cpu_class < CPUCLASS_586)
+ return ENXIO;
+ return 0;
+}
+
+int
+pctrclose (dev_t dev, int oflags, int devtype, struct proc *p)
+{
+ return 0;
+}
+
+static int
+pctrset (int fflag, int cmd, u_short fn)
+{
+ pctrval msr11;
+ int msr;
+ int shift;
+
+ switch (cmd) {
+ case PCIOCS0:
+ msr = 0x12;
+ shift = 0;
+ break;
+ case PCIOCS1:
+ msr = 0x13;
+ shift = 16;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ if (! (fflag & FWRITE))
+ return EPERM;
+ if (fn >= 0x200)
+ return EINVAL;
+ msr11 = rdmsr (0x11);
+ msr11 &= ~(0x1ffLL << shift);
+ msr11 |= fn << shift;
+ wrmsr (0x11, msr11);
+ wrmsr (msr, 0LL);
+
+ return 0;
+}
+
+int
+pctrioctl (dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)
+{
+
+ if (minor (dev) || cpu_class < CPUCLASS_586)
+ panic ("pctr: bad device %d should never have been opened.\n", dev);
+
+ switch (cmd) {
+ case PCIOCRD:
+ {
+ u_int msr11;
+ struct pctrst *st;
+
+ st = (void *) data;
+ msr11 = rdmsr (0x11);
+ st->pctr_fn[0] = msr11 & 0xffff;
+ st->pctr_fn[1] = msr11 >> 16;
+ __asm __volatile ("cli");
+ st->pctr_tsc = rdtsc ();
+ st->pctr_hwc[0] = rdmsr (0x12);
+ st->pctr_hwc[1] = rdmsr (0x13);
+ __asm __volatile ("sti");
+ st->pctr_idl = pctr_idlcnt;
+ return 0;
+ break;
+ }
+ case PCIOCS0:
+ case PCIOCS1:
+ return pctrset (fflag, cmd, *(u_short *) data);
+ default:
+ return EINVAL;
+ }
+}
diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h
index 4f5cbd78e41..3abe70557f5 100644
--- a/sys/arch/i386/include/cpu.h
+++ b/sys/arch/i386/include/cpu.h
@@ -99,27 +99,25 @@ void delay __P((int));
/*
* High resolution clock support (Pentium only)
*/
-#define CPU_CLOCKUPDATE(otime, ntime) \
- do { \
- if (pentium_mhz) { \
- __asm __volatile("cli\n" \
- "movl (%2), %%eax\n" \
- "movl %%eax, (%1)\n" \
- "movl 4(%2), %%eax\n" \
- "movl %%eax, 4(%1)\n" \
- "movl $0x10, %%ecx\n" \
- "xorl %%eax, %%eax\n" \
- "movl %%eax, %%edx\n" \
- ".byte 0xf, 0x30\n" \
- "sti\n" \
- "#%0%1%2" \
- : "=m" (*otime) \
- : "c" (otime), "b" (ntime) \
- : "ax", "cx", "dx"); \
- } \
- else { \
- *(otime) = *(ntime); \
- } \
+extern u_quad_t pentium_base_tsc;
+#define CPU_CLOCKUPDATE(otime, ntime) \
+ do { \
+ if (pentium_mhz) { \
+ __asm __volatile("cli\n" \
+ "movl (%3), %%eax\n" \
+ "movl %%eax, (%2)\n" \
+ "movl 4(%3), %%eax\n" \
+ "movl %%eax, 4(%2)\n" \
+ ".byte 0xf, 0x31\n" \
+ "sti\n" \
+ "#%0 %1 %2 %3" \
+ : "=m" (*otime), \
+ "=A" (pentium_base_tsc) \
+ : "c" (otime), "b" (ntime)); \
+ } \
+ else { \
+ *(otime) = *(ntime); \
+ } \
} while (0)
#endif
void delay __P((int));
diff --git a/sys/arch/i386/include/pctr.h b/sys/arch/i386/include/pctr.h
new file mode 100644
index 00000000000..641b3436ca5
--- /dev/null
+++ b/sys/arch/i386/include/pctr.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: pctr.h,v 1.1 1996/08/08 18:47:04 dm Exp $ */
+
+/*
+ * Pentium performance counter driver for OpenBSD.
+ * Author: David Mazieres <dm@lcs.mit.edu>
+ */
+
+#ifndef _I386_PERFCNT_H_
+#define _I386_PERFCNT_H_
+
+typedef u_quad_t pctrval;
+
+#define PCTR_NUM 2
+
+struct pctrst {
+ u_short pctr_fn[PCTR_NUM];
+ pctrval pctr_tsc;
+ pctrval pctr_hwc[PCTR_NUM];
+ pctrval pctr_idl;
+};
+
+/* Bit values in fn fields and PIOCS ioctl's */
+#define PCTR_K 0x40 /* Monitor kernel-level events */
+#define PCTR_U 0x80 /* Monitor user-level events */
+#define PCTR_C 0x100 /* count cycles rather than events */
+
+/* ioctl to set which counter a device tracks. */
+#define PCIOCRD _IOR('c', 1, struct pctrst) /* Read counter value */
+#define PCIOCS0 _IOW('c', 8, unsigned short) /* Set counter 0 function */
+#define PCIOCS1 _IOW('c', 9, unsigned short) /* Set counter 1 function */
+
+#define _PATH_PCTR "/dev/pctr"
+
+#endif /* ! _I386_PERFCNT_H_ */
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 40823ad8914..7afa63d2df6 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.14 1996/08/08 02:08:20 downsj Exp $
+# $OpenBSD: Makefile,v 1.15 1996/08/08 18:46:58 dm Exp $
# $NetBSD: Makefile,v 1.62 1996/03/10 05:45:43 thorpej Exp $
# from: @(#)Makefile 5.8.1.1 (Berkeley) 5/8/91
@@ -26,4 +26,8 @@ SUBDIR= apply apropos arch asa at awk banner basename bdes biff cal calendar \
SUBDIR+= ar gprof nm ranlib size strip strings
.endif
+.if ${MACHINE_ARCH} == "i386"
+SUBDIR+= pctrctl
+.endif
+
.include <bsd.subdir.mk>
diff --git a/usr.bin/pctrctl/Makefile b/usr.bin/pctrctl/Makefile
new file mode 100644
index 00000000000..13a607c167d
--- /dev/null
+++ b/usr.bin/pctrctl/Makefile
@@ -0,0 +1,7 @@
+# $OpenBSD: Makefile,v 1.1 1996/08/08 18:47:01 dm Exp $
+# $NetBSD: Makefile,v 1.7 1995/09/28 06:24:35 perry Exp $
+
+PROG= pctrctl
+NOMAN= yes
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/pctrctl/pctrctl.c b/usr.bin/pctrctl/pctrctl.c
new file mode 100644
index 00000000000..c69b6ac6a80
--- /dev/null
+++ b/usr.bin/pctrctl/pctrctl.c
@@ -0,0 +1,198 @@
+/* $OpenBSD: pctrctl.c,v 1.1 1996/08/08 18:47:03 dm Exp $ */
+/*
+ * Pentium performance counter driver for OpenBSD.
+ * Author: David Mazieres <dm@lcs.mit.edu>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <machine/pctr.h>
+
+char *progname;
+
+char *pctr_name[] = {
+ "Data read", /* 0 */
+ "Data write",
+ "Data TLB miss",
+ "Data read miss",
+ "Data write miss",
+ "Write (hit) to M or E state lines",
+ "Data cache lines written back",
+ "Data cache snoops",
+ "Data cache snoop hits", /* 8 */
+ "Memory accesses in both pipes",
+ "Bank conflicts",
+ "Misaligned data memory references",
+ "Code read",
+ "Code TLB miss",
+ "Code cache miss",
+ "Any segment register load",
+ NULL, /* 0x10 */
+ NULL,
+ "Branches",
+ "BTB hits",
+ "Taken branch or BTB hit",
+ "Pipeline flushes",
+ "Instructions executed",
+ "Instructions executed in the V-pipe",
+ "Bus utilization (clocks)", /* 0x18 */
+ "Pipeline stalled by write backup",
+ "Pipeline stalled by data memory read",
+ "Pipeline stalled by write to E or M line",
+ "Locked bus cycle",
+ "I/O read or write cycle",
+ "Noncacheable memory references",
+ "AGI (Address Generation Interlock)",
+ NULL, /* 0x20 */
+ NULL,
+ "Floating-point operations",
+ "Breakpoint 0 match",
+ "Breakpoint 1 match",
+ "Breakpoint 2 match",
+ "Breakpoint 3 match",
+ "Hardware interupts",
+ "Data read or data write", /* 0x28 */
+ "Data read miss or data write miss",
+};
+
+static const int pctr_name_size = (sizeof (pctr_name) / sizeof (char *));
+
+/* Print all possible counter functions */
+static void
+list (void)
+{
+ int i;
+
+ printf ("Hardware counter event types:\n");
+ for (i = 0; i < pctr_name_size; i++)
+ printf (" %02x %s\n", i, pctr_name[i] ? pctr_name[i] : "invalid");
+}
+
+/* Print status of counters */
+static void
+readst (void)
+{
+ int fd, i;
+ struct pctrst st;
+
+ fd = open (_PATH_PCTR, O_RDONLY);
+ if (fd < 0) {
+ perror (_PATH_PCTR);
+ exit (1);
+ }
+ if (ioctl (fd, PCIOCRD, &st) < 0) {
+ perror ("PCIOCRD");
+ exit (1);
+ }
+ close (fd);
+
+ for (i = 0; i < PCTR_NUM; i++)
+ printf (" ctr%d = %16qd [%c%c%c %02x (%s)]\n", i, st.pctr_hwc[i],
+ (st.pctr_fn[i] & PCTR_C) ? 'c' : 'e',
+ (st.pctr_fn[i] & PCTR_U) ? 'u' : '-',
+ (st.pctr_fn[i] & PCTR_K) ? 'k' : '-',
+ (st.pctr_fn[i] & 0x3f),
+ (((st.pctr_fn[i] & 0x3f) < pctr_name_size
+ && pctr_name[st.pctr_fn[i] & 0x3f])
+ ? pctr_name[st.pctr_fn[i] & 0x3f] : "invalid"));
+ printf (" tsc = %16qd\n idl = %16qd\n", st.pctr_tsc, st.pctr_idl);
+}
+
+static void
+setctr (int ctr, u_short val)
+{
+ int fd;
+
+ fd = open (_PATH_PCTR, O_WRONLY);
+ if (fd < 0) {
+ perror (_PATH_PCTR);
+ exit (1);
+ }
+ if (ioctl (fd, PCIOCS0 + ctr, &val) < 0) {
+ perror ("PCIOCSn");
+ exit (1);
+ }
+ close (fd);
+}
+
+static void
+usage (void)
+{
+ fprintf (stderr,
+ "usage: %s [-l | -s ctr [selstr] evtype]\n"
+ " -l list event types\n"
+ " -s set counter <ctr> to monitor events of type <evtype>\n"
+ " <selstr> = [e|c][u][k] (default euk)\n"
+ " e - count number of events\n"
+ " c - count number of cycles\n"
+ " u - count events in user mode (ring 3)\n"
+ " k - count events in kernel mode (rings 0-2)\n",
+ progname);
+ exit (1);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int fd;
+ u_int ctr;
+ char *cp;
+ u_short fn;
+
+ if (progname = strrchr (argv[0], '/'))
+ progname++;
+ else
+ progname = argv[0];
+
+ if (argc <= 1)
+ readst ();
+ else if (argc == 2 && !strcmp (argv[1], "-l"))
+ list ();
+ else if (!strcmp (argv[1], "-s") && argc >= 4) {
+ if (argc > 5)
+ usage ();
+ ctr = atoi (argv[2]);
+ if (ctr >= PCTR_NUM)
+ usage ();
+ if (argc == 5) {
+ fn = strtoul (argv[4], NULL, 16);
+ if (fn & ~0x3f)
+ usage ();
+ for (cp = argv[3]; *cp; cp++) {
+ switch (*cp) {
+ case 'c':
+ fn |= PCTR_C;
+ break;
+ case 'e':
+ fn &= ~PCTR_C;
+ break;
+ case 'k':
+ fn |= PCTR_K;
+ break;
+ case 'u':
+ fn |= PCTR_U;
+ break;
+ default:
+ usage ();
+ }
+ }
+ }
+ else {
+ fn = strtoul (argv[3], NULL, 16);
+ if (fn & ~0x3f)
+ usage ();
+ fn |= PCTR_K | PCTR_U;
+ }
+ setctr (ctr, fn);
+ }
+ else
+ usage ();
+
+ return 0;
+}