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