2 * Copyright (C) 2012 Fusion-io
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 * Parts of this file were imported from Jens Axboe's blktrace sources (also GPL)
19 #include <sys/types.h>
28 #include <asm/types.h>
41 extern char **environ;
43 static int line_len = 1024;
44 static char line[1024];
46 static pid_t blktrace_pid = 0;
47 static pid_t mpstat_pid = 0;
49 char *mpstat_args[] = {
55 int stop_tracer(pid_t *tracer_pid)
58 pid_t pid = *tracer_pid;
66 ret = kill(pid, SIGTERM);
68 fprintf(stderr, "failed to stop tracer pid %lu error %s\n",
69 (unsigned long)pid, strerror(errno));
72 pid_ret = waitpid(pid, &status, WUNTRACED);
73 if (pid_ret == pid && WIFEXITED(status) == 0) {
74 fprintf(stderr, "blktrace returns error %d\n", WEXITSTATUS(status));
79 static void sig_handler_for_quit(int val)
81 fprintf(stderr, "Received signal %d. Terminating tracers.\n", val);
83 wait_program(blktrace_pid, "blktrace", SIGTERM);
86 stop_tracer(&mpstat_pid);
89 int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest)
93 char *argv[15 + MAX_DEVICES_PER_TRACE * 2];
101 argv[argc++] = "blktrace";
103 argv[argc++] = "8192";
105 argv[argc++] = "queue";
107 argv[argc++] = "complete";
109 argv[argc++] = "issue";
111 argv[argc++] = "notify";
113 if (num_devices == 1) {
115 argv[argc++] = trace_name;
117 /* Multiple devices output to a directory named trace_name */
123 for (i = 0; i < num_devices; i++) {
125 argv[argc++] = devices[i];
128 signal(SIGTERM, sig_handler_for_quit);
129 signal(SIGINT, sig_handler_for_quit);
130 ret = run_program(argc, argv, 0, &blktrace_pid);
134 int wait_program(pid_t pid, const char *pname, int sig)
140 ret = kill(pid, sig);
142 fprintf(stderr, "Failed to send signal %d to %s (%lu): %s\n",
143 sig, pname, (long)pid, strerror(errno));
146 fprintf(stderr, "Kill (%d): %s (%ld)\n", sig, pname, (long)pid);
149 waitpid(pid, &status, 0);
150 if (WIFEXITED(status)) {
151 ret = WEXITSTATUS(status);
152 if (ret == 127) /* spawnp failed after forking */
153 fprintf(stderr, "Failed to run '%s'\n", pname);
154 } else if (WIFSIGNALED(status) && sig && WTERMSIG(status) != sig) {
155 fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status));
161 int run_program(int argc, char **argv, int wait, pid_t *pid)
167 fprintf(stderr, "running");
168 for (i = 0; i < argc; i++)
169 fprintf(stderr, " '%s'", argv[i]);
170 fprintf(stderr, "\n");
172 err = posix_spawnp(&_pid, argv[0], NULL, NULL, argv, environ);
174 fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err));
176 err = wait_program(_pid, argv[0], 0);
178 fprintf(stderr, "Warning: %s (%ld): Not saving pid and not waiting for it.\n",
179 argv[0], (long)_pid);
186 int wait_for_tracers(void)
188 if (blktrace_pid != 0) {
189 int err = wait_program(blktrace_pid, "blktrace", SIGINT);
194 if (mpstat_pid != 0) {
196 stop_tracer(&mpstat_pid);
197 waitpid(mpstat_pid, &status, WUNTRACED);
203 int start_mpstat(char *trace_name)
208 snprintf(line, line_len, "%s.mpstat", trace_name);
210 fd = open(line, O_WRONLY | O_CREAT | O_TRUNC, 0600);
212 fprintf(stderr, "unable to open %s for writing err %s\n",
213 line, strerror(errno));
223 fprintf(stderr, "failed to setup output file for mpstat\n");
226 ret = execvp("mpstat", mpstat_args);
228 fprintf(stderr, "failed to exec mpstat err %s\n",