From 808918a21bdbe80159e3e3e46fc450c4c25b5d61 Mon Sep 17 00:00:00 2001 From: wollman Date: Thu, 28 Mar 1996 21:20:22 +0000 Subject: A sample program for /dev/perfmon --- share/examples/perfmon/Makefile | 8 ++ share/examples/perfmon/README | 24 +++++ share/examples/perfmon/perfmon.c | 187 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 share/examples/perfmon/Makefile create mode 100644 share/examples/perfmon/README create mode 100644 share/examples/perfmon/perfmon.c (limited to 'share/examples/perfmon') diff --git a/share/examples/perfmon/Makefile b/share/examples/perfmon/Makefile new file mode 100644 index 0000000..0bcd815 --- /dev/null +++ b/share/examples/perfmon/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.1 1994/08/10 06:40:35 wollman Exp $ + +PROG= perfmon +NOMAN= + +install: + +.include diff --git a/share/examples/perfmon/README b/share/examples/perfmon/README new file mode 100644 index 0000000..1a339b8 --- /dev/null +++ b/share/examples/perfmon/README @@ -0,0 +1,24 @@ +`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 must be the number of the counter. +All numbers can be specified in any format acceptable to strtol(3). + +$Id$ diff --git a/share/examples/perfmon/perfmon.c b/share/examples/perfmon/perfmon.c new file mode 100644 index 0000000..274a828 --- /dev/null +++ b/share/examples/perfmon/perfmon.c @@ -0,0 +1,187 @@ +/* + * 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. + * + * $Id$ + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static int getnum(const char *, int, int); +static void __dead usage(const char *) __dead2; + +int +main(int argc, char **argv) +{ + int c, fd, num; + int loops, i, sleeptime; + 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; + loops = 50; + sleeptime = 0; + + while ((c = getopt(argc, argv, "s:l:uoeiU:m:")) != EOF) { + 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; + 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 (sleeptime) + sleep(sleeptime); + 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 (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; + } else if(errno) { + errx(1, "`%s': must be between %ld and %ld", + LONG_MIN, LONG_MAX); + } + errx(1, "`%s': parameter must be an integer"); +} + +static void +usage(const char *pname) +{ + fprintf(stderr, + "%s: usage:\n\t%s [-eiou] [-l nloops] [-U unit] [-m mask] " + "counter\n", pname, pname); + exit(1); +} -- cgit v1.1