perfmon.c revision 21673
1100616Smp/* 259243Sobrien * Copyright 1996 Massachusetts Institute of Technology 359243Sobrien * 459243Sobrien * Permission to use, copy, modify, and distribute this software and 559243Sobrien * its documentation for any purpose and without fee is hereby 659243Sobrien * granted, provided that both the above copyright notice and this 759243Sobrien * permission notice appear in all copies, that both the above 859243Sobrien * copyright notice and this permission notice appear in all 959243Sobrien * supporting documentation, and that the name of M.I.T. not be used 1059243Sobrien * in advertising or publicity pertaining to distribution of the 1159243Sobrien * software without specific, written prior permission. M.I.T. makes 1259243Sobrien * no representations about the suitability of this software for any 1359243Sobrien * purpose. It is provided "as is" without express or implied 1459243Sobrien * warranty. 1559243Sobrien * 1659243Sobrien * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17100616Smp * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1859243Sobrien * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1959243Sobrien * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2059243Sobrien * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2159243Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2259243Sobrien * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2359243Sobrien * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2459243Sobrien * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2559243Sobrien * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2659243Sobrien * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2759243Sobrien * SUCH DAMAGE. 2859243Sobrien * 2959243Sobrien * $FreeBSD: head/share/examples/perfmon/perfmon.c 21673 1997-01-14 07:20:47Z jkh $ 3059243Sobrien */ 3159243Sobrien 3259243Sobrien#include <sys/types.h> 3359243Sobrien#include <sys/ioctl.h> 3459243Sobrien 3559243Sobrien#include <machine/cpu.h> 3659243Sobrien#include <machine/perfmon.h> 3759243Sobrien 3859243Sobrien#include <stdio.h> 3959243Sobrien#include <stdlib.h> 4069408Sache#include <string.h> 4159243Sobrien#include <err.h> 4259243Sobrien#include <unistd.h> 4359243Sobrien#include <fcntl.h> 4459243Sobrien#include <limits.h> 4569408Sache#include <errno.h> 4659243Sobrien 4759243Sobrienstatic int getnum(const char *, int, int); 4859243Sobrienstatic void __dead usage(const char *) __dead2; 4959243Sobrien 5059243Sobrienint 5159243Sobrienmain(int argc, char **argv) 5259243Sobrien{ 5359243Sobrien int c, fd, num; 5459243Sobrien int loops, i, sleeptime; 5559243Sobrien struct pmc pmc; 5659243Sobrien struct pmc_tstamp then, now; 5759243Sobrien struct pmc_data value; 5859243Sobrien quad_t *buf; 5959243Sobrien double total; 6059243Sobrien 6159243Sobrien pmc.pmc_num = 0; 6259243Sobrien pmc.pmc_event = 0; 6359243Sobrien pmc.pmc_unit = 0; 6459243Sobrien pmc.pmc_flags = 0; 6559243Sobrien pmc.pmc_mask = 0; 6659243Sobrien loops = 50; 6759243Sobrien sleeptime = 0; 6859243Sobrien 6959243Sobrien while ((c = getopt(argc, argv, "s:l:uoeiU:m:")) != EOF) { 7059243Sobrien switch(c) { 7159243Sobrien case 'u': 7259243Sobrien pmc.pmc_flags |= PMCF_USR; 7359243Sobrien break; 7459243Sobrien case 'o': 7559243Sobrien pmc.pmc_flags |= PMCF_OS; 7659243Sobrien break; 7759243Sobrien case 'e': 7859243Sobrien pmc.pmc_flags |= PMCF_E; 7959243Sobrien break; 8059243Sobrien case 'i': 8159243Sobrien pmc.pmc_flags |= PMCF_INV; 8259243Sobrien break; 8359243Sobrien case 'U': 8459243Sobrien pmc.pmc_unit = getnum(optarg, 0, 256); 8559243Sobrien break; 8659243Sobrien case 'm': 8759243Sobrien pmc.pmc_mask = getnum(optarg, 0, 256); 8859243Sobrien break; 8959243Sobrien case 'l': 9059243Sobrien loops = getnum(optarg, 1, INT_MAX - 1); 9159243Sobrien break; 9259243Sobrien case 's': 9359243Sobrien sleeptime = getnum(optarg, 0, INT_MAX - 1); 9459243Sobrien break; 9583098Smp default: 9659243Sobrien usage(argv[0]); 9759243Sobrien } 9859243Sobrien } 9959243Sobrien 10059243Sobrien if (argc - optind != 1) 10159243Sobrien usage(argv[0]); 10259243Sobrien 10359243Sobrien pmc.pmc_event = getnum(argv[optind], 0, 255); 10459243Sobrien 10559243Sobrien buf = malloc((loops + 1) * sizeof *buf); 10659243Sobrien if (!buf) 10759243Sobrien err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf); 10859243Sobrien 10959243Sobrien fd = open(_PATH_PERFMON, O_RDWR, 0); 11059243Sobrien if (fd < 0) 11159243Sobrien err(1, "open: " _PATH_PERFMON); 11259243Sobrien 11359243Sobrien if (ioctl(fd, PMIOSETUP, &pmc) < 0) 11459243Sobrien err(1, "ioctl(PMIOSETUP)"); 11559243Sobrien 11659243Sobrien if (ioctl(fd, PMIOTSTAMP, &then) < 0) 11759243Sobrien err(1, "ioctl(PMIOTSTAMP)"); 11859243Sobrien 11959243Sobrien num = 0; 12059243Sobrien if (ioctl(fd, PMIOSTART, &num) < 0) 12159243Sobrien err(1, "ioctl(PMIOSTART)"); 12259243Sobrien 12359243Sobrien value.pmcd_num = 0; 12459243Sobrien for (i = 0; i < loops; i++) { 12559243Sobrien if (sleeptime) 12659243Sobrien sleep(sleeptime); 12759243Sobrien if (ioctl(fd, PMIOSTOP, &num) < 0) 12859243Sobrien err(1, "ioctl(PMIOSTOP)"); 12959243Sobrien if (ioctl(fd, PMIOREAD, &value) < 0) 13059243Sobrien err(1, "ioctl(PMIOREAD)"); 13159243Sobrien buf[i] = value.pmcd_value; 13259243Sobrien if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0) 13359243Sobrien err(1, "ioctl(PMIORESET)"); 13459243Sobrien if (ioctl(fd, PMIOSTART, &num) < 0) 13559243Sobrien err(1, "ioctl(PMIOSTART)"); 13659243Sobrien } 13759243Sobrien 13859243Sobrien if (ioctl(fd, PMIOSTOP, &num) < 0) 13959243Sobrien err(1, "ioctl(PMIOSTOP)"); 14059243Sobrien if (ioctl(fd, PMIOREAD, &value) < 0) 14159243Sobrien err(1, "ioctl(PMIOREAD)"); 14259243Sobrien buf[i] = value.pmcd_value; 14359243Sobrien if (ioctl(fd, PMIOTSTAMP, &now) < 0) 14459243Sobrien err(1, "ioctl(PMIOTSTAMP)"); 14559243Sobrien 14659243Sobrien total = 0; 14759243Sobrien for (i = 1; i <= loops; i++) { 14859243Sobrien printf("%d: %qd\n", i, buf[i]); 14959243Sobrien total += buf[i]; 15059243Sobrien } 15159243Sobrien printf("total: %f\nmean: %f\n", total, total / loops); 15259243Sobrien 15359243Sobrien printf("clocks (at %d-MHz): %qd\n", now.pmct_rate, 15459243Sobrien now.pmct_value - then.pmct_value); 15559243Sobrien 15659243Sobrien return 0; 15759243Sobrien} 15859243Sobrien 15959243Sobrienstatic int 16059243Sobriengetnum(const char *buf, int min, int max) 16159243Sobrien{ 16259243Sobrien char *ep; 16359243Sobrien long l; 16459243Sobrien 16559243Sobrien errno = 0; 16659243Sobrien l = strtol(buf, &ep, 0); 16759243Sobrien if (*buf && !*ep && !errno) { 16859243Sobrien if (l < min || l > max) { 16959243Sobrien errx(1, "`%s': must be between %d and %d", 17059243Sobrien buf, min, max); 17159243Sobrien } 17259243Sobrien return (int)l; 17359243Sobrien } else if(errno) { 17459243Sobrien errx(1, "`%s': must be between %ld and %ld", 17559243Sobrien LONG_MIN, LONG_MAX); 17659243Sobrien } 17759243Sobrien errx(1, "`%s': parameter must be an integer"); 17859243Sobrien} 17959243Sobrien 18059243Sobrienstatic void 18159243Sobrienusage(const char *pname) 18259243Sobrien{ 18359243Sobrien fprintf(stderr, 18459243Sobrien "%s: usage:\n\t%s [-eiou] [-l nloops] [-U unit] [-m mask] " 18559243Sobrien "counter\n", pname, pname); 18659243Sobrien exit(1); 18759243Sobrien} 18859243Sobrien