perfmon.c revision 14895
1177633Sdfr/*
2177633Sdfr * Copyright 1996 Massachusetts Institute of Technology
3177633Sdfr *
4177633Sdfr * Permission to use, copy, modify, and distribute this software and
5177633Sdfr * its documentation for any purpose and without fee is hereby
6177633Sdfr * granted, provided that both the above copyright notice and this
7177633Sdfr * permission notice appear in all copies, that both the above
8177633Sdfr * copyright notice and this permission notice appear in all
9177633Sdfr * supporting documentation, and that the name of M.I.T. not be used
10177633Sdfr * in advertising or publicity pertaining to distribution of the
11177633Sdfr * software without specific, written prior permission.  M.I.T. makes
12177633Sdfr * no representations about the suitability of this software for any
13177633Sdfr * purpose.  It is provided "as is" without express or implied
14177633Sdfr * warranty.
15177633Sdfr *
16177633Sdfr * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17177633Sdfr * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18177633Sdfr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19177633Sdfr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20177633Sdfr * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21177633Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22177633Sdfr * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23177633Sdfr * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24177633Sdfr * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25177633Sdfr * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26177633Sdfr * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27177633Sdfr * SUCH DAMAGE.
28177633Sdfr *
29177633Sdfr *	$Id$
30177633Sdfr */
31177633Sdfr
32177633Sdfr#include <sys/types.h>
33177633Sdfr#include <sys/ioctl.h>
34177633Sdfr
35177633Sdfr#include <machine/cpu.h>
36177633Sdfr#include <machine/perfmon.h>
37177633Sdfr
38177633Sdfr#include <stdio.h>
39177633Sdfr#include <stdlib.h>
40177633Sdfr#include <string.h>
41177633Sdfr#include <err.h>
42177633Sdfr#include <unistd.h>
43177633Sdfr#include <fcntl.h>
44177633Sdfr#include <limits.h>
45177633Sdfr#include <errno.h>
46177633Sdfr
47177633Sdfrstatic int getnum(const char *, int, int);
48180025Sdfrstatic void __dead usage(const char *) __dead2;
49177633Sdfr
50177633Sdfrint
51177633Sdfrmain(int argc, char **argv)
52177633Sdfr{
53177633Sdfr	int c, fd, num;
54177633Sdfr	int loops, i, sleeptime;
55177633Sdfr	struct pmc pmc;
56177633Sdfr	struct pmc_tstamp then, now;
57177633Sdfr	struct pmc_data value;
58177633Sdfr	quad_t *buf;
59177633Sdfr	double total;
60196503Szec
61196503Szec	pmc.pmc_num = 0;
62177633Sdfr	pmc.pmc_event = 0;
63177685Sdfr	pmc.pmc_unit = 0;
64177633Sdfr	pmc.pmc_flags = 0;
65177633Sdfr	pmc.pmc_mask = 0;
66177633Sdfr	loops = 50;
67177633Sdfr	sleeptime = 0;
68177633Sdfr
69177633Sdfr	while ((c = getopt(argc, argv, "s:l:uoeiU:m:")) != EOF) {
70177633Sdfr		switch(c) {
71177633Sdfr		case 'u':
72177633Sdfr			pmc.pmc_flags |= PMCF_USR;
73177633Sdfr			break;
74177633Sdfr		case 'o':
75177633Sdfr			pmc.pmc_flags |= PMCF_OS;
76180025Sdfr			break;
77184588Sdfr		case 'e':
78177633Sdfr			pmc.pmc_flags |= PMCF_E;
79177633Sdfr			break;
80177633Sdfr		case 'i':
81177633Sdfr			pmc.pmc_flags |= PMCF_INV;
82184588Sdfr			break;
83177633Sdfr		case 'U':
84193272Sjhb			pmc.pmc_unit = getnum(optarg, 0, 256);
85177633Sdfr			break;
86177633Sdfr		case 'm':
87177633Sdfr			pmc.pmc_mask = getnum(optarg, 0, 256);
88177633Sdfr			break;
89177633Sdfr		case 'l':
90177633Sdfr			loops = getnum(optarg, 1, INT_MAX - 1);
91184588Sdfr			break;
92177633Sdfr		case 's':
93177633Sdfr			sleeptime = getnum(optarg, 0, INT_MAX - 1);
94177633Sdfr			break;
95177633Sdfr		default:
96177633Sdfr			usage(argv[0]);
97177633Sdfr		}
98177633Sdfr	}
99180025Sdfr
100180025Sdfr	if (argc - optind != 1)
101180025Sdfr		usage(argv[0]);
102177633Sdfr
103177633Sdfr	pmc.pmc_event = getnum(argv[optind], 0, 255);
104177633Sdfr
105180025Sdfr	buf = malloc((loops + 1) * sizeof *buf);
106177633Sdfr	if (!buf)
107177633Sdfr		err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
108177633Sdfr
109184588Sdfr	fd = open(_PATH_PERFMON, O_RDWR, 0);
110177633Sdfr	if (fd < 0)
111177633Sdfr		err(1, "open: " _PATH_PERFMON);
112177633Sdfr
113177633Sdfr	if (ioctl(fd, PMIOSETUP, &pmc) < 0)
114177633Sdfr		err(1, "ioctl(PMIOSETUP)");
115177633Sdfr
116177633Sdfr	if (ioctl(fd, PMIOTSTAMP, &then) < 0)
117193272Sjhb		err(1, "ioctl(PMIOTSTAMP)");
118177633Sdfr
119177633Sdfr	num = 0;
120177633Sdfr	if (ioctl(fd, PMIOSTART, &num) < 0)
121177633Sdfr		err(1, "ioctl(PMIOSTART)");
122177633Sdfr
123177633Sdfr	value.pmcd_num = 0;
124177633Sdfr	for (i = 0; i < loops; i++) {
125177633Sdfr		if (sleeptime)
126177633Sdfr			sleep(sleeptime);
127177633Sdfr		if (ioctl(fd, PMIOSTOP, &num) < 0)
128193437Srmacklem			err(1, "ioctl(PMIOSTOP)");
129177633Sdfr		if (ioctl(fd, PMIOREAD, &value) < 0)
130177633Sdfr			err(1, "ioctl(PMIOREAD)");
131193437Srmacklem		buf[i] = value.pmcd_value;
132193437Srmacklem		if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
133177633Sdfr			err(1, "ioctl(PMIORESET)");
134177633Sdfr		if (ioctl(fd, PMIOSTART, &num) < 0)
135177633Sdfr			err(1, "ioctl(PMIOSTART)");
136177633Sdfr	}
137180025Sdfr
138184588Sdfr	if (ioctl(fd, PMIOSTOP, &num) < 0)
139184588Sdfr		err(1, "ioctl(PMIOSTOP)");
140177633Sdfr	if (ioctl(fd, PMIOREAD, &value) < 0)
141177633Sdfr		err(1, "ioctl(PMIOREAD)");
142177633Sdfr	buf[i] = value.pmcd_value;
143177633Sdfr	if (ioctl(fd, PMIOTSTAMP, &now) < 0)
144177633Sdfr		err(1, "ioctl(PMIOTSTAMP)");
145177633Sdfr
146177633Sdfr	total = 0;
147177633Sdfr	for (i = 1; i <= loops; i++) {
148177633Sdfr		printf("%d: %qd\n", i, buf[i]);
149177633Sdfr		total += buf[i];
150177633Sdfr	}
151177633Sdfr	printf("total: %f\nmean: %f\n", total, total / loops);
152177633Sdfr
153177633Sdfr	printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
154177633Sdfr	       now.pmct_value - then.pmct_value);
155177633Sdfr
156177633Sdfr	return 0;
157184588Sdfr}
158184588Sdfr
159184588Sdfrstatic int
160177633Sdfrgetnum(const char *buf, int min, int max)
161177633Sdfr{
162184588Sdfr	char *ep;
163184588Sdfr	long l;
164184588Sdfr
165177633Sdfr	errno = 0;
166177633Sdfr	l = strtol(buf, &ep, 0);
167177633Sdfr	if (*buf && !*ep && !errno) {
168177633Sdfr		if (l < min || l > max) {
169177633Sdfr			errx(1, "`%s': must be between %d and %d",
170177633Sdfr			     buf, min, max);
171177633Sdfr		}
172177633Sdfr		return (int)l;
173177633Sdfr	} else if(errno) {
174177633Sdfr		errx(1, "`%s': must be between %ld and %ld",
175177633Sdfr		     LONG_MIN, LONG_MAX);
176177633Sdfr	}
177177633Sdfr	errx(1, "`%s': parameter must be an integer");
178177633Sdfr}
179177633Sdfr
180177633Sdfrstatic void
181177633Sdfrusage(const char *pname)
182177633Sdfr{
183177633Sdfr	fprintf(stderr,
184177633Sdfr		"%s: usage:\n\t%s [-eiou] [-l nloops] [-U unit] [-m mask] "
185177633Sdfr		"counter\n", pname, pname);
186177633Sdfr	exit(1);
187177633Sdfr}
188177633Sdfr