Commit | Line | Data |
---|---|---|
9e066e23 CM |
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 | |
660b0411 | 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
9e066e23 CM |
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> | |
2ef0fdd4 | 34 | #include <spawn.h> |
9e066e23 CM |
35 | |
36 | #include "plot.h" | |
37 | #include "blkparse.h" | |
38 | #include "list.h" | |
33e3face | 39 | #include "tracers.h" |
9e066e23 | 40 | |
2ef0fdd4 AP |
41 | extern char **environ; |
42 | ||
9e066e23 | 43 | static pid_t blktrace_pid = 0; |
e199d546 | 44 | static pid_t mpstat_pid = 0; |
9e066e23 | 45 | |
30420b58 | 46 | static void sig_handler_for_quit(int val) |
9e066e23 | 47 | { |
30420b58 | 48 | fprintf(stderr, "Received signal %d. Terminating tracers.\n", val); |
49559b61 | 49 | wait_for_tracers(SIGTERM); |
9e066e23 CM |
50 | } |
51 | ||
2203e914 | 52 | int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest) |
9e066e23 | 53 | { |
9e066e23 | 54 | int ret; |
2203e914 | 55 | int i; |
30420b58 AP |
56 | char *argv[15 + MAX_DEVICES_PER_TRACE * 2]; |
57 | int argc = 0; | |
9e066e23 | 58 | |
2203e914 CM |
59 | if (!trace_name) |
60 | trace_name = "trace"; | |
30420b58 AP |
61 | if (!dest) |
62 | dest = "."; | |
63 | ||
64 | argv[argc++] = "blktrace"; | |
65 | argv[argc++] = "-b"; | |
66 | argv[argc++] = "8192"; | |
67 | argv[argc++] = "-a"; | |
68 | argv[argc++] = "queue"; | |
69 | argv[argc++] = "-a"; | |
70 | argv[argc++] = "complete"; | |
71 | argv[argc++] = "-a"; | |
72 | argv[argc++] = "issue"; | |
73 | argv[argc++] = "-a"; | |
74 | argv[argc++] = "notify"; | |
2203e914 | 75 | |
2203e914 | 76 | if (num_devices == 1) { |
30420b58 AP |
77 | argv[argc++] = "-o"; |
78 | argv[argc++] = trace_name; | |
2203e914 | 79 | } else { |
30420b58 AP |
80 | /* Multiple devices output to a directory named trace_name */ |
81 | dest = trace_name; | |
2203e914 | 82 | } |
30420b58 AP |
83 | argv[argc++] = "-D"; |
84 | argv[argc++] = dest; | |
2203e914 | 85 | |
30420b58 AP |
86 | for (i = 0; i < num_devices; i++) { |
87 | argv[argc++] = "-d"; | |
88 | argv[argc++] = devices[i]; | |
9e066e23 | 89 | } |
30420b58 AP |
90 | argv[argc] = NULL; |
91 | signal(SIGTERM, sig_handler_for_quit); | |
92 | signal(SIGINT, sig_handler_for_quit); | |
49559b61 | 93 | ret = run_program(argc, argv, 0, &blktrace_pid, NULL); |
30420b58 | 94 | return ret; |
9e066e23 CM |
95 | } |
96 | ||
30420b58 | 97 | int wait_program(pid_t pid, const char *pname, int sig) |
33e3face AP |
98 | { |
99 | int status; | |
100 | int ret = 0; | |
101 | ||
30420b58 AP |
102 | if (sig) { |
103 | ret = kill(pid, sig); | |
104 | if (ret) { | |
105 | fprintf(stderr, "Failed to send signal %d to %s (%lu): %s\n", | |
106 | sig, pname, (long)pid, strerror(errno)); | |
107 | return ret; | |
108 | } | |
109 | fprintf(stderr, "Kill (%d): %s (%ld)\n", sig, pname, (long)pid); | |
110 | } | |
111 | ||
33e3face AP |
112 | waitpid(pid, &status, 0); |
113 | if (WIFEXITED(status)) { | |
114 | ret = WEXITSTATUS(status); | |
115 | if (ret == 127) /* spawnp failed after forking */ | |
116 | fprintf(stderr, "Failed to run '%s'\n", pname); | |
49559b61 AP |
117 | else |
118 | fprintf(stderr, "Exit (%d): %s\n", ret, pname); | |
30420b58 | 119 | } else if (WIFSIGNALED(status) && sig && WTERMSIG(status) != sig) { |
33e3face AP |
120 | fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status)); |
121 | ret = -1; | |
122 | } | |
123 | return ret; | |
124 | } | |
125 | ||
49559b61 | 126 | int run_program(int argc, char **argv, int wait, pid_t *pid, char *outpath) |
c1ab63ed AP |
127 | { |
128 | int i; | |
129 | int err; | |
33e3face | 130 | pid_t _pid; |
49559b61 AP |
131 | posix_spawn_file_actions_t facts; |
132 | posix_spawn_file_actions_t *factp = NULL; | |
c1ab63ed | 133 | |
49559b61 AP |
134 | if (outpath != NULL) { |
135 | posix_spawn_file_actions_init(&facts); | |
136 | posix_spawn_file_actions_addopen(&facts, 1, outpath, O_WRONLY|O_CREAT|O_TRUNC, 0600); | |
137 | factp = &facts; | |
138 | } | |
139 | ||
140 | fprintf(stderr, "Start"); | |
c1ab63ed | 141 | for (i = 0; i < argc; i++) |
49559b61 | 142 | fprintf(stderr, " %s", argv[i]); |
c1ab63ed AP |
143 | fprintf(stderr, "\n"); |
144 | ||
49559b61 | 145 | err = posix_spawnp(&_pid, argv[0], factp, NULL, argv, environ); |
c1ab63ed | 146 | if (err != 0) { |
6061d941 | 147 | fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err)); |
ce225d50 | 148 | } else if (wait) { |
30420b58 | 149 | err = wait_program(_pid, argv[0], 0); |
33e3face AP |
150 | } else if (!pid) { |
151 | fprintf(stderr, "Warning: %s (%ld): Not saving pid and not waiting for it.\n", | |
152 | argv[0], (long)_pid); | |
153 | } else { | |
154 | *pid = _pid; | |
6061d941 AP |
155 | } |
156 | return err; | |
c1ab63ed AP |
157 | } |
158 | ||
49559b61 | 159 | int wait_for_tracers(int sig) |
9e066e23 | 160 | { |
49559b61 | 161 | int err; |
e199d546 | 162 | if (blktrace_pid != 0) { |
49559b61 | 163 | err = wait_program(blktrace_pid, "blktrace", sig); |
30420b58 AP |
164 | if (err) |
165 | exit(1); | |
e199d546 CM |
166 | blktrace_pid = 0; |
167 | } | |
168 | if (mpstat_pid != 0) { | |
49559b61 AP |
169 | err = wait_program(mpstat_pid, "mpstat", sig); |
170 | if (err) | |
171 | exit(1); | |
e199d546 CM |
172 | mpstat_pid = 0; |
173 | } | |
9e066e23 CM |
174 | return 0; |
175 | } | |
176 | ||
49559b61 | 177 | int start_mpstat(char *path) |
e199d546 | 178 | { |
49559b61 AP |
179 | int ret; |
180 | int argc = 4; | |
181 | char *argv[] = { | |
182 | "mpstat", | |
183 | "-P", "ALL", "1", | |
184 | NULL, | |
185 | }; | |
186 | ||
187 | ret = run_program(argc, argv, 0, &mpstat_pid, path); | |
188 | return ret; | |
e199d546 | 189 | } |