tprof.c revision 1.6
1/* $NetBSD: tprof.c,v 1.6 2018/07/13 07:56:29 maxv Exp $ */ 2 3/* 4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Maxime Villard. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c)2008 YAMAMOTO Takashi, 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58#include <sys/cdefs.h> 59#ifndef lint 60__RCSID("$NetBSD: tprof.c,v 1.6 2018/07/13 07:56:29 maxv Exp $"); 61#endif /* not lint */ 62 63#include <sys/ioctl.h> 64#include <sys/wait.h> 65 66#include <dev/tprof/tprof_ioctl.h> 67 68#include <err.h> 69#include <errno.h> 70#include <fcntl.h> 71#include <inttypes.h> 72#include <pthread.h> 73#include <signal.h> 74#include <stdbool.h> 75#include <stdio.h> 76#include <stdlib.h> 77#include <string.h> 78#include <unistd.h> 79#include "tprof.h" 80 81#define _PATH_TPROF "/dev/tprof" 82 83int devfd; 84int outfd; 85 86__dead static void 87usage(void) 88{ 89 90 fprintf(stderr, "%s [options] command ...\n", getprogname()); 91 fprintf(stderr, "\n"); 92 fprintf(stderr, "-e name:{u}{k}\t" 93 "the event to count.\n"); 94 fprintf(stderr, "-l\t\t" 95 "list the events.\n"); 96 fprintf(stderr, "-o filename\t" 97 "output to the file. [default: -o tprof.out]\n"); 98 fprintf(stderr, "-c\t\t" 99 "output to stdout. NOTE: the output is a binary stream.\n"); 100 101 exit(EXIT_FAILURE); 102} 103 104static void * 105process_samples(void *dummy) 106{ 107 108 for (;;) { 109 char buf[4096]; 110 const char *cp; 111 ssize_t ssz; 112 113 ssz = read(devfd, buf, sizeof(buf)); 114 if (ssz == -1) { 115 err(EXIT_FAILURE, "read"); 116 } 117 if (ssz == 0) { 118 break; 119 } 120 cp = buf; 121 while (ssz) { 122 ssize_t wsz; 123 124 wsz = write(outfd, cp, ssz); 125 if (wsz == -1) { 126 err(EXIT_FAILURE, "write"); 127 } 128 ssz -= wsz; 129 cp += wsz; 130 } 131 } 132 return NULL; 133} 134 135int 136main(int argc, char *argv[]) 137{ 138 struct tprof_param param; 139 struct tprof_info info; 140 struct tprof_stat ts; 141 const char *outfile = "tprof.out"; 142 bool cflag = false; 143 pid_t pid; 144 pthread_t pt; 145 int error; 146 int ret; 147 int ch; 148 char *tokens[2]; 149 150 memset(¶m, 0, sizeof(param)); 151 152 devfd = open(_PATH_TPROF, O_RDWR); 153 if (devfd == -1) { 154 err(EXIT_FAILURE, "%s", _PATH_TPROF); 155 } 156 157 ret = ioctl(devfd, TPROF_IOC_GETINFO, &info); 158 if (ret == -1) { 159 err(EXIT_FAILURE, "TPROF_IOC_GETINFO"); 160 } 161 if (info.ti_version != TPROF_VERSION) { 162 errx(EXIT_FAILURE, "version mismatch: version=%d, expected=%d", 163 info.ti_version, TPROF_VERSION); 164 } 165 if (tprof_event_init(info.ti_ident) == -1) { 166 err(EXIT_FAILURE, "cpu not supported"); 167 } 168 169 while ((ch = getopt(argc, argv, "clo:e:")) != -1) { 170 switch (ch) { 171 case 'c': 172 cflag = true; 173 break; 174 case 'l': 175 tprof_event_list(); 176 return 0; 177 case 'o': 178 outfile = optarg; 179 break; 180 case 'e': 181 tokens[0] = strtok(optarg, ":"); 182 tokens[1] = strtok(NULL, ":"); 183 if (tokens[1] == NULL) 184 usage(); 185 tprof_event_lookup(tokens[0], ¶m); 186 if (strchr(tokens[1], 'u')) 187 param.p_flags |= TPROF_PARAM_USER; 188 if (strchr(tokens[1], 'k')) 189 param.p_flags |= TPROF_PARAM_KERN; 190 break; 191 default: 192 usage(); 193 } 194 } 195 argc -= optind; 196 argv += optind; 197 if (argc == 0) { 198 usage(); 199 } 200 201 if (param.p_flags == 0) { 202 usage(); 203 } 204 205 if (cflag) { 206 outfd = STDOUT_FILENO; 207 } else { 208 outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); 209 if (outfd == -1) { 210 err(EXIT_FAILURE, "%s", outfile); 211 } 212 } 213 214 ret = ioctl(devfd, TPROF_IOC_START, ¶m); 215 if (ret == -1) { 216 err(EXIT_FAILURE, "TPROF_IOC_START"); 217 } 218 219 pid = fork(); 220 switch (pid) { 221 case -1: 222 err(EXIT_FAILURE, "fork"); 223 case 0: 224 close(devfd); 225 execvp(argv[0], argv); 226 _Exit(EXIT_FAILURE); 227 } 228 229 signal(SIGINT, SIG_IGN); 230 231 error = pthread_create(&pt, NULL, process_samples, NULL); 232 if (error != 0) { 233 errx(1, "pthread_create: %s", strerror(error)); 234 } 235 236 for (;;) { 237 int status; 238 239 pid = wait4(-1, &status, 0, NULL); 240 if (pid == -1) { 241 if (errno == ECHILD) { 242 break; 243 } 244 err(EXIT_FAILURE, "wait4"); 245 } 246 if (pid != 0 && WIFEXITED(status)) { 247 break; 248 } 249 } 250 251 ret = ioctl(devfd, TPROF_IOC_STOP, NULL); 252 if (ret == -1) { 253 err(EXIT_FAILURE, "TPROF_IOC_STOP"); 254 } 255 256 pthread_join(pt, NULL); 257 258 ret = ioctl(devfd, TPROF_IOC_GETSTAT, &ts); 259 if (ret == -1) { 260 err(EXIT_FAILURE, "TPROF_IOC_GETSTAT"); 261 } 262 263 fprintf(stderr, "\n%s statistics:\n", getprogname()); 264 fprintf(stderr, "\tsample %" PRIu64 "\n", ts.ts_sample); 265 fprintf(stderr, "\toverflow %" PRIu64 "\n", ts.ts_overflow); 266 fprintf(stderr, "\tbuf %" PRIu64 "\n", ts.ts_buf); 267 fprintf(stderr, "\temptybuf %" PRIu64 "\n", ts.ts_emptybuf); 268 fprintf(stderr, "\tdropbuf %" PRIu64 "\n", ts.ts_dropbuf); 269 fprintf(stderr, "\tdropbuf_sample %" PRIu64 "\n", ts.ts_dropbuf_sample); 270 271 exit(EXIT_SUCCESS); 272} 273