iowatcher: Add initial support for flash tracing
[blktrace.git] / iowatcher / tracers.c
1 /*
2  * Copyright (C) 2012 Fusion-io
3  *
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.
7  *
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.
12  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  *  Parts of this file were imported from Jens Axboe's blktrace sources (also GPL)
18  */
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <inttypes.h>
27 #include <string.h>
28 #include <asm/types.h>
29 #include <errno.h>
30 #include <sys/mman.h>
31 #include <time.h>
32 #include <signal.h>
33 #include <sys/wait.h>
34
35 #include "plot.h"
36 #include "blkparse.h"
37 #include "list.h"
38
39 static int line_len = 1024;
40 static char line[1024];
41
42 static pid_t blktrace_pid = 0;
43 static pid_t mpstat_pid = 0;
44
45 char *blktrace_args[] = {
46         "blktrace",
47         "-d", NULL,
48         "-b", "16384",
49         "-o", "trace",
50         "-D", ".",
51         "-a", "queue",
52         "-a", "complete",
53         "-a", "issue",
54         "-a", "notify",
55         NULL,
56 };
57
58 char *mpstat_args[] = {
59         "mpstat",
60         "-P", "ALL", "1",
61         NULL,
62 };
63
64 #define DEVICE_INDEX 2
65 #define DEST_DIR_INDEX 8
66 #define TRACE_NAME_INDEX 6
67
68 int stop_tracer(pid_t *tracer_pid)
69 {
70         int ret;
71         pid_t pid = *tracer_pid;
72         pid_t pid_ret;
73         int status = 0;
74
75         if (pid == 0)
76                 return 0;
77
78         *tracer_pid = 0;
79         ret = kill(pid, SIGTERM);
80         if (ret) {
81                 fprintf(stderr, "failed to stop tracer pid %lu error %s\n",
82                         (unsigned long)pid, strerror(errno));
83                 return -errno;
84         }
85         pid_ret = waitpid(pid, &status, WUNTRACED);
86         if (pid_ret == pid && WIFEXITED(status) == 0) {
87                 fprintf(stderr, "blktrace returns error %d\n", WEXITSTATUS(status));
88         }
89         return 0;
90 }
91
92
93 void stop_all_tracers(void)
94 {
95         stop_tracer(&blktrace_pid);
96         stop_tracer(&mpstat_pid);
97 }
98
99 void sig_handler_for_quit(int val)
100 {
101         fprintf(stderr, "iowatcher exiting with %d, stopping tracers\n", val);
102         stop_all_tracers();
103 }
104
105
106 int start_blktrace(char *device, char *trace_name, char *dest)
107 {
108         pid_t pid;
109         int ret;
110         char **arg = blktrace_args;
111         blktrace_args[DEVICE_INDEX] = device;
112
113         fprintf(stderr, "running blktrace");
114         if (dest)
115                 blktrace_args[DEST_DIR_INDEX] = dest;
116         if (trace_name)
117                 blktrace_args[TRACE_NAME_INDEX] = trace_name;
118
119         while(*arg) {
120                 fprintf(stderr, " %s", *arg);
121                 arg++;
122         }
123         fprintf(stderr, "\n");
124
125
126         pid = fork();
127         if (pid == 0) {
128                 ret = execvp("blktrace", blktrace_args);
129                 if (ret) {
130                         fprintf(stderr, "failed to exec blktrace error %s\n", strerror(errno));
131                         exit(errno);
132                 }
133
134         } else {
135                 blktrace_pid = pid;
136                 signal(SIGTERM, sig_handler_for_quit);
137                 signal(SIGINT, sig_handler_for_quit);
138         }
139         return 0;
140 }
141
142 int run_program(char *str)
143 {
144         int ret;
145
146         fprintf(stderr, "running program %s\n", str);
147         ret = system(str);
148         if (ret == -1) {
149                 fprintf(stderr, "failed to run program %s error %s\n", str, strerror(errno));
150                 stop_all_tracers();
151                 return -errno;
152         }
153         stop_all_tracers();
154         return 0;
155 }
156
157 int wait_for_tracers(void)
158 {
159         int status = 0;
160         if (blktrace_pid != 0) {
161                 waitpid(blktrace_pid, &status, WUNTRACED);
162                 blktrace_pid = 0;
163         }
164         if (mpstat_pid != 0) {
165                 waitpid(mpstat_pid, &status, WUNTRACED);
166                 mpstat_pid = 0;
167         }
168         return 0;
169 }
170
171 int blktrace_to_dump(char *trace_name)
172 {
173         snprintf(line, line_len, "blkparse -O -i %s -d '%s.%s'",
174                 trace_name, trace_name, "dump");
175
176         system(line);
177         return 0;
178 }
179
180 int start_mpstat(char *trace_name)
181 {
182         int fd;
183         pid_t pid;
184
185         snprintf(line, line_len, "%s.mpstat", trace_name);
186
187         fd = open(line, O_WRONLY | O_CREAT | O_TRUNC);
188         if (fd < 0) {
189                 fprintf(stderr, "unable to open %s for writing err %s\n",
190                         line, strerror(errno));
191                 exit(1);
192         }
193         pid = fork();
194         if (pid == 0) {
195                 int ret;
196
197                 close(1);
198                 ret = dup2(fd, 1);
199                 if (ret < 0) {
200                         fprintf(stderr, "failed to setup output file for mpstat\n");
201                         exit(1);
202                 }
203                 ret = execvp("mpstat", mpstat_args);
204                 if (ret < 0) {
205                         fprintf(stderr, "failed to exec mpstat err %s\n",
206                                 strerror(ret));
207                         exit(1);
208                 }
209         }
210         mpstat_pid = pid;
211         return 0;
212 }