[PATCH] blktrace.tex: add description of each possible action
[blktrace.git] / blktrace.c
CommitLineData
d0ca268b
JA
1/*
2 * block queue tracing application
3 *
d956a2cd
JA
4 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
d0ca268b
JA
20 */
21#include <pthread.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <locale.h>
26#include <signal.h>
27#include <fcntl.h>
28#include <string.h>
29#include <sys/ioctl.h>
b9d4294e 30#include <sys/param.h>
e3e74029 31#include <sys/statfs.h>
d0ca268b
JA
32#include <stdio.h>
33#include <stdlib.h>
34#include <sched.h>
d39c04ca
AB
35#include <ctype.h>
36#include <getopt.h>
d0ca268b
JA
37
38#include "blktrace.h"
39
52724a0e
JA
40static char blktrace_version[] = "0.90";
41
d0ca268b
JA
42#define BUF_SIZE (128 *1024)
43#define BUF_NR (4)
44
e3e74029
NS
45#define RELAYFS_TYPE 0xF0B4A981
46
d1d7f15f 47#define S_OPTS "d:a:A:r:o:kw:vb:n:D:"
d5396421 48static struct option l_opts[] = {
5c86134e 49 {
d39c04ca 50 .name = "dev",
428683db 51 .has_arg = required_argument,
d39c04ca
AB
52 .flag = NULL,
53 .val = 'd'
54 },
5c86134e 55 {
d39c04ca 56 .name = "act-mask",
428683db 57 .has_arg = required_argument,
d39c04ca
AB
58 .flag = NULL,
59 .val = 'a'
60 },
5c86134e 61 {
d39c04ca 62 .name = "set-mask",
428683db 63 .has_arg = required_argument,
d39c04ca
AB
64 .flag = NULL,
65 .val = 'A'
66 },
5c86134e 67 {
5270dddd 68 .name = "relay",
428683db 69 .has_arg = required_argument,
5270dddd
JA
70 .flag = NULL,
71 .val = 'r'
72 },
d5396421
JA
73 {
74 .name = "output",
428683db 75 .has_arg = required_argument,
d5396421
JA
76 .flag = NULL,
77 .val = 'o'
78 },
bc39777c
JA
79 {
80 .name = "kill",
428683db 81 .has_arg = no_argument,
bc39777c
JA
82 .flag = NULL,
83 .val = 'k'
84 },
ece238a6
NS
85 {
86 .name = "stopwatch",
428683db 87 .has_arg = required_argument,
ece238a6
NS
88 .flag = NULL,
89 .val = 'w'
90 },
52724a0e
JA
91 {
92 .name = "version",
93 .has_arg = no_argument,
94 .flag = NULL,
95 .val = 'v'
96 },
129aa440 97 {
3f65c585 98 .name = "buffer-size",
129aa440
JA
99 .has_arg = required_argument,
100 .flag = NULL,
101 .val = 'b'
102 },
103 {
3f65c585 104 .name = "num-sub-buffers",
129aa440
JA
105 .has_arg = required_argument,
106 .flag = NULL,
107 .val = 'n'
108 },
d1d7f15f 109 {
3f65c585 110 .name = "output-dir",
d1d7f15f
JA
111 .has_arg = required_argument,
112 .flag = NULL,
113 .val = 'D'
114 },
71ef8b7c
JA
115 {
116 .name = NULL,
117 }
d39c04ca
AB
118};
119
d0ca268b
JA
120struct thread_information {
121 int cpu;
122 pthread_t thread;
b9d4294e
JA
123
124 int fd;
125 char fn[MAXPATHLEN + 64];
8a43bac5
JA
126 void *buf;
127 unsigned long buf_offset;
128 unsigned int buf_subbuf;
129 unsigned int sequence;
b9d4294e 130
d5396421
JA
131 pthread_mutex_t *fd_lock;
132 int ofd;
133
d0ca268b 134 unsigned long events_processed;
e7c9f3ff 135 struct device_information *device;
d0ca268b
JA
136};
137
e7c9f3ff
NS
138struct device_information {
139 int fd;
140 char *path;
141 char buts_name[32];
142 int trace_started;
143 struct thread_information *threads;
144};
d0ca268b 145
e7c9f3ff 146static int ncpus;
d0ca268b 147static struct thread_information *thread_information;
e7c9f3ff
NS
148static int ndevs;
149static struct device_information *device_information;
150
151/* command line option globals */
152static char *relay_path;
d5396421 153static char *output_name;
d1d7f15f 154static char *output_dir;
5c86134e 155static int act_mask = ~0U;
bc39777c 156static int kill_running_trace;
e820abd7
JA
157static unsigned int buf_size = BUF_SIZE;
158static unsigned int buf_nr = BUF_NR;
d39c04ca 159
e7c9f3ff
NS
160#define is_done() (*(volatile int *)(&done))
161static volatile int done;
162
d5396421
JA
163static pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
164
72ca8801
NS
165static void exit_trace(int status);
166
e7c9f3ff 167static int start_trace(struct device_information *dip)
d0ca268b
JA
168{
169 struct blk_user_trace_setup buts;
170
1f79c4a0 171 memset(&buts, 0, sizeof(buts));
129aa440
JA
172 buts.buf_size = buf_size;
173 buts.buf_nr = buf_nr;
d39c04ca 174 buts.act_mask = act_mask;
d0ca268b 175
e7c9f3ff 176 if (ioctl(dip->fd, BLKSTARTTRACE, &buts) < 0) {
d0ca268b
JA
177 perror("BLKSTARTTRACE");
178 return 1;
179 }
180
e7c9f3ff
NS
181 memcpy(dip->buts_name, buts.name, sizeof(dip->buts_name));
182 dip->trace_started = 1;
d0ca268b
JA
183 return 0;
184}
185
e7c9f3ff 186static void stop_trace(struct device_information *dip)
d0ca268b 187{
e7c9f3ff
NS
188 if (dip->trace_started || kill_running_trace) {
189 if (ioctl(dip->fd, BLKSTOPTRACE) < 0)
707b0914 190 perror("BLKSTOPTRACE");
e7c9f3ff
NS
191 close(dip->fd);
192 dip->trace_started = 0;
707b0914 193 }
d0ca268b
JA
194}
195
e7c9f3ff
NS
196static void stop_all_traces(void)
197{
198 struct device_information *dip;
199 int i;
200
201 for (dip = device_information, i = 0; i < ndevs; i++, dip++)
202 stop_trace(dip);
203}
204
db6fe5bc 205static int read_data(struct thread_information *tip, void *buf, int len)
d0ca268b 206{
8a43bac5
JA
207 char *p = buf;
208 int ret, bytes_left = len;
d0ca268b 209
8a43bac5 210 while (!is_done() && bytes_left > 0) {
b9d4294e 211 ret = read(tip->fd, p, bytes_left);
db6fe5bc 212 if (ret == bytes_left)
3752a433 213 return 0;
8a43bac5
JA
214
215 if (ret < 0) {
b9d4294e 216 perror(tip->fn);
8a43bac5 217 fprintf(stderr,"Thread %d failed read of %s\n",
b9d4294e 218 tip->cpu, tip->fn);
db6fe5bc 219 break;
8a43bac5 220 } else if (ret > 0) {
d0ca268b
JA
221 p += ret;
222 bytes_left -= ret;
db6fe5bc
JA
223 } else
224 usleep(1000);
8a43bac5
JA
225 }
226
3752a433 227 return -1;
8a43bac5
JA
228}
229
db6fe5bc 230static int write_data(int fd, void *buf, unsigned int buf_len)
8a43bac5 231{
db6fe5bc
JA
232 int ret, bytes_left;
233 char *p = buf;
8a43bac5 234
db6fe5bc
JA
235 bytes_left = buf_len;
236 while (bytes_left > 0) {
237 ret = write(fd, p, bytes_left);
238 if (ret == bytes_left)
8a43bac5
JA
239 break;
240
db6fe5bc
JA
241 if (ret < 0) {
242 perror("write");
243 return 1;
244 } else if (ret > 0) {
245 p += ret;
246 bytes_left -= ret;
247 } else {
248 fprintf(stderr, "Zero write?\n");
249 return 1;
8a43bac5 250 }
d0ca268b
JA
251 }
252
8a43bac5
JA
253 return 0;
254}
255
e820abd7 256static void *extract_data(struct thread_information *tip, int nb)
8a43bac5
JA
257{
258 unsigned char *buf;
259
260 buf = malloc(nb);
db6fe5bc 261 if (!read_data(tip, buf, nb))
8a43bac5
JA
262 return buf;
263
264 free(buf);
8a43bac5 265 return NULL;
d0ca268b
JA
266}
267
3a9d6c13
JA
268/*
269 * trace may start inside 'bit' or may need to be gotten further on
270 */
271static int get_event_slow(struct thread_information *tip,
272 struct blk_io_trace *bit)
4b5db44a 273{
3a9d6c13
JA
274 const int inc = sizeof(__u32);
275 struct blk_io_trace foo;
fb39f32f 276 unsigned int offset;
3a9d6c13
JA
277 void *p;
278
279 /*
280 * check is trace is inside
281 */
282 offset = 0;
283 p = bit;
284 while (offset < sizeof(*bit)) {
285 p += inc;
286 offset += inc;
287
288 memcpy(&foo, p, inc);
289
290 if (CHECK_MAGIC(&foo))
291 break;
292 }
4b5db44a 293
3a9d6c13
JA
294 /*
295 * part trace found inside, read the rest
296 */
297 if (offset < sizeof(*bit)) {
298 int good_bytes = sizeof(*bit) - offset;
299
300 memmove(bit, p, good_bytes);
301 p = (void *) bit + good_bytes;
302
303 return read_data(tip, p, offset);
304 }
305
306 /*
307 * nothing found, keep looking for start of trace
308 */
4b5db44a
JA
309 do {
310 if (read_data(tip, bit, sizeof(bit->magic)))
311 return -1;
4b5db44a
JA
312 } while (!CHECK_MAGIC(bit));
313
3a9d6c13
JA
314 /*
315 * now get the rest of it
316 */
317 p = &bit->sequence;
318 if (!read_data(tip, p, sizeof(*bit) - inc))
319 return -1;
320
321 return 0;
322}
323
324/*
325 * Sometimes relayfs screws us a little, if an event crosses a sub buffer
326 * boundary. So keep looking forward in the trace data until an event
327 * is found
328 */
329static int get_event(struct thread_information *tip, struct blk_io_trace *bit)
330{
331 /*
332 * optimize for the common fast case, a full trace read that
333 * succeeds
334 */
335 if (read_data(tip, bit, sizeof(*bit)))
336 return -1;
337
338 if (CHECK_MAGIC(bit))
4b5db44a
JA
339 return 0;
340
3a9d6c13
JA
341 /*
342 * ok that didn't work, the event may start somewhere inside the
343 * trace itself
344 */
345 return get_event_slow(tip, bit);
4b5db44a
JA
346}
347
d5396421
JA
348static inline void tip_fd_unlock(struct thread_information *tip)
349{
350 if (tip->fd_lock)
351 pthread_mutex_unlock(tip->fd_lock);
352}
353
354static inline void tip_fd_lock(struct thread_information *tip)
355{
356 if (tip->fd_lock)
357 pthread_mutex_lock(tip->fd_lock);
358}
359
3aabcd89 360static void *extract(void *arg)
d0ca268b
JA
361{
362 struct thread_information *tip = arg;
db6fe5bc 363 int pdu_len;
e820abd7 364 char *pdu_data;
d0ca268b
JA
365 struct blk_io_trace t;
366 pid_t pid = getpid();
367 cpu_set_t cpu_mask;
368
369 CPU_ZERO(&cpu_mask);
b9d4294e 370 CPU_SET((tip->cpu), &cpu_mask);
d0ca268b
JA
371
372 if (sched_setaffinity(pid, sizeof(cpu_mask), &cpu_mask) == -1) {
373 perror("sched_setaffinity");
76718bcd 374 exit_trace(1);
d0ca268b
JA
375 }
376
e7c9f3ff
NS
377 snprintf(tip->fn, sizeof(tip->fn), "%s/block/%s/trace%d",
378 relay_path, tip->device->buts_name, tip->cpu);
b9d4294e
JA
379 tip->fd = open(tip->fn, O_RDONLY);
380 if (tip->fd < 0) {
381 perror(tip->fn);
5c86134e
JA
382 fprintf(stderr,"Thread %d failed open of %s\n", tip->cpu,
383 tip->fn);
76718bcd 384 exit_trace(1);
d0ca268b
JA
385 }
386
69e65a9e 387 pdu_data = NULL;
d0ca268b 388 while (!is_done()) {
4b5db44a 389 if (get_event(tip, &t))
8a43bac5 390 break;
d0ca268b
JA
391
392 if (verify_trace(&t))
db6fe5bc 393 break;
d0ca268b 394
18ada3d4
JA
395 pdu_len = t.pdu_len;
396
6fe4709e
JA
397 trace_to_be(&t);
398
db6fe5bc 399 if (pdu_len) {
e820abd7 400 pdu_data = extract_data(tip, pdu_len);
db6fe5bc
JA
401 if (!pdu_data)
402 break;
403 }
69e65a9e
JA
404
405 /*
406 * now we have both trace and payload, get a lock on the
407 * output descriptor and send it off
408 */
d5396421
JA
409 tip_fd_lock(tip);
410
db6fe5bc 411 if (write_data(tip->ofd, &t, sizeof(t))) {
d5396421 412 tip_fd_unlock(tip);
db6fe5bc 413 break;
d0ca268b
JA
414 }
415
db6fe5bc
JA
416 if (pdu_data && write_data(tip->ofd, pdu_data, pdu_len)) {
417 tip_fd_unlock(tip);
418 break;
419 }
420
421 tip_fd_unlock(tip);
d5396421 422
db6fe5bc 423 if (pdu_data) {
69e65a9e
JA
424 free(pdu_data);
425 pdu_data = NULL;
426 }
87b72777 427
d0ca268b
JA
428 tip->events_processed++;
429 }
430
db6fe5bc 431 exit_trace(1);
d0ca268b
JA
432 return NULL;
433}
434
e7c9f3ff 435static int start_threads(struct device_information *dip)
d0ca268b
JA
436{
437 struct thread_information *tip;
d5396421 438 char op[64];
e7c9f3ff 439 int j, pipeline = output_name && !strcmp(output_name, "-");
d1d7f15f 440 int len;
d0ca268b 441
e7c9f3ff
NS
442 for (tip = dip->threads, j = 0; j < ncpus; j++, tip++) {
443 tip->cpu = j;
444 tip->device = dip;
d5396421 445 tip->fd_lock = NULL;
d0ca268b
JA
446 tip->events_processed = 0;
447
e7c9f3ff 448 if (pipeline) {
1f79c4a0 449 tip->ofd = dup(STDOUT_FILENO);
d5396421
JA
450 tip->fd_lock = &stdout_mutex;
451 } else {
d1d7f15f
JA
452 len = 0;
453
454 if (output_dir)
455 len = sprintf(op, "%s/", output_dir);
456
9f6486bd 457 if (output_name) {
d1d7f15f 458 sprintf(op + len, "%s.blktrace.%d", output_name,
9f6486bd
JA
459 tip->cpu);
460 } else {
d1d7f15f 461 sprintf(op + len, "%s.blktrace.%d",
e7c9f3ff 462 dip->buts_name, tip->cpu);
9f6486bd 463 }
d5396421
JA
464 tip->ofd = open(op, O_CREAT|O_TRUNC|O_WRONLY, 0644);
465 }
466
467 if (tip->ofd < 0) {
468 perror(op);
e7c9f3ff 469 return 1;
d5396421
JA
470 }
471
d0ca268b 472 if (pthread_create(&tip->thread, NULL, extract, tip)) {
e7c9f3ff
NS
473 perror("pthread_create");
474 close(tip->ofd);
475 return 1;
d0ca268b
JA
476 }
477 }
478
e7c9f3ff 479 return 0;
d0ca268b
JA
480}
481
72ca8801
NS
482static void close_thread(struct thread_information *tip)
483{
484 if (tip->fd != -1)
485 close(tip->fd);
486 if (tip->ofd != -1)
487 close(tip->ofd);
8a43bac5 488
72ca8801
NS
489 tip->fd = tip->ofd = -1;
490}
491
e7c9f3ff 492static void stop_threads(struct device_information *dip)
3aabcd89 493{
e7c9f3ff
NS
494 struct thread_information *tip;
495 long ret;
496 int j;
3aabcd89 497
e7c9f3ff 498 for (tip = dip->threads, j = 0; j < ncpus; j++, tip++) {
3aabcd89
JA
499 if (pthread_join(tip->thread, (void *) &ret))
500 perror("thread_join");
72ca8801 501 close_thread(tip);
3aabcd89
JA
502 }
503}
504
e7c9f3ff 505static void stop_all_threads(void)
72ca8801 506{
e7c9f3ff 507 struct device_information *dip;
72ca8801
NS
508 int i;
509
e7c9f3ff
NS
510 for (dip = device_information, i = 0; i < ndevs; i++, dip++)
511 stop_threads(dip);
512}
513
514static void stop_all_tracing(void)
515{
516 struct device_information *dip;
517 struct thread_information *tip;
518 int i, j;
519
520 for (dip = device_information, i = 0; i < ndevs; i++, dip++) {
521 for (tip = dip->threads, j = 0; j < ncpus; j++, tip++)
522 close_thread(tip);
523 stop_trace(dip);
524 }
72ca8801
NS
525}
526
527static void exit_trace(int status)
528{
e7c9f3ff 529 stop_all_tracing();
72ca8801
NS
530 exit(status);
531}
532
e7c9f3ff
NS
533static int resize_devices(char *path)
534{
535 int size = (ndevs + 1) * sizeof(struct device_information);
536
537 device_information = realloc(device_information, size);
538 if (!device_information) {
539 fprintf(stderr, "Out of memory, device %s (%d)\n", path, size);
540 return 1;
541 }
542 device_information[ndevs].path = path;
543 ndevs++;
544 return 0;
545}
546
547static int open_devices(void)
d0ca268b 548{
e7c9f3ff 549 struct device_information *dip;
d0ca268b 550 int i;
d0ca268b 551
e7c9f3ff
NS
552 for (dip = device_information, i = 0; i < ndevs; i++, dip++) {
553 dip->fd = open(dip->path, O_RDONLY);
554 if (dip->fd < 0) {
555 perror(dip->path);
556 return 1;
557 }
558 }
559 return 0;
560}
561
562static int start_devices(void)
563{
564 struct device_information *dip;
565 int i, j, size;
566
567 size = ncpus * sizeof(struct thread_information);
568 thread_information = malloc(size * ndevs);
569 if (!thread_information) {
570 fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
571 return 1;
572 }
d5396421 573
e7c9f3ff
NS
574 for (dip = device_information, i = 0; i < ndevs; i++, dip++) {
575 if (start_trace(dip)) {
576 close(dip->fd);
577 fprintf(stderr, "Failed to start trace on %s\n",
578 dip->path);
579 break;
580 }
581 }
582 if (i != ndevs) {
583 for (dip = device_information, j = 0; j < i; j++, dip++)
584 stop_trace(dip);
585 return 1;
586 }
587
588 for (dip = device_information, i = 0; i < ndevs; i++, dip++) {
589 dip->threads = thread_information + (i * ncpus);
590 if (start_threads(dip)) {
591 fprintf(stderr, "Failed to start worker threads\n");
592 break;
593 }
594 }
595 if (i != ndevs) {
596 for (dip = device_information, j = 0; j < i; j++, dip++)
597 stop_threads(dip);
598 for (dip = device_information, i = 0; i < ndevs; i++, dip++)
599 stop_trace(dip);
600 return 1;
d0ca268b
JA
601 }
602
e7c9f3ff 603 return 0;
d0ca268b
JA
604}
605
e7c9f3ff
NS
606static void show_stats(void)
607{
608 int i, j;
609 struct device_information *dip;
610 struct thread_information *tip;
611 unsigned long long events_processed;
428683db 612
e7c9f3ff
NS
613 if (output_name && !strcmp(output_name, "-"))
614 return;
615
616 for (dip = device_information, i = 0; i < ndevs; i++, dip++) {
617 printf("Device: %s\n", dip->path);
618 events_processed = 0;
619 for (tip = dip->threads, j = 0; j < ncpus; j++, tip++) {
620 printf(" CPU%3d: %20ld events\n",
621 tip->cpu, tip->events_processed);
622 events_processed += tip->events_processed;
623 }
624 printf(" Total: %20lld events\n", events_processed);
625 }
626}
52724a0e
JA
627
628static char usage_str[] = \
629 "-d <dev> [ -r relay path ] [ -o <output> ] [-k ] [ -w time ]\n" \
630 "[ -a action ] [ -A action mask ] [ -v ]\n\n" \
631 "\t-d Use specified device. May also be given last after options\n" \
632 "\t-r Path to mounted relayfs, defaults to /relay\n" \
633 "\t-o File(s) to send output to\n" \
d1d7f15f 634 "\t-D Directory to prepend to output file names\n" \
52724a0e
JA
635 "\t-k Kill a running trace\n" \
636 "\t-w Stop after defined time, in seconds\n" \
637 "\t-a Only trace specified actions. See documentation\n" \
638 "\t-A Give trace mask as a single value. See documentation\n" \
129aa440
JA
639 "\t-b Sub buffer size in KiB\n" \
640 "\t-n Number of sub buffers\n" \
52724a0e
JA
641 "\t-v Print program version info\n\n";
642
ee1f4158
NS
643static void show_usage(char *program)
644{
52724a0e 645 fprintf(stderr, "Usage: %s %s %s",program, blktrace_version, usage_str);
ee1f4158
NS
646}
647
e820abd7 648static void handle_sigint(__attribute__((__unused__)) int sig)
d0ca268b 649{
d0ca268b
JA
650 done = 1;
651}
652
653int main(int argc, char *argv[])
654{
5270dddd 655 static char default_relay_path[] = "/relay";
e3e74029 656 struct statfs st;
d39c04ca 657 int i, c;
ece238a6 658 int stop_watch = 0;
d39c04ca
AB
659 int act_mask_tmp = 0;
660
661 while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
662 switch (c) {
663 case 'a':
664 i = find_mask_map(optarg);
665 if (i < 0) {
ab197ca7 666 fprintf(stderr,"Invalid action mask %s\n",
d39c04ca 667 optarg);
7425d456 668 return 1;
d39c04ca
AB
669 }
670 act_mask_tmp |= i;
671 break;
672
673 case 'A':
98f8386b
AB
674 if ((sscanf(optarg, "%x", &i) != 1) ||
675 !valid_act_opt(i)) {
d39c04ca 676 fprintf(stderr,
ab197ca7 677 "Invalid set action mask %s/0x%x\n",
d39c04ca 678 optarg, i);
7425d456 679 return 1;
d39c04ca
AB
680 }
681 act_mask_tmp = i;
682 break;
d0ca268b 683
d39c04ca 684 case 'd':
e7c9f3ff
NS
685 if (resize_devices(optarg) != 0)
686 return 1;
d39c04ca
AB
687 break;
688
5270dddd
JA
689 case 'r':
690 relay_path = optarg;
691 break;
692
d5396421 693 case 'o':
66efebf8 694 output_name = optarg;
d5396421 695 break;
bc39777c
JA
696 case 'k':
697 kill_running_trace = 1;
698 break;
ece238a6
NS
699 case 'w':
700 stop_watch = atoi(optarg);
701 if (stop_watch <= 0) {
702 fprintf(stderr,
703 "Invalid stopwatch value (%d secs)\n",
704 stop_watch);
705 return 1;
706 }
707 break;
52724a0e
JA
708 case 'v':
709 printf("%s version %s\n", argv[0], blktrace_version);
710 return 0;
129aa440
JA
711 case 'b':
712 buf_size = atoi(optarg);
183a0855 713 if (buf_size <= 0 || buf_size > 16*1024) {
129aa440
JA
714 fprintf(stderr,
715 "Invalid buffer size (%d)\n", buf_size);
716 return 1;
717 }
718 buf_size <<= 10;
719 break;
720 case 'n':
721 buf_nr = atoi(optarg);
722 if (buf_nr <= 0) {
723 fprintf(stderr,
724 "Invalid buffer nr (%d)\n", buf_nr);
725 return 1;
726 }
727 break;
d1d7f15f
JA
728 case 'D':
729 output_dir = optarg;
730 break;
d39c04ca 731 default:
ee1f4158 732 show_usage(argv[0]);
7425d456 733 return 1;
d39c04ca
AB
734 }
735 }
736
e7c9f3ff
NS
737 while (optind < argc) {
738 if (resize_devices(argv[optind++]) != 0)
739 return 1;
740 }
ee1f4158 741
e7c9f3ff 742 if (ndevs == 0) {
ee1f4158 743 show_usage(argv[0]);
7425d456 744 return 1;
d39c04ca
AB
745 }
746
5270dddd
JA
747 if (!relay_path)
748 relay_path = default_relay_path;
749
d5396421 750 if (act_mask_tmp != 0)
d39c04ca 751 act_mask = act_mask_tmp;
d0ca268b 752
e3e74029
NS
753 if (statfs(relay_path, &st) < 0) {
754 perror("statfs");
755 fprintf(stderr,"%s does not appear to be a valid path\n",
756 relay_path);
757 return 1;
758 } else if (st.f_type != RELAYFS_TYPE) {
759 fprintf(stderr,"%s does not appear to be a relay filesystem\n",
d0ca268b 760 relay_path);
7425d456 761 return 1;
d0ca268b
JA
762 }
763
e7c9f3ff 764 if (open_devices() != 0)
7425d456 765 return 1;
bc39777c
JA
766
767 if (kill_running_trace) {
e7c9f3ff 768 stop_all_traces();
7425d456 769 return 0;
bc39777c
JA
770 }
771
d0ca268b
JA
772 setlocale(LC_NUMERIC, "en_US");
773
e7c9f3ff
NS
774 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
775 if (ncpus < 0) {
776 fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n");
7425d456 777 return 1;
d0ca268b
JA
778 }
779
e7c9f3ff
NS
780 if (start_devices() != 0)
781 return 1;
782
d0ca268b
JA
783 signal(SIGINT, handle_sigint);
784 signal(SIGHUP, handle_sigint);
785 signal(SIGTERM, handle_sigint);
ece238a6 786 signal(SIGALRM, handle_sigint);
d0ca268b 787
e7c9f3ff 788 atexit(stop_all_tracing);
830fd65c 789
ece238a6
NS
790 if (stop_watch)
791 alarm(stop_watch);
792
d0ca268b
JA
793 while (!is_done())
794 sleep(1);
795
e7c9f3ff
NS
796 stop_all_threads();
797 stop_all_traces();
d0ca268b
JA
798 show_stats();
799
800 return 0;
801}
802