xref: /freebsd/share/examples/perfmon/perfmon.c (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
1 /*
2  * Copyright 1996 Massachusetts Institute of Technology
3  *
4  * Permission to use, copy, modify, and distribute this software and
5  * its documentation for any purpose and without fee is hereby
6  * granted, provided that both the above copyright notice and this
7  * permission notice appear in all copies, that both the above
8  * copyright notice and this permission notice appear in all
9  * supporting documentation, and that the name of M.I.T. not be used
10  * in advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.  M.I.T. makes
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied
14  * warranty.
15  *
16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 
33 #include <machine/cpu.h>
34 #include <machine/perfmon.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <err.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <errno.h>
44 
45 static int getnum(const char *, int, int);
46 static void usage(const char *) __dead2;
47 
48 int
49 main(int argc, char **argv)
50 {
51 	int c, fd, num;
52 	int loops, i, sleeptime;
53 	char *cmd;
54 	struct pmc pmc;
55 	struct pmc_tstamp then, now;
56 	struct pmc_data value;
57 	quad_t *buf;
58 	double total;
59 
60 	pmc.pmc_num = 0;
61 	pmc.pmc_event = 0;
62 	pmc.pmc_unit = 0;
63 	pmc.pmc_flags = 0;
64 	pmc.pmc_mask = 0;
65 	cmd = NULL;
66 	loops = 50;
67 	sleeptime = 0;
68 
69 	while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) {
70 		switch(c) {
71 		case 'u':
72 			pmc.pmc_flags |= PMCF_USR;
73 			break;
74 		case 'o':
75 			pmc.pmc_flags |= PMCF_OS;
76 			break;
77 		case 'e':
78 			pmc.pmc_flags |= PMCF_E;
79 			break;
80 		case 'i':
81 			pmc.pmc_flags |= PMCF_INV;
82 			break;
83 		case 'U':
84 			pmc.pmc_unit = getnum(optarg, 0, 256);
85 			break;
86 		case 'm':
87 			pmc.pmc_mask = getnum(optarg, 0, 256);
88 			break;
89 		case 'l':
90 			loops = getnum(optarg, 1, INT_MAX - 1);
91 			break;
92 		case 's':
93 			sleeptime = getnum(optarg, 0, INT_MAX - 1);
94 			break;
95 		case 'c':
96 			cmd = optarg;
97 			break;
98 		default:
99 			usage(argv[0]);
100 		}
101 	}
102 
103 	if (argc - optind != 1)
104 		usage(argv[0]);
105 
106 	pmc.pmc_event = getnum(argv[optind], 0, 255);
107 
108 	buf = malloc((loops + 1) * sizeof *buf);
109 	if (!buf)
110 		err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
111 
112 	fd = open(_PATH_PERFMON, O_RDWR, 0);
113 	if (fd < 0)
114 		err(1, "open: " _PATH_PERFMON);
115 
116 	if (ioctl(fd, PMIOSETUP, &pmc) < 0)
117 		err(1, "ioctl(PMIOSETUP)");
118 
119 	if (ioctl(fd, PMIOTSTAMP, &then) < 0)
120 		err(1, "ioctl(PMIOTSTAMP)");
121 
122 	num = 0;
123 	if (ioctl(fd, PMIOSTART, &num) < 0)
124 		err(1, "ioctl(PMIOSTART)");
125 
126 	value.pmcd_num = 0;
127 	for (i = 0; i < loops; i++) {
128 		if (ioctl(fd, PMIOSTOP, &num) < 0)
129 			err(1, "ioctl(PMIOSTOP)");
130 		if (ioctl(fd, PMIOREAD, &value) < 0)
131 			err(1, "ioctl(PMIOREAD)");
132 		buf[i] = value.pmcd_value;
133 		if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
134 			err(1, "ioctl(PMIORESET)");
135 		if (ioctl(fd, PMIOSTART, &num) < 0)
136 			err(1, "ioctl(PMIOSTART)");
137 		if (sleeptime)
138 			sleep(sleeptime);
139 		if (cmd)
140 			system(cmd);
141 	}
142 
143 	if (ioctl(fd, PMIOSTOP, &num) < 0)
144 		err(1, "ioctl(PMIOSTOP)");
145 	if (ioctl(fd, PMIOREAD, &value) < 0)
146 		err(1, "ioctl(PMIOREAD)");
147 	buf[i] = value.pmcd_value;
148 	if (ioctl(fd, PMIOTSTAMP, &now) < 0)
149 		err(1, "ioctl(PMIOTSTAMP)");
150 
151 	total = 0;
152 	for (i = 1; i <= loops; i++) {
153 		printf("%d: %qd\n", i, buf[i]);
154 		total += buf[i];
155 	}
156 	printf("total: %f\nmean: %f\n", total, total / loops);
157 
158 	printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
159 	       now.pmct_value - then.pmct_value);
160 
161 	return 0;
162 }
163 
164 static int
165 getnum(const char *buf, int min, int max)
166 {
167 	char *ep;
168 	long l;
169 
170 	errno = 0;
171 	l = strtol(buf, &ep, 0);
172 	if (*buf && !*ep && !errno) {
173 		if (l < min || l > max) {
174 			errx(1, "%s: must be between %d and %d",
175 			     buf, min, max);
176 		}
177 		return (int)l;
178 	}
179 
180 	errx(1, "%s: parameter must be an integer", buf);
181 }
182 
183 static void
184 usage(const char *pname)
185 {
186 	fprintf(stderr,
187 	"usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n"
188 	"       [-U unit] counter\n",
189 		pname);
190 	exit(1);
191 }
192