[BACK]Return to pctrctl.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pctrctl

File: [local] / src / usr.bin / pctrctl / Attic / pctrctl.c (download)

Revision 1.2, Wed Aug 14 03:02:52 1996 UTC (27 years, 10 months ago) by dm
Branch: MAIN
Changes since 1.1: +17 -10 lines

Added support in the driver for the Pentium Pro (pctrctl still needs to
be done, though).

/*	$OpenBSD: pctrctl.c,v 1.2 1996/08/14 03:02:52 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/cpu.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] & P5CTR_C) ? 'c' : 'e',
	    (st.pctr_fn[i] & P5CTR_U) ? 'u' : '-',
	    (st.pctr_fn[i] & P5CTR_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_int 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;
  pctrval id = __cpuid ();

  if (__hasp6ctr (id)) {
    fprintf (stderr, "Pentium Pro not supported\n");
    exit (1);
  }

  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 |= P5CTR_C;
	  break;
	case 'e':
	  fn &= ~P5CTR_C;
	  break;
	case 'k':
	  fn |= P5CTR_K;
	  break;
	case 'u':
	  fn |= P5CTR_U;
	  break;
	default:
	  usage ();
	}
      }
    }
    else {
      fn = strtoul (argv[3], NULL, 16);
      if (fn & ~0x3f)
	usage ();
      fn |= P5CTR_K | P5CTR_U;
    }
    setctr (ctr, fn);
  }
  else
    usage ();

  return 0;
}