Changelog
[blktrace.git] / blktrace.c
CommitLineData
d0ca268b
JA
1/*
2 * block queue tracing application
3 *
4 * TODO (in no particular order):
5 * - Add ability to specify capture mask instead of logging all events
6 * - Add option for relayfs mount point
7 *
8 */
9#include <pthread.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
13#include <locale.h>
14#include <signal.h>
15#include <fcntl.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <sched.h>
21
22#include "blktrace.h"
23
24#define BUF_SIZE (128 *1024)
25#define BUF_NR (4)
26
27struct thread_information {
28 int cpu;
29 pthread_t thread;
30 unsigned long events_processed;
31};
32
33static char relay_path[] = "/relay/";
34
35#define is_done() (*(volatile int *)(&done))
36static volatile int done;
37
38static int devfd, ncpus;
39static struct thread_information *thread_information;
40static char *buts_name_p;
41
3aabcd89 42static int start_trace(char *dev)
d0ca268b
JA
43{
44 struct blk_user_trace_setup buts;
45
46 devfd = open(dev, O_RDONLY);
47 if (devfd < 0) {
48 perror(dev);
49 return 1;
50 }
51
52 memset(&buts, sizeof(buts), 0);
53 buts.buf_size = BUF_SIZE;
54 buts.buf_nr = BUF_NR;
55
56 printf("Starting trace on %s\n", dev);
57 if (ioctl(devfd, BLKSTARTTRACE, &buts) < 0) {
58 perror("BLKSTARTTRACE");
59 return 1;
60 }
61
62 buts_name_p = strdup(buts.name);
63 return 0;
64}
65
3aabcd89 66static void stop_trace(void)
d0ca268b
JA
67{
68 if (ioctl(devfd, BLKSTOPTRACE) < 0)
69 perror("BLKSTOPTRACE");
70
71 close(devfd);
72}
73
3aabcd89 74static inline int verify_trace(struct blk_io_trace *t)
d0ca268b
JA
75{
76 if (!CHECK_MAGIC(t)) {
77 fprintf(stderr, "bad trace magic %x\n", t->magic);
78 return 1;
79 }
80 if ((t->magic & 0xff) != SUPPORTED_VERSION) {
81 fprintf(stderr, "unsupported trace version %x\n",
82 t->magic & 0xff);
83 return 1;
84 }
85
86 return 0;
87}
88
3aabcd89
JA
89static void extract_data(int cpu, char *ifn, int ifd, char *ofn, int ofd,
90 int nb)
d0ca268b
JA
91{
92 int ret, bytes_left;
93 unsigned char buf[nb], *p;
94
95 p = buf;
96 bytes_left = nb;
97 while (bytes_left > 0) {
98 ret = read(ifd, p, bytes_left);
3aabcd89
JA
99 if (!ret)
100 usleep(1000);
101 else if (ret < 0) {
d0ca268b
JA
102 perror(ifn);
103 fprintf(stderr, "Thread %d extract_data %s failed\n",
104 cpu, ifn);
105 exit(1);
3aabcd89 106 } else {
d0ca268b
JA
107 p += ret;
108 bytes_left -= ret;
109 }
110 }
111
112 ret = write(ofd, buf, nb);
113 if (ret != nb) {
114 perror(ofn);
115 fprintf(stderr,"Thread %d extract_data %s failed\n", cpu, ofn);
116 exit(1);
117 }
118}
119
3aabcd89 120static void *extract(void *arg)
d0ca268b
JA
121{
122 struct thread_information *tip = arg;
123 int tracefd, ret, ofd, dfd;
124 char ip[64], op[64], dp[64];
125 struct blk_io_trace t;
126 pid_t pid = getpid();
127 cpu_set_t cpu_mask;
128
129 CPU_ZERO(&cpu_mask);
130 CPU_SET(tip->cpu, &cpu_mask);
131
132 if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
133 perror("sched_setaffinity");
134 exit(1);
135 }
136
137 sprintf(op, "%s_out.%d", buts_name_p, tip->cpu);
138 ofd = open(op, O_CREAT|O_TRUNC|O_WRONLY, 0644);
139 if (ofd < 0) {
140 perror(op);
141 fprintf(stderr,"Thread %d failed creat of %s\n", tip->cpu, op);
142 exit(1);
143 }
144
145 sprintf(dp, "%s_dat.%d", buts_name_p, tip->cpu);
146 dfd = open(dp, O_CREAT|O_TRUNC|O_WRONLY, 0644);
147 if (dfd < 0) {
148 perror(dp);
149 fprintf(stderr,"Thread %d failed creat of %s\n", tip->cpu, dp);
150 exit(1);
151 }
152
153 sprintf(ip, "%s%s%d", relay_path, buts_name_p, tip->cpu);
154 tracefd = open(ip, O_RDONLY);
155 if (tracefd < 0) {
156 perror(ip);
157 fprintf(stderr,"Thread %d failed open of %s\n", tip->cpu, ip);
158 exit(1);
159 }
160
161 while (!is_done()) {
162 ret = read(tracefd, &t, sizeof(t));
163 if (ret != sizeof(t)) {
164 if (ret < 0) {
165 perror(ip);
166 fprintf(stderr,"Thread %d failed read of %s\n",
167 tip->cpu, ip);
168 exit(1);
169 } else if (ret > 0) {
8fc0abbc
JA
170 fprintf(stderr,"Thread %d misread %s %d,%d\n",
171 tip->cpu, ip, ret, (int)sizeof(t));
d0ca268b
JA
172 exit(1);
173 } else {
174 usleep(10000);
175 continue;
176 }
177 }
178
179 if (verify_trace(&t))
180 exit(1);
181
182 switch (t.action & 0xffff) {
183 case __BLK_TA_ISSUE:
184 case __BLK_TA_COMPLETE:
185 if (!t.pdu_len)
186 break;
187 else if (t.pdu_len > 64) {
188 fprintf(stderr,
189 "Thread %d Payload too large %d\n",
190 tip->cpu, t.pdu_len);
191 exit(1);
192 }
193 extract_data(tip->cpu, ip, tracefd, dp, dfd, t.pdu_len);
194 break;
195 }
196
197 /* version is verified, stuff with CPU number now */
fd92da24 198 t.magic = tip->cpu;
d0ca268b
JA
199 ret = write(ofd, &t, sizeof(t));
200 if (ret < 0) {
201 perror(op);
202 fprintf(stderr,"Thread %d failed write of %s\n",
203 tip->cpu, op);
204 exit(1);
205 }
206
207 tip->events_processed++;
208 }
209
210 return NULL;
211}
212
3aabcd89 213static int start_threads(void)
d0ca268b
JA
214{
215 struct thread_information *tip;
216 int i;
217
218 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
219 if (ncpus < 0) {
220 fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
221 return 1;
222 }
223 printf("Processors online: %d\n", ncpus);
224
225 thread_information = malloc(ncpus * sizeof(struct thread_information));
226 for (i = 0, tip = thread_information; i < ncpus; i++, tip++) {
227 tip->cpu = i;
228 tip->events_processed = 0;
229
230 if (pthread_create(&tip->thread, NULL, extract, tip)) {
231 perror( "pthread_create");
232 return 0;
233 }
234 }
235
236 return ncpus;
237}
238
3aabcd89
JA
239static void stop_threads(void)
240{
241 struct thread_information *tip = thread_information;
242 int i;
243
244 for (i = 0; i < ncpus; i++, tip++) {
245 int ret;
246
247 if (pthread_join(tip->thread, (void *) &ret))
248 perror("thread_join");
249 }
250}
251
d0ca268b
JA
252void show_stats(void)
253{
254 int i;
255 struct thread_information *tip;
256 unsigned long events_processed = 0;
257
258 for (i = 0, tip = thread_information; i < ncpus; i++, tip++) {
259 printf("CPU%3d: %20ld events\n",
260 tip->cpu, tip->events_processed);
261 events_processed += tip->events_processed;
262 }
263
264 printf("Total: %20ld events\n", events_processed);
265}
266
267void handle_sigint(int sig)
268{
269 printf("exiting on signal %d\n", sig);
270 done = 1;
271}
272
273int main(int argc, char *argv[])
274{
d0ca268b
JA
275 struct stat st;
276 int i;
277
278 if (argc < 2) {
279 fprintf(stderr, "Usage: %s <dev>\n", argv[0]);
280 return 1;
281 }
282
283 if (stat(relay_path, &st) < 0) {
284 fprintf(stderr,"%s does not appear to be mounted\n",
285 relay_path);
286 return 2;
287 }
288
289 if (start_trace(argv[1])) {
290 fprintf(stderr, "Failed to start trace\n");
291 stop_trace();
292 return 3;
293 }
294
295 setlocale(LC_NUMERIC, "en_US");
296
297 i = start_threads();
298 if (!i) {
299 fprintf(stderr, "Failed to start worker threads\n");
300 stop_trace();
301 return 4;
302 }
303
304 printf("Threads started : %d\n", i);
305
306 signal(SIGINT, handle_sigint);
307 signal(SIGHUP, handle_sigint);
308 signal(SIGTERM, handle_sigint);
309
310 while (!is_done())
311 sleep(1);
312
3aabcd89 313 stop_threads();
d0ca268b
JA
314 stop_trace();
315 close(devfd);
316 show_stats();
317
318 return 0;
319}
320