tprof.c revision 1.1
1/* $NetBSD: tprof.c,v 1.1 2008/01/01 21:33:26 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.1 2008/01/01 21:33:26 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 [-c] [-o outfile] command ...\n", getprogname()); 61 62 exit(EXIT_FAILURE); 63} 64 65static void * 66process_samples(void *dummy) 67{ 68 69 for (;;) { 70 char buf[4096]; 71 const char *cp; 72 ssize_t ssz; 73 74 ssz = read(devfd, buf, sizeof(buf)); 75 if (ssz == -1) { 76 err(EXIT_FAILURE, "read"); 77 } 78 if (ssz == 0) { 79 break; 80 } 81 cp = buf; 82 while (ssz) { 83 ssize_t wsz; 84 85 wsz = write(outfd, cp, ssz); 86 if (wsz == -1) { 87 err(EXIT_FAILURE, "write"); 88 } 89 ssz -= wsz; 90 cp += wsz; 91 } 92 } 93 return NULL; 94} 95 96int 97main(int argc, char *argv[]) 98{ 99 struct tprof_param param; 100 struct tprof_stat ts; 101 const char *outfile = "tprof.out"; 102 bool cflag = false; 103 pid_t pid; 104 pthread_t pt; 105 int error; 106 int ret; 107 int ch; 108 int version; 109 110 while ((ch = getopt(argc, argv, "co:")) != -1) { 111 switch (ch) { 112 case 'c': 113 cflag = true; 114 break; 115 case 'o': 116 outfile = optarg; 117 break; 118 default: 119 usage(); 120 } 121 } 122 argc -= optind; 123 argv += optind; 124 if (argc == 0) { 125 usage(); 126 } 127 128 if (cflag) { 129 outfd = STDOUT_FILENO; 130 } else { 131 outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); 132 if (outfd == -1) { 133 err(EXIT_FAILURE, "%s", optarg); 134 } 135 } 136 137 devfd = open(_PATH_TPROF, O_RDWR); 138 if (devfd == -1) { 139 err(EXIT_SUCCESS, "%s", _PATH_TPROF); 140 } 141 142 ret = ioctl(devfd, TPROF_IOC_GETVERSION, &version); 143 if (ret == -1) { 144 err(EXIT_SUCCESS, "TPROF_IOC_GETVERSION"); 145 } 146 if (version != TPROF_VERSION) { 147 errx(EXIT_SUCCESS, "version mismatch: version=%d, expected=%d", 148 version, TPROF_VERSION); 149 } 150 151 memset(¶m, 0, sizeof(param)); 152 ret = ioctl(devfd, TPROF_IOC_START, ¶m); 153 if (ret == -1) { 154 err(EXIT_SUCCESS, "TPROF_IOC_START"); 155 } 156 157 pid = fork(); 158 switch (pid) { 159 case -1: 160 err(EXIT_FAILURE, "fork"); 161 case 0: 162 close(devfd); 163 execvp(argv[0], argv); 164 _Exit(EXIT_FAILURE); 165 } 166 167 signal(SIGINT, SIG_IGN); 168 169 error = pthread_create(&pt, NULL, process_samples, NULL); 170 if (error != 0) { 171 errx(1, "pthread_create: %s", strerror(error)); 172 } 173 174 for (;;) { 175 int status; 176 177 pid = wait4(-1, &status, 0, NULL); 178 if (pid == -1) { 179 if (errno == ECHILD) { 180 break; 181 } 182 err(EXIT_FAILURE, "wait4"); 183 } 184 if (pid != 0 && WIFEXITED(status)) { 185 break; 186 } 187 } 188 189 ret = ioctl(devfd, TPROF_IOC_STOP, NULL); 190 if (ret == -1) { 191 err(EXIT_FAILURE, "TPROF_IOC_STOP"); 192 } 193 194 pthread_join(pt, NULL); 195 196 ret = ioctl(devfd, TPROF_IOC_GETSTAT, &ts); 197 if (ret == -1) { 198 err(EXIT_FAILURE, "TPROF_IOC_GETSTAT"); 199 } 200 201 fprintf(stderr, "\n%s statistics:\n", getprogname()); 202 fprintf(stderr, "\tsample %" PRIu64 "\n", ts.ts_sample); 203 fprintf(stderr, "\toverflow %" PRIu64 "\n", ts.ts_overflow); 204 fprintf(stderr, "\tbuf %" PRIu64 "\n", ts.ts_buf); 205 fprintf(stderr, "\temptybuf %" PRIu64 "\n", ts.ts_emptybuf); 206 fprintf(stderr, "\tdropbuf %" PRIu64 "\n", ts.ts_dropbuf); 207 fprintf(stderr, "\tdropbuf_sample %" PRIu64 "\n", ts.ts_dropbuf_sample); 208 209 exit(EXIT_SUCCESS); 210} 211