perfmon.c revision 21673
1100616Smp/*
259243Sobrien * Copyright 1996 Massachusetts Institute of Technology
359243Sobrien *
459243Sobrien * Permission to use, copy, modify, and distribute this software and
559243Sobrien * its documentation for any purpose and without fee is hereby
659243Sobrien * granted, provided that both the above copyright notice and this
759243Sobrien * permission notice appear in all copies, that both the above
859243Sobrien * copyright notice and this permission notice appear in all
959243Sobrien * supporting documentation, and that the name of M.I.T. not be used
1059243Sobrien * in advertising or publicity pertaining to distribution of the
1159243Sobrien * software without specific, written prior permission.  M.I.T. makes
1259243Sobrien * no representations about the suitability of this software for any
1359243Sobrien * purpose.  It is provided "as is" without express or implied
1459243Sobrien * warranty.
1559243Sobrien *
1659243Sobrien * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17100616Smp * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
1859243Sobrien * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1959243Sobrien * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
2059243Sobrien * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2159243Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2259243Sobrien * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2359243Sobrien * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2459243Sobrien * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2559243Sobrien * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2659243Sobrien * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2759243Sobrien * SUCH DAMAGE.
2859243Sobrien *
2959243Sobrien *	$FreeBSD: head/share/examples/perfmon/perfmon.c 21673 1997-01-14 07:20:47Z jkh $
3059243Sobrien */
3159243Sobrien
3259243Sobrien#include <sys/types.h>
3359243Sobrien#include <sys/ioctl.h>
3459243Sobrien
3559243Sobrien#include <machine/cpu.h>
3659243Sobrien#include <machine/perfmon.h>
3759243Sobrien
3859243Sobrien#include <stdio.h>
3959243Sobrien#include <stdlib.h>
4069408Sache#include <string.h>
4159243Sobrien#include <err.h>
4259243Sobrien#include <unistd.h>
4359243Sobrien#include <fcntl.h>
4459243Sobrien#include <limits.h>
4569408Sache#include <errno.h>
4659243Sobrien
4759243Sobrienstatic int getnum(const char *, int, int);
4859243Sobrienstatic void __dead usage(const char *) __dead2;
4959243Sobrien
5059243Sobrienint
5159243Sobrienmain(int argc, char **argv)
5259243Sobrien{
5359243Sobrien	int c, fd, num;
5459243Sobrien	int loops, i, sleeptime;
5559243Sobrien	struct pmc pmc;
5659243Sobrien	struct pmc_tstamp then, now;
5759243Sobrien	struct pmc_data value;
5859243Sobrien	quad_t *buf;
5959243Sobrien	double total;
6059243Sobrien
6159243Sobrien	pmc.pmc_num = 0;
6259243Sobrien	pmc.pmc_event = 0;
6359243Sobrien	pmc.pmc_unit = 0;
6459243Sobrien	pmc.pmc_flags = 0;
6559243Sobrien	pmc.pmc_mask = 0;
6659243Sobrien	loops = 50;
6759243Sobrien	sleeptime = 0;
6859243Sobrien
6959243Sobrien	while ((c = getopt(argc, argv, "s:l:uoeiU:m:")) != EOF) {
7059243Sobrien		switch(c) {
7159243Sobrien		case 'u':
7259243Sobrien			pmc.pmc_flags |= PMCF_USR;
7359243Sobrien			break;
7459243Sobrien		case 'o':
7559243Sobrien			pmc.pmc_flags |= PMCF_OS;
7659243Sobrien			break;
7759243Sobrien		case 'e':
7859243Sobrien			pmc.pmc_flags |= PMCF_E;
7959243Sobrien			break;
8059243Sobrien		case 'i':
8159243Sobrien			pmc.pmc_flags |= PMCF_INV;
8259243Sobrien			break;
8359243Sobrien		case 'U':
8459243Sobrien			pmc.pmc_unit = getnum(optarg, 0, 256);
8559243Sobrien			break;
8659243Sobrien		case 'm':
8759243Sobrien			pmc.pmc_mask = getnum(optarg, 0, 256);
8859243Sobrien			break;
8959243Sobrien		case 'l':
9059243Sobrien			loops = getnum(optarg, 1, INT_MAX - 1);
9159243Sobrien			break;
9259243Sobrien		case 's':
9359243Sobrien			sleeptime = getnum(optarg, 0, INT_MAX - 1);
9459243Sobrien			break;
9583098Smp		default:
9659243Sobrien			usage(argv[0]);
9759243Sobrien		}
9859243Sobrien	}
9959243Sobrien
10059243Sobrien	if (argc - optind != 1)
10159243Sobrien		usage(argv[0]);
10259243Sobrien
10359243Sobrien	pmc.pmc_event = getnum(argv[optind], 0, 255);
10459243Sobrien
10559243Sobrien	buf = malloc((loops + 1) * sizeof *buf);
10659243Sobrien	if (!buf)
10759243Sobrien		err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
10859243Sobrien
10959243Sobrien	fd = open(_PATH_PERFMON, O_RDWR, 0);
11059243Sobrien	if (fd < 0)
11159243Sobrien		err(1, "open: " _PATH_PERFMON);
11259243Sobrien
11359243Sobrien	if (ioctl(fd, PMIOSETUP, &pmc) < 0)
11459243Sobrien		err(1, "ioctl(PMIOSETUP)");
11559243Sobrien
11659243Sobrien	if (ioctl(fd, PMIOTSTAMP, &then) < 0)
11759243Sobrien		err(1, "ioctl(PMIOTSTAMP)");
11859243Sobrien
11959243Sobrien	num = 0;
12059243Sobrien	if (ioctl(fd, PMIOSTART, &num) < 0)
12159243Sobrien		err(1, "ioctl(PMIOSTART)");
12259243Sobrien
12359243Sobrien	value.pmcd_num = 0;
12459243Sobrien	for (i = 0; i < loops; i++) {
12559243Sobrien		if (sleeptime)
12659243Sobrien			sleep(sleeptime);
12759243Sobrien		if (ioctl(fd, PMIOSTOP, &num) < 0)
12859243Sobrien			err(1, "ioctl(PMIOSTOP)");
12959243Sobrien		if (ioctl(fd, PMIOREAD, &value) < 0)
13059243Sobrien			err(1, "ioctl(PMIOREAD)");
13159243Sobrien		buf[i] = value.pmcd_value;
13259243Sobrien		if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
13359243Sobrien			err(1, "ioctl(PMIORESET)");
13459243Sobrien		if (ioctl(fd, PMIOSTART, &num) < 0)
13559243Sobrien			err(1, "ioctl(PMIOSTART)");
13659243Sobrien	}
13759243Sobrien
13859243Sobrien	if (ioctl(fd, PMIOSTOP, &num) < 0)
13959243Sobrien		err(1, "ioctl(PMIOSTOP)");
14059243Sobrien	if (ioctl(fd, PMIOREAD, &value) < 0)
14159243Sobrien		err(1, "ioctl(PMIOREAD)");
14259243Sobrien	buf[i] = value.pmcd_value;
14359243Sobrien	if (ioctl(fd, PMIOTSTAMP, &now) < 0)
14459243Sobrien		err(1, "ioctl(PMIOTSTAMP)");
14559243Sobrien
14659243Sobrien	total = 0;
14759243Sobrien	for (i = 1; i <= loops; i++) {
14859243Sobrien		printf("%d: %qd\n", i, buf[i]);
14959243Sobrien		total += buf[i];
15059243Sobrien	}
15159243Sobrien	printf("total: %f\nmean: %f\n", total, total / loops);
15259243Sobrien
15359243Sobrien	printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
15459243Sobrien	       now.pmct_value - then.pmct_value);
15559243Sobrien
15659243Sobrien	return 0;
15759243Sobrien}
15859243Sobrien
15959243Sobrienstatic int
16059243Sobriengetnum(const char *buf, int min, int max)
16159243Sobrien{
16259243Sobrien	char *ep;
16359243Sobrien	long l;
16459243Sobrien
16559243Sobrien	errno = 0;
16659243Sobrien	l = strtol(buf, &ep, 0);
16759243Sobrien	if (*buf && !*ep && !errno) {
16859243Sobrien		if (l < min || l > max) {
16959243Sobrien			errx(1, "`%s': must be between %d and %d",
17059243Sobrien			     buf, min, max);
17159243Sobrien		}
17259243Sobrien		return (int)l;
17359243Sobrien	} else if(errno) {
17459243Sobrien		errx(1, "`%s': must be between %ld and %ld",
17559243Sobrien		     LONG_MIN, LONG_MAX);
17659243Sobrien	}
17759243Sobrien	errx(1, "`%s': parameter must be an integer");
17859243Sobrien}
17959243Sobrien
18059243Sobrienstatic void
18159243Sobrienusage(const char *pname)
18259243Sobrien{
18359243Sobrien	fprintf(stderr,
18459243Sobrien		"%s: usage:\n\t%s [-eiou] [-l nloops] [-U unit] [-m mask] "
18559243Sobrien		"counter\n", pname, pname);
18659243Sobrien	exit(1);
18759243Sobrien}
18859243Sobrien