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 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/ioctl.h> 34 35 #include <machine/cpu.h> 36 #include <machine/perfmon.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <err.h> 42 #include <unistd.h> 43 #include <fcntl.h> 44 #include <limits.h> 45 #include <errno.h> 46 47 static int getnum(const char *, int, int); 48 static void usage(const char *) __dead2; 49 50 int 51 main(int argc, char **argv) 52 { 53 int c, fd, num; 54 int loops, i, sleeptime; 55 char *cmd; 56 struct pmc pmc; 57 struct pmc_tstamp then, now; 58 struct pmc_data value; 59 quad_t *buf; 60 double total; 61 62 pmc.pmc_num = 0; 63 pmc.pmc_event = 0; 64 pmc.pmc_unit = 0; 65 pmc.pmc_flags = 0; 66 pmc.pmc_mask = 0; 67 cmd = NULL; 68 loops = 50; 69 sleeptime = 0; 70 71 while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) { 72 switch(c) { 73 case 'u': 74 pmc.pmc_flags |= PMCF_USR; 75 break; 76 case 'o': 77 pmc.pmc_flags |= PMCF_OS; 78 break; 79 case 'e': 80 pmc.pmc_flags |= PMCF_E; 81 break; 82 case 'i': 83 pmc.pmc_flags |= PMCF_INV; 84 break; 85 case 'U': 86 pmc.pmc_unit = getnum(optarg, 0, 256); 87 break; 88 case 'm': 89 pmc.pmc_mask = getnum(optarg, 0, 256); 90 break; 91 case 'l': 92 loops = getnum(optarg, 1, INT_MAX - 1); 93 break; 94 case 's': 95 sleeptime = getnum(optarg, 0, INT_MAX - 1); 96 break; 97 case 'c': 98 cmd = optarg; 99 break; 100 default: 101 usage(argv[0]); 102 } 103 } 104 105 if (argc - optind != 1) 106 usage(argv[0]); 107 108 pmc.pmc_event = getnum(argv[optind], 0, 255); 109 110 buf = malloc((loops + 1) * sizeof *buf); 111 if (!buf) 112 err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf); 113 114 fd = open(_PATH_PERFMON, O_RDWR, 0); 115 if (fd < 0) 116 err(1, "open: " _PATH_PERFMON); 117 118 if (ioctl(fd, PMIOSETUP, &pmc) < 0) 119 err(1, "ioctl(PMIOSETUP)"); 120 121 if (ioctl(fd, PMIOTSTAMP, &then) < 0) 122 err(1, "ioctl(PMIOTSTAMP)"); 123 124 num = 0; 125 if (ioctl(fd, PMIOSTART, &num) < 0) 126 err(1, "ioctl(PMIOSTART)"); 127 128 value.pmcd_num = 0; 129 for (i = 0; i < loops; i++) { 130 if (ioctl(fd, PMIOSTOP, &num) < 0) 131 err(1, "ioctl(PMIOSTOP)"); 132 if (ioctl(fd, PMIOREAD, &value) < 0) 133 err(1, "ioctl(PMIOREAD)"); 134 buf[i] = value.pmcd_value; 135 if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0) 136 err(1, "ioctl(PMIORESET)"); 137 if (ioctl(fd, PMIOSTART, &num) < 0) 138 err(1, "ioctl(PMIOSTART)"); 139 if (sleeptime) 140 sleep(sleeptime); 141 if (cmd) 142 system(cmd); 143 } 144 145 if (ioctl(fd, PMIOSTOP, &num) < 0) 146 err(1, "ioctl(PMIOSTOP)"); 147 if (ioctl(fd, PMIOREAD, &value) < 0) 148 err(1, "ioctl(PMIOREAD)"); 149 buf[i] = value.pmcd_value; 150 if (ioctl(fd, PMIOTSTAMP, &now) < 0) 151 err(1, "ioctl(PMIOTSTAMP)"); 152 153 total = 0; 154 for (i = 1; i <= loops; i++) { 155 printf("%d: %qd\n", i, buf[i]); 156 total += buf[i]; 157 } 158 printf("total: %f\nmean: %f\n", total, total / loops); 159 160 printf("clocks (at %d-MHz): %qd\n", now.pmct_rate, 161 now.pmct_value - then.pmct_value); 162 163 return 0; 164 } 165 166 static int 167 getnum(const char *buf, int min, int max) 168 { 169 char *ep; 170 long l; 171 172 errno = 0; 173 l = strtol(buf, &ep, 0); 174 if (*buf && !*ep && !errno) { 175 if (l < min || l > max) { 176 errx(1, "`%s': must be between %d and %d", 177 buf, min, max); 178 } 179 return (int)l; 180 } else if(errno) { 181 errx(1, "`%s': must be between %ld and %ld", 182 LONG_MIN, LONG_MAX); 183 } 184 errx(1, "`%s': parameter must be an integer"); 185 } 186 187 static void 188 usage(const char *pname) 189 { 190 fprintf(stderr, 191 "usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n" 192 " [-U unit] counter\n", 193 pname); 194 exit(1); 195 } 196