114895Swollman/*
214895Swollman * Copyright 1996 Massachusetts Institute of Technology
314895Swollman *
414895Swollman * Permission to use, copy, modify, and distribute this software and
514895Swollman * its documentation for any purpose and without fee is hereby
614895Swollman * granted, provided that both the above copyright notice and this
714895Swollman * permission notice appear in all copies, that both the above
814895Swollman * copyright notice and this permission notice appear in all
914895Swollman * supporting documentation, and that the name of M.I.T. not be used
1014895Swollman * in advertising or publicity pertaining to distribution of the
1114895Swollman * software without specific, written prior permission.  M.I.T. makes
1214895Swollman * no representations about the suitability of this software for any
1314895Swollman * purpose.  It is provided "as is" without express or implied
1414895Swollman * warranty.
1514895Swollman *
1614895Swollman * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
1714895Swollman * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
1814895Swollman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1914895Swollman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
2014895Swollman * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2114895Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2214895Swollman * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2314895Swollman * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2414895Swollman * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2514895Swollman * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2614895Swollman * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2714895Swollman * SUCH DAMAGE.
2814895Swollman *
2950476Speter * $FreeBSD$
3014895Swollman */
3114895Swollman
3214895Swollman#include <sys/types.h>
3314895Swollman#include <sys/ioctl.h>
3414895Swollman
35253750Savg#include <machine/cpu.h>
3614895Swollman#include <machine/perfmon.h>
3714895Swollman
3814895Swollman#include <stdio.h>
3914895Swollman#include <stdlib.h>
4014895Swollman#include <string.h>
4114895Swollman#include <err.h>
4214895Swollman#include <unistd.h>
4314895Swollman#include <fcntl.h>
4414895Swollman#include <limits.h>
4514895Swollman#include <errno.h>
4614895Swollman
4714895Swollmanstatic int getnum(const char *, int, int);
4827085Sbdestatic void usage(const char *) __dead2;
4914895Swollman
5014895Swollmanint
5114895Swollmanmain(int argc, char **argv)
5214895Swollman{
5314895Swollman	int c, fd, num;
5414895Swollman	int loops, i, sleeptime;
5527085Sbde	char *cmd;
5614895Swollman	struct pmc pmc;
5714895Swollman	struct pmc_tstamp then, now;
5814895Swollman	struct pmc_data value;
5914895Swollman	quad_t *buf;
6014895Swollman	double total;
6114895Swollman
6214895Swollman	pmc.pmc_num = 0;
6314895Swollman	pmc.pmc_event = 0;
6414895Swollman	pmc.pmc_unit = 0;
6514895Swollman	pmc.pmc_flags = 0;
6614895Swollman	pmc.pmc_mask = 0;
6727085Sbde	cmd = NULL;
6814895Swollman	loops = 50;
6914895Swollman	sleeptime = 0;
7014895Swollman
7127085Sbde	while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) {
7214895Swollman		switch(c) {
7314895Swollman		case 'u':
7414895Swollman			pmc.pmc_flags |= PMCF_USR;
7514895Swollman			break;
7614895Swollman		case 'o':
7714895Swollman			pmc.pmc_flags |= PMCF_OS;
7814895Swollman			break;
7914895Swollman		case 'e':
8014895Swollman			pmc.pmc_flags |= PMCF_E;
8114895Swollman			break;
8214895Swollman		case 'i':
8314895Swollman			pmc.pmc_flags |= PMCF_INV;
8414895Swollman			break;
8514895Swollman		case 'U':
8614895Swollman			pmc.pmc_unit = getnum(optarg, 0, 256);
8714895Swollman			break;
8814895Swollman		case 'm':
8914895Swollman			pmc.pmc_mask = getnum(optarg, 0, 256);
9014895Swollman			break;
9114895Swollman		case 'l':
9214895Swollman			loops = getnum(optarg, 1, INT_MAX - 1);
9314895Swollman			break;
9414895Swollman		case 's':
9514895Swollman			sleeptime = getnum(optarg, 0, INT_MAX - 1);
9614895Swollman			break;
9727085Sbde		case 'c':
9827085Sbde			cmd = optarg;
9927085Sbde			break;
10014895Swollman		default:
10114895Swollman			usage(argv[0]);
10214895Swollman		}
10314895Swollman	}
10414895Swollman
10514895Swollman	if (argc - optind != 1)
10614895Swollman		usage(argv[0]);
10714895Swollman
10814895Swollman	pmc.pmc_event = getnum(argv[optind], 0, 255);
10914895Swollman
11014895Swollman	buf = malloc((loops + 1) * sizeof *buf);
11114895Swollman	if (!buf)
11214895Swollman		err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
11314895Swollman
11414895Swollman	fd = open(_PATH_PERFMON, O_RDWR, 0);
11514895Swollman	if (fd < 0)
11614895Swollman		err(1, "open: " _PATH_PERFMON);
11714895Swollman
11814895Swollman	if (ioctl(fd, PMIOSETUP, &pmc) < 0)
11914895Swollman		err(1, "ioctl(PMIOSETUP)");
12014895Swollman
12114895Swollman	if (ioctl(fd, PMIOTSTAMP, &then) < 0)
12214895Swollman		err(1, "ioctl(PMIOTSTAMP)");
12314895Swollman
12414895Swollman	num = 0;
12514895Swollman	if (ioctl(fd, PMIOSTART, &num) < 0)
12614895Swollman		err(1, "ioctl(PMIOSTART)");
12714895Swollman
12814895Swollman	value.pmcd_num = 0;
12914895Swollman	for (i = 0; i < loops; i++) {
13014895Swollman		if (ioctl(fd, PMIOSTOP, &num) < 0)
13114895Swollman			err(1, "ioctl(PMIOSTOP)");
13214895Swollman		if (ioctl(fd, PMIOREAD, &value) < 0)
13314895Swollman			err(1, "ioctl(PMIOREAD)");
13414895Swollman		buf[i] = value.pmcd_value;
13514895Swollman		if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
13614895Swollman			err(1, "ioctl(PMIORESET)");
13714895Swollman		if (ioctl(fd, PMIOSTART, &num) < 0)
13814895Swollman			err(1, "ioctl(PMIOSTART)");
13927085Sbde		if (sleeptime)
14027085Sbde			sleep(sleeptime);
14127085Sbde		if (cmd)
14227085Sbde			system(cmd);
14314895Swollman	}
14414895Swollman
14514895Swollman	if (ioctl(fd, PMIOSTOP, &num) < 0)
14614895Swollman		err(1, "ioctl(PMIOSTOP)");
14714895Swollman	if (ioctl(fd, PMIOREAD, &value) < 0)
14814895Swollman		err(1, "ioctl(PMIOREAD)");
14914895Swollman	buf[i] = value.pmcd_value;
15014895Swollman	if (ioctl(fd, PMIOTSTAMP, &now) < 0)
15114895Swollman		err(1, "ioctl(PMIOTSTAMP)");
15214895Swollman
15314895Swollman	total = 0;
15414895Swollman	for (i = 1; i <= loops; i++) {
15514895Swollman		printf("%d: %qd\n", i, buf[i]);
15614895Swollman		total += buf[i];
15714895Swollman	}
15814895Swollman	printf("total: %f\nmean: %f\n", total, total / loops);
15914895Swollman
16014895Swollman	printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
16114895Swollman	       now.pmct_value - then.pmct_value);
16214895Swollman
16314895Swollman	return 0;
16414895Swollman}
16514895Swollman
16614895Swollmanstatic int
16714895Swollmangetnum(const char *buf, int min, int max)
16814895Swollman{
16914895Swollman	char *ep;
17014895Swollman	long l;
17114895Swollman
17214895Swollman	errno = 0;
17314895Swollman	l = strtol(buf, &ep, 0);
17414895Swollman	if (*buf && !*ep && !errno) {
17514895Swollman		if (l < min || l > max) {
176209455Skevlo			errx(1, "%s: must be between %d and %d",
17714895Swollman			     buf, min, max);
17814895Swollman		}
17914895Swollman		return (int)l;
180209455Skevlo	}
181209455Skevlo
182209455Skevlo	errx(1, "%s: parameter must be an integer", buf);
18314895Swollman}
18414895Swollman
18514895Swollmanstatic void
18614895Swollmanusage(const char *pname)
18714895Swollman{
18814895Swollman	fprintf(stderr,
18927085Sbde	"usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n"
19027085Sbde	"       [-U unit] counter\n",
19127085Sbde		pname);
19214895Swollman	exit(1);
19314895Swollman}
194