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