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