Annotation of src/usr.bin/pctrctl/pctrctl.c, Revision 1.1
1.1 ! dm 1: /* $OpenBSD$ */
! 2: /*
! 3: * Pentium performance counter driver for OpenBSD.
! 4: * Author: David Mazieres <dm@lcs.mit.edu>
! 5: */
! 6:
! 7: #include <stdio.h>
! 8: #include <stdlib.h>
! 9: #include <string.h>
! 10: #include <sys/types.h>
! 11: #include <sys/stat.h>
! 12: #include <sys/ioctl.h>
! 13: #include <fcntl.h>
! 14: #include <machine/pctr.h>
! 15:
! 16: char *progname;
! 17:
! 18: char *pctr_name[] = {
! 19: "Data read", /* 0 */
! 20: "Data write",
! 21: "Data TLB miss",
! 22: "Data read miss",
! 23: "Data write miss",
! 24: "Write (hit) to M or E state lines",
! 25: "Data cache lines written back",
! 26: "Data cache snoops",
! 27: "Data cache snoop hits", /* 8 */
! 28: "Memory accesses in both pipes",
! 29: "Bank conflicts",
! 30: "Misaligned data memory references",
! 31: "Code read",
! 32: "Code TLB miss",
! 33: "Code cache miss",
! 34: "Any segment register load",
! 35: NULL, /* 0x10 */
! 36: NULL,
! 37: "Branches",
! 38: "BTB hits",
! 39: "Taken branch or BTB hit",
! 40: "Pipeline flushes",
! 41: "Instructions executed",
! 42: "Instructions executed in the V-pipe",
! 43: "Bus utilization (clocks)", /* 0x18 */
! 44: "Pipeline stalled by write backup",
! 45: "Pipeline stalled by data memory read",
! 46: "Pipeline stalled by write to E or M line",
! 47: "Locked bus cycle",
! 48: "I/O read or write cycle",
! 49: "Noncacheable memory references",
! 50: "AGI (Address Generation Interlock)",
! 51: NULL, /* 0x20 */
! 52: NULL,
! 53: "Floating-point operations",
! 54: "Breakpoint 0 match",
! 55: "Breakpoint 1 match",
! 56: "Breakpoint 2 match",
! 57: "Breakpoint 3 match",
! 58: "Hardware interupts",
! 59: "Data read or data write", /* 0x28 */
! 60: "Data read miss or data write miss",
! 61: };
! 62:
! 63: static const int pctr_name_size = (sizeof (pctr_name) / sizeof (char *));
! 64:
! 65: /* Print all possible counter functions */
! 66: static void
! 67: list (void)
! 68: {
! 69: int i;
! 70:
! 71: printf ("Hardware counter event types:\n");
! 72: for (i = 0; i < pctr_name_size; i++)
! 73: printf (" %02x %s\n", i, pctr_name[i] ? pctr_name[i] : "invalid");
! 74: }
! 75:
! 76: /* Print status of counters */
! 77: static void
! 78: readst (void)
! 79: {
! 80: int fd, i;
! 81: struct pctrst st;
! 82:
! 83: fd = open (_PATH_PCTR, O_RDONLY);
! 84: if (fd < 0) {
! 85: perror (_PATH_PCTR);
! 86: exit (1);
! 87: }
! 88: if (ioctl (fd, PCIOCRD, &st) < 0) {
! 89: perror ("PCIOCRD");
! 90: exit (1);
! 91: }
! 92: close (fd);
! 93:
! 94: for (i = 0; i < PCTR_NUM; i++)
! 95: printf (" ctr%d = %16qd [%c%c%c %02x (%s)]\n", i, st.pctr_hwc[i],
! 96: (st.pctr_fn[i] & PCTR_C) ? 'c' : 'e',
! 97: (st.pctr_fn[i] & PCTR_U) ? 'u' : '-',
! 98: (st.pctr_fn[i] & PCTR_K) ? 'k' : '-',
! 99: (st.pctr_fn[i] & 0x3f),
! 100: (((st.pctr_fn[i] & 0x3f) < pctr_name_size
! 101: && pctr_name[st.pctr_fn[i] & 0x3f])
! 102: ? pctr_name[st.pctr_fn[i] & 0x3f] : "invalid"));
! 103: printf (" tsc = %16qd\n idl = %16qd\n", st.pctr_tsc, st.pctr_idl);
! 104: }
! 105:
! 106: static void
! 107: setctr (int ctr, u_short val)
! 108: {
! 109: int fd;
! 110:
! 111: fd = open (_PATH_PCTR, O_WRONLY);
! 112: if (fd < 0) {
! 113: perror (_PATH_PCTR);
! 114: exit (1);
! 115: }
! 116: if (ioctl (fd, PCIOCS0 + ctr, &val) < 0) {
! 117: perror ("PCIOCSn");
! 118: exit (1);
! 119: }
! 120: close (fd);
! 121: }
! 122:
! 123: static void
! 124: usage (void)
! 125: {
! 126: fprintf (stderr,
! 127: "usage: %s [-l | -s ctr [selstr] evtype]\n"
! 128: " -l list event types\n"
! 129: " -s set counter <ctr> to monitor events of type <evtype>\n"
! 130: " <selstr> = [e|c][u][k] (default euk)\n"
! 131: " e - count number of events\n"
! 132: " c - count number of cycles\n"
! 133: " u - count events in user mode (ring 3)\n"
! 134: " k - count events in kernel mode (rings 0-2)\n",
! 135: progname);
! 136: exit (1);
! 137: }
! 138:
! 139:
! 140: int
! 141: main (int argc, char **argv)
! 142: {
! 143: int fd;
! 144: u_int ctr;
! 145: char *cp;
! 146: u_short fn;
! 147:
! 148: if (progname = strrchr (argv[0], '/'))
! 149: progname++;
! 150: else
! 151: progname = argv[0];
! 152:
! 153: if (argc <= 1)
! 154: readst ();
! 155: else if (argc == 2 && !strcmp (argv[1], "-l"))
! 156: list ();
! 157: else if (!strcmp (argv[1], "-s") && argc >= 4) {
! 158: if (argc > 5)
! 159: usage ();
! 160: ctr = atoi (argv[2]);
! 161: if (ctr >= PCTR_NUM)
! 162: usage ();
! 163: if (argc == 5) {
! 164: fn = strtoul (argv[4], NULL, 16);
! 165: if (fn & ~0x3f)
! 166: usage ();
! 167: for (cp = argv[3]; *cp; cp++) {
! 168: switch (*cp) {
! 169: case 'c':
! 170: fn |= PCTR_C;
! 171: break;
! 172: case 'e':
! 173: fn &= ~PCTR_C;
! 174: break;
! 175: case 'k':
! 176: fn |= PCTR_K;
! 177: break;
! 178: case 'u':
! 179: fn |= PCTR_U;
! 180: break;
! 181: default:
! 182: usage ();
! 183: }
! 184: }
! 185: }
! 186: else {
! 187: fn = strtoul (argv[3], NULL, 16);
! 188: if (fn & ~0x3f)
! 189: usage ();
! 190: fn |= PCTR_K | PCTR_U;
! 191: }
! 192: setctr (ctr, fn);
! 193: }
! 194: else
! 195: usage ();
! 196:
! 197: return 0;
! 198: }