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 * $Id$ 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 __dead 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 struct pmc pmc; 56 struct pmc_tstamp then, now; 57 struct pmc_data value; 58 quad_t *buf; 59 double total; 60 61 pmc.pmc_num = 0; 62 pmc.pmc_event = 0; 63 pmc.pmc_unit = 0; 64 pmc.pmc_flags = 0; 65 pmc.pmc_mask = 0; 66 loops = 50; 67 sleeptime = 0; 68 69 while ((c = getopt(argc, argv, "s:l:uoeiU:m:")) != EOF) { 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 default: 96 usage(argv[0]); 97 } 98 } 99 100 if (argc - optind != 1) 101 usage(argv[0]); 102 103 pmc.pmc_event = getnum(argv[optind], 0, 255); 104 105 buf = malloc((loops + 1) * sizeof *buf); 106 if (!buf) 107 err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf); 108 109 fd = open(_PATH_PERFMON, O_RDWR, 0); 110 if (fd < 0) 111 err(1, "open: " _PATH_PERFMON); 112 113 if (ioctl(fd, PMIOSETUP, &pmc) < 0) 114 err(1, "ioctl(PMIOSETUP)"); 115 116 if (ioctl(fd, PMIOTSTAMP, &then) < 0) 117 err(1, "ioctl(PMIOTSTAMP)"); 118 119 num = 0; 120 if (ioctl(fd, PMIOSTART, &num) < 0) 121 err(1, "ioctl(PMIOSTART)"); 122 123 value.pmcd_num = 0; 124 for (i = 0; i < loops; i++) { 125 if (sleeptime) 126 sleep(sleeptime); 127 if (ioctl(fd, PMIOSTOP, &num) < 0) 128 err(1, "ioctl(PMIOSTOP)"); 129 if (ioctl(fd, PMIOREAD, &value) < 0) 130 err(1, "ioctl(PMIOREAD)"); 131 buf[i] = value.pmcd_value; 132 if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0) 133 err(1, "ioctl(PMIORESET)"); 134 if (ioctl(fd, PMIOSTART, &num) < 0) 135 err(1, "ioctl(PMIOSTART)"); 136 } 137 138 if (ioctl(fd, PMIOSTOP, &num) < 0) 139 err(1, "ioctl(PMIOSTOP)"); 140 if (ioctl(fd, PMIOREAD, &value) < 0) 141 err(1, "ioctl(PMIOREAD)"); 142 buf[i] = value.pmcd_value; 143 if (ioctl(fd, PMIOTSTAMP, &now) < 0) 144 err(1, "ioctl(PMIOTSTAMP)"); 145 146 total = 0; 147 for (i = 1; i <= loops; i++) { 148 printf("%d: %qd\n", i, buf[i]); 149 total += buf[i]; 150 } 151 printf("total: %f\nmean: %f\n", total, total / loops); 152 153 printf("clocks (at %d-MHz): %qd\n", now.pmct_rate, 154 now.pmct_value - then.pmct_value); 155 156 return 0; 157 } 158 159 static int 160 getnum(const char *buf, int min, int max) 161 { 162 char *ep; 163 long l; 164 165 errno = 0; 166 l = strtol(buf, &ep, 0); 167 if (*buf && !*ep && !errno) { 168 if (l < min || l > max) { 169 errx(1, "`%s': must be between %d and %d", 170 buf, min, max); 171 } 172 return (int)l; 173 } else if(errno) { 174 errx(1, "`%s': must be between %ld and %ld", 175 LONG_MIN, LONG_MAX); 176 } 177 errx(1, "`%s': parameter must be an integer"); 178 } 179 180 static void 181 usage(const char *pname) 182 { 183 fprintf(stderr, 184 "%s: usage:\n\t%s [-eiou] [-l nloops] [-U unit] [-m mask] " 185 "counter\n", pname, pname); 186 exit(1); 187 } 188