[PATCH] Missing ->cpu endianness conversion
[blktrace.git] / blkparse.c
CommitLineData
d956a2cd
JA
1/*
2 * block queue tracing parse application
3 *
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 *
20 */
d0ca268b
JA
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <stdlib.h>
8fc0abbc 27#include <string.h>
d5396421 28#include <getopt.h>
412819ce
JA
29#include <errno.h>
30#include <signal.h>
d0ca268b 31
8fc0abbc
JA
32#include "blktrace.h"
33#include "rbtree.h"
d0ca268b 34
fd92da24 35#define MAX_CPUS (512)
d0ca268b 36
cfab07eb
AB
37#define SECONDS(x) ((unsigned long long)(x) / 1000000000)
38#define NANO_SECONDS(x) ((unsigned long long)(x) % 1000000000)
39
d5396421
JA
40static int backwards;
41static unsigned long long genesis_time, last_reported_time;
42
43struct per_cpu_info {
d0ca268b
JA
44 int cpu;
45 int nelems;
d0ca268b
JA
46
47 int fd;
87b72777 48 char fname[128];
d0ca268b 49
87b72777
JA
50 FILE *ofp;
51 char ofname[128];
8fc0abbc 52
5c017e4b 53 unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
afd2d7ad 54 unsigned long ireads, iwrites;
5c017e4b 55 unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
afd2d7ad 56 unsigned long long iread_kb, iwrite_kb;
d0ca268b
JA
57};
58
d5396421
JA
59#define S_OPTS "i:o:"
60static struct option l_opts[] = {
61 {
62 .name = "input",
63 .has_arg = 1,
64 .flag = NULL,
65 .val = 'i'
66 },
67 {
68 .name = "output",
69 .has_arg = 1,
70 .flag = NULL,
71 .val = 'o'
72 },
73 {
74 .name = NULL,
75 .has_arg = 0,
76 .flag = NULL,
77 .val = 0
78 }
79};
80
8fc0abbc
JA
81static struct rb_root rb_root;
82
83struct trace {
84 struct blk_io_trace *bit;
85 struct rb_node rb_node;
86};
87
d5396421 88static struct per_cpu_info per_cpu_info[MAX_CPUS];
d0ca268b 89
87b72777
JA
90static unsigned long long events;
91
92static int max_cpus;
d5396421
JA
93
94static char *dev, *output_name;
d0ca268b 95
412819ce
JA
96#define is_done() (*(volatile int *)(&done))
97static volatile int done;
98
cfab07eb
AB
99static inline void check_time(struct blk_io_trace *bit)
100{
101 unsigned long long this = bit->time;
102 unsigned long long last = last_reported_time;
103
104 backwards = (this < last) ? 'B' : ' ';
105 last_reported_time = this;
106}
107
d5396421 108static inline void account_m(struct per_cpu_info *pci, int rw,
5c017e4b 109 unsigned int bytes)
d0ca268b
JA
110{
111 if (rw) {
d5396421
JA
112 pci->mwrites++;
113 pci->qwrite_kb += bytes >> 10;
d0ca268b 114 } else {
d5396421
JA
115 pci->mreads++;
116 pci->qread_kb += bytes >> 10;
d0ca268b
JA
117 }
118}
119
d5396421 120static inline void account_q(struct per_cpu_info *pci, int rw,
5c017e4b 121 unsigned int bytes)
d0ca268b
JA
122{
123 if (rw) {
d5396421
JA
124 pci->qwrites++;
125 pci->qwrite_kb += bytes >> 10;
d0ca268b 126 } else {
d5396421
JA
127 pci->qreads++;
128 pci->qread_kb += bytes >> 10;
d0ca268b
JA
129 }
130}
131
d5396421 132static inline void account_c(struct per_cpu_info *pci, int rw,
5c017e4b 133 unsigned int bytes)
d0ca268b
JA
134{
135 if (rw) {
d5396421
JA
136 pci->cwrites++;
137 pci->cwrite_kb += bytes >> 10;
d0ca268b 138 } else {
d5396421
JA
139 pci->creads++;
140 pci->cread_kb += bytes >> 10;
d0ca268b
JA
141 }
142}
143
d5396421 144static inline void account_i(struct per_cpu_info *pci, int rw,
afd2d7ad 145 unsigned int bytes)
146{
147 if (rw) {
d5396421
JA
148 pci->iwrites++;
149 pci->iwrite_kb += bytes >> 10;
afd2d7ad 150 } else {
d5396421
JA
151 pci->ireads++;
152 pci->iread_kb += bytes >> 10;
afd2d7ad 153 }
154}
155
d5396421 156static void output(struct per_cpu_info *pci, char *s)
d0ca268b
JA
157{
158 printf("%s", s);
d5396421
JA
159
160 if (pci->ofp)
33b56019 161 fprintf(pci->ofp, "%s", s);
d0ca268b
JA
162}
163
3aabcd89
JA
164static char hstring[256];
165static char tstring[256];
d0ca268b 166
d5396421
JA
167static inline char *setup_header(struct per_cpu_info *pci,
168 struct blk_io_trace *t, char act)
d0ca268b
JA
169{
170 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
171 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
172 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
173 char rwbs[4];
174 int i = 0;
175
176 if (w)
177 rwbs[i++] = 'W';
178 else
179 rwbs[i++] = 'R';
180 if (b)
181 rwbs[i++] = 'B';
182 if (s)
183 rwbs[i++] = 'S';
184
185 rwbs[i] = '\0';
186
cfab07eb 187 sprintf(hstring, "%c %3d %15ld %5Lu.%09Lu %5u %c %3s", backwards,
d5396421 188 pci->cpu,
cfab07eb
AB
189 (unsigned long)t->sequence, SECONDS(t->time),
190 NANO_SECONDS(t->time), t->pid, act, rwbs);
d0ca268b
JA
191
192 return hstring;
193}
194
d5396421
JA
195static void log_complete(struct per_cpu_info *pci, struct blk_io_trace *t,
196 char act)
d0ca268b 197{
d5396421 198 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(pci, t, act),
d0ca268b 199 (unsigned long long)t->sector, t->bytes >> 9, t->error);
d5396421 200 output(pci, tstring);
d0ca268b
JA
201}
202
d5396421
JA
203static void log_queue(struct per_cpu_info *pci, struct blk_io_trace *t,
204 char act)
d0ca268b 205{
d5396421 206 sprintf(tstring,"%s %Lu + %u\n", setup_header(pci, t, act),
d0ca268b 207 (unsigned long long)t->sector, t->bytes >> 9);
d5396421 208 output(pci, tstring);
d0ca268b
JA
209}
210
d5396421
JA
211static void log_issue(struct per_cpu_info *pci, struct blk_io_trace *t,
212 char act)
d0ca268b 213{
d5396421 214 sprintf(tstring,"%s %Lu + %u\n", setup_header(pci, t, act),
d0ca268b 215 (unsigned long long)t->sector, t->bytes >> 9);
d5396421 216 output(pci, tstring);
d0ca268b
JA
217}
218
d5396421
JA
219static void log_merge(struct per_cpu_info *pci, struct blk_io_trace *t,
220 char act)
d0ca268b 221{
d5396421 222 sprintf(tstring,"%s %Lu + %u\n", setup_header(pci, t, act),
d0ca268b 223 (unsigned long long)t->sector, t->bytes >> 9);
d5396421 224 output(pci, tstring);
d0ca268b
JA
225}
226
d5396421
JA
227static void log_generic(struct per_cpu_info *pci, struct blk_io_trace *t,
228 char act)
d0ca268b 229{
d5396421 230 sprintf(tstring,"%s %Lu + %u\n", setup_header(pci, t, act),
d0ca268b 231 (unsigned long long)t->sector, t->bytes >> 9);
d5396421 232 output(pci, tstring);
d0ca268b
JA
233}
234
d5396421 235static int log_pc(struct per_cpu_info *pci, struct blk_io_trace *t, char act)
d0ca268b 236{
87b72777
JA
237 unsigned char *buf;
238 int i;
d0ca268b 239
d5396421
JA
240 sprintf(tstring,"%s ", setup_header(pci, t, act));
241 output(pci, tstring);
d0ca268b 242
87b72777 243 buf = (unsigned char *) t + sizeof(*t);
d0ca268b
JA
244 for (i = 0; i < t->pdu_len; i++) {
245 sprintf(tstring,"%02x ", buf[i]);
d5396421 246 output(pci, tstring);
d0ca268b
JA
247 }
248
249 if (act == 'C') {
250 sprintf(tstring,"[%d]", t->error);
d5396421 251 output(pci, tstring);
d0ca268b
JA
252 }
253
254 printf("\n");
87b72777 255 return 0;
d0ca268b
JA
256}
257
d5396421 258static int dump_trace_pc(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b 259{
87b72777
JA
260 int ret = 0;
261
d0ca268b
JA
262 switch (t->action & 0xffff) {
263 case __BLK_TA_QUEUE:
d5396421 264 log_generic(pci, t, 'Q');
d0ca268b
JA
265 break;
266 case __BLK_TA_GETRQ:
d5396421 267 log_generic(pci, t, 'G');
d0ca268b
JA
268 break;
269 case __BLK_TA_SLEEPRQ:
d5396421 270 log_generic(pci, t, 'S');
d0ca268b
JA
271 break;
272 case __BLK_TA_REQUEUE:
d5396421 273 log_generic(pci, t, 'R');
d0ca268b
JA
274 break;
275 case __BLK_TA_ISSUE:
d5396421 276 ret = log_pc(pci, t, 'D');
d0ca268b
JA
277 break;
278 case __BLK_TA_COMPLETE:
d5396421 279 log_pc(pci, t, 'C');
d0ca268b
JA
280 break;
281 default:
282 fprintf(stderr, "Bad pc action %x\n", t->action);
87b72777
JA
283 ret = 1;
284 break;
d0ca268b
JA
285 }
286
87b72777 287 return ret;
d0ca268b
JA
288}
289
d5396421 290static void dump_trace_fs(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b
JA
291{
292 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
293
294 switch (t->action & 0xffff) {
295 case __BLK_TA_QUEUE:
d5396421
JA
296 account_q(pci, w, t->bytes);
297 log_queue(pci, t, 'Q');
d0ca268b
JA
298 break;
299 case __BLK_TA_BACKMERGE:
d5396421
JA
300 account_m(pci, w, t->bytes);
301 log_merge(pci, t, 'M');
d0ca268b
JA
302 break;
303 case __BLK_TA_FRONTMERGE:
d5396421
JA
304 account_m(pci, w, t->bytes);
305 log_merge(pci, t, 'F');
d0ca268b
JA
306 break;
307 case __BLK_TA_GETRQ:
d5396421 308 log_generic(pci, t, 'G');
d0ca268b
JA
309 break;
310 case __BLK_TA_SLEEPRQ:
d5396421 311 log_generic(pci, t, 'S');
d0ca268b
JA
312 break;
313 case __BLK_TA_REQUEUE:
d5396421
JA
314 account_c(pci, w, -t->bytes);
315 log_queue(pci, t, 'R');
d0ca268b
JA
316 break;
317 case __BLK_TA_ISSUE:
d5396421
JA
318 account_i(pci, w, t->bytes);
319 log_issue(pci, t, 'D');
d0ca268b
JA
320 break;
321 case __BLK_TA_COMPLETE:
d5396421
JA
322 account_c(pci, w, t->bytes);
323 log_complete(pci, t, 'C');
d0ca268b
JA
324 break;
325 default:
326 fprintf(stderr, "Bad fs action %x\n", t->action);
1f79c4a0 327 break;
d0ca268b 328 }
d0ca268b
JA
329}
330
d5396421 331static int dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b 332{
87b72777
JA
333 int ret = 0;
334
33b56019
JA
335 if (output_name && !pci->ofp) {
336 snprintf(pci->ofname, sizeof(pci->ofname) - 1,
337 "%s_log.%d", output_name, pci->cpu);
338
339 pci->ofp = fopen(pci->ofname, "w");
340 if (pci->ofp == NULL) {
341 perror(pci->ofname);
342 return 1;
343 }
344 }
345
d0ca268b 346 if (t->action & BLK_TC_ACT(BLK_TC_PC))
d5396421 347 ret = dump_trace_pc(t, pci);
d0ca268b 348 else
d5396421 349 dump_trace_fs(t, pci);
87b72777
JA
350
351 events++;
352 return ret;
d0ca268b
JA
353}
354
d5396421 355static void dump_pci_stats(struct per_cpu_info *pci)
5c017e4b
JA
356{
357 printf("\tReads:\n");
d5396421
JA
358 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pci->qreads, pci->qread_kb);
359 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pci->ireads, pci->iread_kb);
360 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pci->creads, pci->cread_kb);
361 printf("\t\tMerges: %'8lu\n", pci->mreads);
5c017e4b
JA
362
363 printf("\tWrites:\n");
d5396421
JA
364 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pci->qwrites,pci->qwrite_kb);
365 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pci->iwrites,pci->iwrite_kb);
366 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pci->cwrites,pci->cwrite_kb);
367 printf("\t\tMerges: %'8lu\n", pci->mwrites);
5c017e4b
JA
368}
369
d5396421 370static void show_stats(void)
d0ca268b 371{
d5396421 372 struct per_cpu_info foo, *pci;
412819ce 373 int i, pci_events = 0;
5c017e4b
JA
374
375 memset(&foo, 0, sizeof(foo));
d0ca268b 376
412819ce 377 for (i = 0; i < MAX_CPUS; i++) {
d5396421 378 pci = &per_cpu_info[i];
5c017e4b 379
d5396421 380 if (!pci->nelems)
afd2d7ad 381 continue;
382
d5396421
JA
383 foo.qreads += pci->qreads;
384 foo.qwrites += pci->qwrites;
385 foo.creads += pci->creads;
386 foo.cwrites += pci->cwrites;
387 foo.mreads += pci->mreads;
388 foo.mwrites += pci->mwrites;
389 foo.qread_kb += pci->qread_kb;
390 foo.qwrite_kb += pci->qwrite_kb;
391 foo.cread_kb += pci->cread_kb;
392 foo.cwrite_kb += pci->cwrite_kb;
5c017e4b
JA
393
394 printf("CPU%d:\n", i);
d5396421 395 dump_pci_stats(pci);
412819ce 396 pci_events++;
5c017e4b
JA
397 }
398
412819ce 399 if (pci_events > 1) {
5c017e4b 400 printf("Total:\n");
d5396421 401 dump_pci_stats(&foo);
5c017e4b 402 }
d0ca268b
JA
403
404 printf("Events: %'Lu\n", events);
d0ca268b
JA
405}
406
3aabcd89 407static inline int trace_rb_insert(struct trace *t)
8fc0abbc
JA
408{
409 struct rb_node **p = &rb_root.rb_node;
410 struct rb_node *parent = NULL;
411 struct trace *__t;
412
413 while (*p) {
414 parent = *p;
415 __t = rb_entry(parent, struct trace, rb_node);
416
417 if (t->bit->sequence < __t->bit->sequence)
418 p = &(*p)->rb_left;
419 else if (t->bit->sequence > __t->bit->sequence)
420 p = &(*p)->rb_right;
421 else {
87b72777 422 fprintf(stderr, "sequence alias!\n");
8fc0abbc
JA
423 return 1;
424 }
425 }
426
427 rb_link_node(&t->rb_node, parent, p);
428 rb_insert_color(&t->rb_node, &rb_root);
429 return 0;
430}
431
412819ce 432static int sort_entries(void *traces, unsigned long offset, int nr)
8fc0abbc 433{
412819ce 434 struct per_cpu_info *pci;
8fc0abbc
JA
435 struct blk_io_trace *bit;
436 struct trace *t;
437 void *start = traces;
438 int nelems = 0;
439
6fe4709e 440 while (traces - start <= offset - sizeof(*bit)) {
412819ce
JA
441 if (!nr)
442 break;
443
8fc0abbc 444 bit = traces;
6fe4709e 445
8fc0abbc
JA
446 t = malloc(sizeof(*t));
447 t->bit = bit;
448 memset(&t->rb_node, 0, sizeof(t->rb_node));
449
6fe4709e
JA
450 trace_to_cpu(bit);
451
66fa7233
JA
452 if (verify_trace(bit))
453 break;
454
412819ce
JA
455 pci = &per_cpu_info[bit->cpu];
456
412819ce
JA
457 pci->nelems++;
458
8fc0abbc
JA
459 if (trace_rb_insert(t))
460 return -1;
461
462 traces += sizeof(*bit) + bit->pdu_len;
463 nelems++;
412819ce 464 nr--;
6fe4709e 465 }
8fc0abbc
JA
466
467 return nelems;
468}
469
412819ce
JA
470static void free_entries_rb(void)
471{
472 struct rb_node *n;
473
474 while ((n = rb_first(&rb_root)) != NULL) {
475 struct trace *t = rb_entry(n, struct trace, rb_node);
476
477 rb_erase(&t->rb_node, &rb_root);
478 free(t);
479 }
480}
481
d5396421 482static void show_entries_rb(void)
8fc0abbc 483{
8fc0abbc 484 struct blk_io_trace *bit;
3aabcd89 485 struct rb_node *n;
8fc0abbc
JA
486 struct trace *t;
487 int cpu;
488
3aabcd89
JA
489 n = rb_first(&rb_root);
490 if (!n)
491 return;
8fc0abbc 492
3aabcd89 493 do {
8fc0abbc
JA
494 t = rb_entry(n, struct trace, rb_node);
495 bit = t->bit;
496
d5396421 497 cpu = bit->cpu;
87b72777 498 if (cpu > max_cpus) {
8fc0abbc 499 fprintf(stderr, "CPU number too large (%d)\n", cpu);
87b72777 500 break;
8fc0abbc
JA
501 }
502
cfab07eb
AB
503 if (genesis_time == 0)
504 genesis_time = bit->time;
505 bit->time -= genesis_time;
8fc0abbc 506
cfab07eb 507 check_time(bit);
8fc0abbc 508
d5396421 509 if (dump_trace(bit, &per_cpu_info[cpu]))
87b72777
JA
510 break;
511
8fc0abbc
JA
512 } while ((n = rb_next(n)) != NULL);
513}
514
1f79c4a0
JA
515static int read_data(int fd, void *buffer, int bytes, int block)
516{
517 int ret, bytes_left, fl;
518 void *p;
519
520 fl = fcntl(fd, F_GETFL);
521
522 if (!block)
523 fcntl(fd, F_SETFL, fl | O_NONBLOCK);
524 else
525 fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
526
527 bytes_left = bytes;
528 p = buffer;
529 while (bytes_left > 0) {
530 ret = read(fd, p, bytes_left);
531 if (!ret)
532 return 1;
533 else if (ret < 0) {
534 if (errno != EAGAIN)
535 perror("read");
536 return -1;
537 } else {
538 p += ret;
539 bytes_left -= ret;
540 }
541 }
542
543 return 0;
544}
545
d5396421 546static int do_file(void)
d0ca268b 547{
1f79c4a0 548 int i, ret, nfiles;
d0ca268b 549
1f79c4a0
JA
550 nfiles = 0;
551 max_cpus = 0;
552 for (i = 0; i < MAX_CPUS; i++, nfiles++, max_cpus++) {
d5396421 553 struct per_cpu_info *pci = &per_cpu_info[i];
87b72777
JA
554 struct stat st;
555 void *tb;
556
d5396421
JA
557 pci->cpu = i;
558 pci->ofp = NULL;
d0ca268b 559
d5396421
JA
560 snprintf(pci->fname, sizeof(pci->fname)-1,"%s_out.%d", dev, i);
561 if (stat(pci->fname, &st) < 0)
d0ca268b 562 break;
afd2d7ad 563 if (!st.st_size)
564 continue;
d0ca268b 565
d5396421 566 printf("Processing %s\n", pci->fname);
8fc0abbc 567
87b72777 568 tb = malloc(st.st_size);
8fc0abbc 569
d5396421
JA
570 pci->fd = open(pci->fname, O_RDONLY);
571 if (pci->fd < 0) {
572 perror(pci->fname);
3aabcd89 573 break;
d0ca268b 574 }
afd2d7ad 575
1f79c4a0 576 if (read_data(pci->fd, tb, st.st_size, 1))
3aabcd89 577 break;
d0ca268b 578
412819ce 579 ret = sort_entries(tb, st.st_size, ~0U);
8fc0abbc 580 if (ret == -1)
3aabcd89 581 break;
d0ca268b 582
d5396421 583 close(pci->fd);
d5396421
JA
584 printf("\t%2d %10s %15d\n", i, pci->fname, pci->nelems);
585
586 }
587
588 if (!nfiles) {
589 fprintf(stderr, "No files found\n");
590 return 1;
591 }
592
593 show_entries_rb();
d5396421
JA
594 return 0;
595}
596
412819ce 597static void resize_buffer(void **buffer, long *old_size)
d5396421 598{
412819ce 599 long cur_size = *old_size;
d5396421
JA
600 void *ptr;
601
412819ce
JA
602 *old_size *= 2;
603 ptr = malloc(*old_size);
604 memcpy(ptr, *buffer, cur_size);
605 free(*buffer);
606 *buffer = ptr;
607}
d5396421 608
412819ce
JA
609static int read_sort_events(int fd, void **buffer)
610{
611 long offset, max_offset;
612 int events;
d5396421 613
412819ce
JA
614 max_offset = 128 * sizeof(struct blk_io_trace);
615 *buffer = malloc(max_offset);
616 events = 0;
617 offset = 0;
d5396421 618
412819ce
JA
619 do {
620 struct blk_io_trace *t;
621 int pdu_len;
d5396421 622
412819ce
JA
623 if (max_offset - offset < sizeof(*t))
624 resize_buffer(buffer, &max_offset);
d5396421 625
412819ce
JA
626 if (read_data(fd, *buffer + offset, sizeof(*t), !events)) {
627 if (events)
d5396421 628 break;
412819ce
JA
629
630 usleep(1000);
631 continue;
d5396421
JA
632 }
633
412819ce
JA
634 t = *buffer + offset;
635 offset += sizeof(*t);
d5396421 636
412819ce 637 pdu_len = be16_to_cpu(t->pdu_len);
d5396421 638
412819ce
JA
639 if (max_offset - offset < pdu_len)
640 resize_buffer(buffer, &max_offset);
d5396421 641
412819ce
JA
642 if (read_data(fd, *buffer + offset, pdu_len, 1))
643 break;
d5396421 644
412819ce
JA
645 offset += pdu_len;
646 events++;
647 } while (!is_done());
d5396421 648
412819ce
JA
649 return events;
650}
d5396421 651
412819ce
JA
652static int do_stdin(void)
653{
654 int fd;
655 void *ptr;
d5396421 656
1f79c4a0 657 fd = dup(STDIN_FILENO);
412819ce
JA
658 do {
659 int events;
d5396421 660
412819ce
JA
661 events = read_sort_events(fd, &ptr);
662 if (!events)
663 break;
664
665 sort_entries(ptr, ~0UL, events);
666 show_entries_rb();
667 free_entries_rb();
d5396421
JA
668 } while (1);
669
670 close(fd);
671 free(ptr);
d5396421
JA
672 return 0;
673}
d0ca268b 674
1f79c4a0 675static void flush_output(void)
412819ce
JA
676{
677 int i;
678
679 for (i = 0; i < MAX_CPUS; i++) {
680 struct per_cpu_info *pci = &per_cpu_info[i];
681
682 if (pci->ofp) {
683 fflush(pci->ofp);
684 fclose(pci->ofp);
685 pci->ofp = NULL;
686 }
687 }
688}
689
1f79c4a0 690static void handle_sigint(int sig)
412819ce
JA
691{
692 done = 1;
693 flush_output();
694}
695
1f79c4a0
JA
696static void usage(char *prog)
697{
698 fprintf(stderr, "Usage: %s -i <name> [-o <output>]\n", prog);
699}
700
d5396421
JA
701int main(int argc, char *argv[])
702{
412819ce 703 int c, ret;
d5396421
JA
704
705 while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
706 switch (c) {
707 case 'i':
708 dev = strdup(optarg);
709 break;
710 case 'o':
711 output_name = strdup(optarg);
712 break;
713 default:
1f79c4a0 714 usage(argv[0]);
d5396421
JA
715 return 1;
716 }
d0ca268b
JA
717 }
718
d5396421 719 if (!dev) {
1f79c4a0 720 usage(argv[0]);
d5396421
JA
721 return 1;
722 }
723
724 memset(per_cpu_info, 0, sizeof(per_cpu_info));
412819ce
JA
725 memset(&rb_root, 0, sizeof(rb_root));
726
727 signal(SIGINT, handle_sigint);
728 signal(SIGHUP, handle_sigint);
729 signal(SIGTERM, handle_sigint);
d5396421
JA
730
731 if (!strcmp(dev, "-"))
732 ret = do_stdin();
733 else
734 ret = do_file();
735
412819ce
JA
736 show_stats();
737 flush_output();
d5396421 738 return ret;
d0ca268b 739}