[PATCH] blktrace: remove unneeded strdup
[blktrace.git] / blkparse.c
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  */
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>
27 #include <string.h>
28 #include <getopt.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <locale.h>
32
33 #include "blktrace.h"
34 #include "rbtree.h"
35
36 #define SECONDS(x)      ((unsigned long long)(x) / 1000000000)
37 #define NANO_SECONDS(x) ((unsigned long long)(x) % 1000000000)
38
39 static int backwards;
40 static unsigned long long genesis_time, last_reported_time;
41
42 struct io_stats {
43         unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
44         unsigned long ireads, iwrites;
45         unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
46         unsigned long long iread_kb, iwrite_kb;
47 };
48
49 struct per_cpu_info {
50         int cpu;
51         int nelems;
52
53         int fd;
54         char fname[128];
55
56         struct io_stats io_stats;
57 };
58
59 struct per_process_info {
60         char name[16];
61         __u32 pid;
62         struct io_stats io_stats;
63         struct per_process_info *hash_next, *list_next;
64 };
65
66 #define PPI_HASH_SHIFT  (8)
67 static struct per_process_info *ppi_hash[1 << PPI_HASH_SHIFT];
68 static struct per_process_info *ppi_list;
69
70 #define S_OPTS  "i:o:b:s"
71 static struct option l_opts[] = {
72         {
73                 .name = "input",
74                 .has_arg = 1,
75                 .flag = NULL,
76                 .val = 'i'
77         },
78         {
79                 .name = "output",
80                 .has_arg = 1,
81                 .flag = NULL,
82                 .val = 'o'
83         },
84         {
85                 .name = "batch",
86                 .has_arg = 1,
87                 .flag = NULL,
88                 .val = 'b'
89         },
90         {
91                 .name = "per program stats",
92                 .has_arg = 0,
93                 .flag = NULL,
94                 .val = 's'
95         },
96         {
97                 .name = NULL,
98                 .has_arg = 0,
99                 .flag = NULL,
100                 .val = 0
101         }
102 };
103
104 static struct rb_root rb_root;
105
106 struct trace {
107         struct blk_io_trace *bit;
108         struct rb_node rb_node;
109 };
110
111 static int max_cpus;
112 static struct per_cpu_info *per_cpu_info;
113
114 static unsigned long long events;
115
116 static char *dev, *output_name;
117 static FILE *ofp;
118
119 static int per_process_stats;
120
121 #define RB_BATCH_DEFAULT        (1024)
122 static int rb_batch = RB_BATCH_DEFAULT;
123
124 #define is_done()       (*(volatile int *)(&done))
125 static volatile int done;
126
127 static inline unsigned long hash_long(unsigned long val)
128 {
129 #if __WORDSIZE == 32
130         val *= 0x9e370001UL;
131 #elif __WORDSIZE == 64
132         val *= 0x9e37fffffffc0001UL;
133 #else
134 #error unknown word size
135 #endif
136
137         return val >> (__WORDSIZE - PPI_HASH_SHIFT);
138 }
139
140 static inline void add_process_to_hash(struct per_process_info *ppi)
141 {
142         const int hash_idx = hash_long(ppi->pid);
143
144         ppi->hash_next = ppi_hash[hash_idx];
145         ppi_hash[hash_idx] = ppi;
146 }
147
148 static inline void add_process_to_list(struct per_process_info *ppi)
149 {
150         ppi->list_next = ppi_list;
151         ppi_list = ppi;
152 }
153
154 static struct per_process_info *find_process_by_pid(__u32 pid)
155 {
156         const int hash_idx = hash_long(pid);
157         struct per_process_info *ppi;
158
159         ppi = ppi_hash[hash_idx];
160         while (ppi) {
161                 if (ppi->pid == pid)
162                         return ppi;
163
164                 ppi = ppi->hash_next;
165         }
166
167         return NULL;
168 }
169
170 static struct io_stats *find_process_io_stats(__u32 pid, char *name)
171 {
172         struct per_process_info *ppi = find_process_by_pid(pid);
173
174         if (!ppi) {
175                 ppi = malloc(sizeof(*ppi));
176                 memset(ppi, 0, sizeof(*ppi));
177                 strncpy(ppi->name, name, sizeof(ppi->name));
178                 ppi->pid = pid;
179                 add_process_to_hash(ppi);
180                 add_process_to_list(ppi);
181         }
182
183         return &ppi->io_stats;
184 }
185
186 static void resize_cpu_info(int cpuid)
187 {
188         int new_space, new_max = cpuid + 1;
189         char *new_start;
190
191         per_cpu_info = realloc(per_cpu_info, new_max * sizeof(*per_cpu_info));
192         if (!per_cpu_info) {
193                 fprintf(stderr, "Cannot allocate CPU info -- %d x %d bytes\n",
194                         new_max, (int) sizeof(*per_cpu_info));
195                 exit(1);
196         }
197
198         new_start = (char *)per_cpu_info + (max_cpus * sizeof(*per_cpu_info));
199         new_space = (new_max - max_cpus) * sizeof(*per_cpu_info);
200         memset(new_start, 0, new_space);
201         max_cpus = new_max;
202 }
203
204 static struct per_cpu_info *get_cpu_info(int cpu)
205 {
206         struct per_cpu_info *pci;
207
208         if (cpu >= max_cpus)
209                 resize_cpu_info(cpu);
210
211         /*
212          * ->cpu might already be set, but just set it unconditionally
213          */
214         pci = &per_cpu_info[cpu];
215         pci->cpu = cpu;
216
217         return pci;
218 }
219
220 static inline void check_time(struct blk_io_trace *bit)
221 {
222         unsigned long long this = bit->time;
223         unsigned long long last = last_reported_time;
224
225         backwards = (this < last) ? 'B' : ' ';
226         last_reported_time = this;
227 }
228
229 static inline void __account_m(struct io_stats *ios, struct blk_io_trace *t,
230                                int rw)
231 {
232         if (rw) {
233                 ios->mwrites++;
234                 ios->qwrite_kb += t->bytes >> 10;
235         } else {
236                 ios->mreads++;
237                 ios->qread_kb += t->bytes >> 10;
238         }
239 }
240
241 static inline void account_m(struct blk_io_trace *t, struct per_cpu_info *pci,
242                              int rw)
243 {
244         __account_m(&pci->io_stats, t, rw);
245
246         if (per_process_stats) {
247                 struct io_stats *ios = find_process_io_stats(t->pid, t->comm);
248
249                 __account_m(ios, t, rw);
250         }
251 }
252
253 static inline void __account_q(struct io_stats *ios, struct blk_io_trace *t,
254                                int rw)
255 {
256         if (rw) {
257                 ios->qwrites++;
258                 ios->qwrite_kb += t->bytes >> 10;
259         } else {
260                 ios->qreads++;
261                 ios->qread_kb += t->bytes >> 10;
262         }
263 }
264
265 static inline void account_q(struct blk_io_trace *t, struct per_cpu_info *pci,
266                              int rw)
267 {
268         __account_q(&pci->io_stats, t, rw);
269
270         if (per_process_stats) {
271                 struct io_stats *ios = find_process_io_stats(t->pid, t->comm);
272
273                 __account_q(ios, t, rw);
274         }
275 }
276
277 static inline void __account_c(struct io_stats *ios, int rw, unsigned int bytes)
278 {
279         if (rw) {
280                 ios->cwrites++;
281                 ios->cwrite_kb += bytes >> 10;
282         } else {
283                 ios->creads++;
284                 ios->cread_kb += bytes >> 10;
285         }
286 }
287
288 static inline void account_c(struct blk_io_trace *t, struct per_cpu_info *pci,
289                              int rw, int bytes)
290 {
291         __account_c(&pci->io_stats, rw, bytes);
292
293         if (per_process_stats) {
294                 struct io_stats *ios = find_process_io_stats(t->pid, t->comm);
295
296                 __account_c(ios, rw, bytes);
297         }
298 }
299
300 static inline void __account_i(struct io_stats *ios, int rw, unsigned int bytes)
301 {
302         if (rw) {
303                 ios->iwrites++;
304                 ios->iwrite_kb += bytes >> 10;
305         } else {
306                 ios->ireads++;
307                 ios->iread_kb += bytes >> 10;
308         }
309 }
310
311 static inline void account_i(struct blk_io_trace *t, struct per_cpu_info *pci,
312                              int rw)
313 {
314         __account_i(&pci->io_stats, rw, t->bytes);
315
316         if (per_process_stats) {
317                 struct io_stats *ios = find_process_io_stats(t->pid, t->comm);
318
319                 __account_i(ios, rw, t->bytes);
320         }
321 }
322
323 static void output(struct per_cpu_info *pci, char *s)
324 {
325         fprintf(ofp, "%s", s);
326 }
327
328 static char hstring[256];
329 static char tstring[256];
330
331 static inline char *setup_header(struct per_cpu_info *pci,
332                                  struct blk_io_trace *t, char act)
333 {
334         int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
335         int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
336         int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
337         char rwbs[4];
338         int i = 0;
339
340         if (w)
341                 rwbs[i++] = 'W';
342         else
343                 rwbs[i++] = 'R';
344         if (b)
345                 rwbs[i++] = 'B';
346         if (s)
347                 rwbs[i++] = 'S';
348
349         rwbs[i] = '\0';
350
351         sprintf(hstring, "%c %3d %15ld %5Lu.%09Lu %5u %c %3s", backwards,
352                 pci->cpu,
353                 (unsigned long)t->sequence, SECONDS(t->time), 
354                 NANO_SECONDS(t->time), t->pid, act, rwbs);
355
356         return hstring;
357 }
358
359 static void log_complete(struct per_cpu_info *pci, struct blk_io_trace *t,
360                          char act)
361 {
362         sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(pci, t, act),
363                 (unsigned long long)t->sector, t->bytes >> 9, t->error);
364         output(pci, tstring);
365 }
366
367 static void log_queue(struct per_cpu_info *pci, struct blk_io_trace *t,
368                       char act)
369 {
370         sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
371                 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
372         output(pci, tstring);
373 }
374
375 static void log_issue(struct per_cpu_info *pci, struct blk_io_trace *t,
376                       char act)
377 {
378         sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
379                 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
380         output(pci, tstring);
381 }
382
383 static void log_merge(struct per_cpu_info *pci, struct blk_io_trace *t,
384                       char act)
385 {
386         sprintf(tstring,"%s   %Lu + %u [%s]\n", setup_header(pci, t, act),
387                 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
388         output(pci, tstring);
389 }
390
391 static void log_generic(struct per_cpu_info *pci, struct blk_io_trace *t,
392                         char act)
393 {
394         sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
395                 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
396         output(pci, tstring);
397 }
398
399 static int log_pc(struct per_cpu_info *pci, struct blk_io_trace *t, char act)
400 {
401         unsigned char *buf;
402         int i;
403
404         sprintf(tstring,"%s ", setup_header(pci, t, act));
405         output(pci, tstring);
406
407         buf = (unsigned char *) t + sizeof(*t);
408         for (i = 0; i < t->pdu_len; i++) {
409                 sprintf(tstring,"%02x ", buf[i]);
410                 output(pci, tstring);
411         }
412
413         if (act == 'C') {
414                 sprintf(tstring,"[%d]\n", t->error);
415                 output(pci, tstring);
416         } else {
417                 sprintf(tstring,"[%s]\n", t->comm);
418                 output(pci, tstring);
419         }
420         return 0;
421 }
422
423 static int dump_trace_pc(struct blk_io_trace *t, struct per_cpu_info *pci)
424 {
425         int ret = 0;
426
427         switch (t->action & 0xffff) {
428                 case __BLK_TA_QUEUE:
429                         log_generic(pci, t, 'Q');
430                         break;
431                 case __BLK_TA_GETRQ:
432                         log_generic(pci, t, 'G');
433                         break;
434                 case __BLK_TA_SLEEPRQ:
435                         log_generic(pci, t, 'S');
436                         break;
437                 case __BLK_TA_REQUEUE:
438                         log_generic(pci, t, 'R');
439                         break;
440                 case __BLK_TA_ISSUE:
441                         ret = log_pc(pci, t, 'D');
442                         break;
443                 case __BLK_TA_COMPLETE:
444                         log_pc(pci, t, 'C');
445                         break;
446                 default:
447                         fprintf(stderr, "Bad pc action %x\n", t->action);
448                         ret = 1;
449                         break;
450         }
451         
452         return ret;
453 }
454
455 static void dump_trace_fs(struct blk_io_trace *t, struct per_cpu_info *pci)
456 {
457         int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
458
459         switch (t->action & 0xffff) {
460                 case __BLK_TA_QUEUE:
461                         account_q(t, pci, w);
462                         log_queue(pci, t, 'Q');
463                         break;
464                 case __BLK_TA_BACKMERGE:
465                         account_m(t, pci, w);
466                         log_merge(pci, t, 'M');
467                         break;
468                 case __BLK_TA_FRONTMERGE:
469                         account_m(t, pci, w);
470                         log_merge(pci, t, 'F');
471                         break;
472                 case __BLK_TA_GETRQ:
473                         log_generic(pci, t, 'G');
474                         break;
475                 case __BLK_TA_SLEEPRQ:
476                         log_generic(pci, t, 'S');
477                         break;
478                 case __BLK_TA_REQUEUE:
479                         account_c(t, pci, w, -t->bytes);
480                         log_queue(pci, t, 'R');
481                         break;
482                 case __BLK_TA_ISSUE:
483                         account_i(t, pci, w);
484                         log_issue(pci, t, 'D');
485                         break;
486                 case __BLK_TA_COMPLETE:
487                         account_c(t, pci, w, t->bytes);
488                         log_complete(pci, t, 'C');
489                         break;
490                 default:
491                         fprintf(stderr, "Bad fs action %x\n", t->action);
492                         break;
493         }
494 }
495
496 static int dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci)
497 {
498         int ret = 0;
499
500         if (t->action & BLK_TC_ACT(BLK_TC_PC))
501                 ret = dump_trace_pc(t, pci);
502         else
503                 dump_trace_fs(t, pci);
504
505         events++;
506         return ret;
507 }
508
509 static void dump_io_stats(struct io_stats *ios, char *msg)
510 {
511         fprintf(ofp, "%s\n", msg);
512
513         fprintf(ofp, " Reads Queued:    %'8lu, %'8LuKiB\t", ios->qreads, ios->qread_kb);
514         fprintf(ofp, " Writes Queued:    %'8lu, %'8LuKiB\n", ios->qwrites,ios->qwrite_kb);
515
516         fprintf(ofp, " Read Dispatches: %'8lu, %'8LuKiB\t", ios->ireads, ios->iread_kb);
517         fprintf(ofp, " Write Dispatches: %'8lu, %'8LuKiB\n", ios->iwrites,ios->iwrite_kb);
518         fprintf(ofp, " Reads Completed: %'8lu, %'8LuKiB\t", ios->creads, ios->cread_kb);
519         fprintf(ofp, " Writes Completed: %'8lu, %'8LuKiB\n", ios->cwrites,ios->cwrite_kb);
520         fprintf(ofp, " Read Merges:     %'8lu%8c\t", ios->mreads, ' ');
521
522         fprintf(ofp, " Write Merges:     %'8lu\n", ios->mwrites);
523 }
524
525 static void show_process_stats(void)
526 {
527         struct per_process_info *ppi;
528
529         ppi = ppi_list;
530         while (ppi) {
531                 dump_io_stats(&ppi->io_stats, ppi->name);
532                 ppi = ppi->list_next;
533         }
534
535         fprintf(ofp, "\n");
536 }
537
538 static void show_cpu_stats(void)
539 {
540         struct per_cpu_info foo, *pci;
541         struct io_stats *ios;
542         int i, pci_events = 0;
543
544         memset(&foo, 0, sizeof(foo));
545
546         for (i = 0; i < max_cpus; i++) {
547                 char cpu[8];
548
549                 pci = &per_cpu_info[i];
550                 ios = &pci->io_stats;
551
552                 if (!pci->nelems)
553                         continue;
554
555                 foo.io_stats.qreads += ios->qreads;
556                 foo.io_stats.qwrites += ios->qwrites;
557                 foo.io_stats.creads += ios->creads;
558                 foo.io_stats.cwrites += ios->cwrites;
559                 foo.io_stats.mreads += ios->mreads;
560                 foo.io_stats.mwrites += ios->mwrites;
561                 foo.io_stats.ireads += ios->ireads;
562                 foo.io_stats.iwrites += ios->iwrites;
563                 foo.io_stats.qread_kb += ios->qread_kb;
564                 foo.io_stats.qwrite_kb += ios->qwrite_kb;
565                 foo.io_stats.cread_kb += ios->cread_kb;
566                 foo.io_stats.cwrite_kb += ios->cwrite_kb;
567                 foo.io_stats.iread_kb += ios->iread_kb;
568                 foo.io_stats.iwrite_kb += ios->iwrite_kb;
569
570                 snprintf(cpu, sizeof(cpu) - 1, "CPU%d:", i);
571                 dump_io_stats(ios, cpu);
572                 pci_events++;
573         }
574
575         if (pci_events > 1) {
576                 fprintf(ofp, "\n");
577                 dump_io_stats(&foo.io_stats, "Total:");
578         }
579
580         fprintf(ofp, "\nEvents: %'Lu\n", events);
581 }
582
583 static inline int trace_rb_insert(struct trace *t)
584 {
585         struct rb_node **p = &rb_root.rb_node;
586         struct rb_node *parent = NULL;
587         struct trace *__t;
588
589         while (*p) {
590                 parent = *p;
591                 __t = rb_entry(parent, struct trace, rb_node);
592
593                 if (t->bit->sequence < __t->bit->sequence)
594                         p = &(*p)->rb_left;
595                 else if (t->bit->sequence > __t->bit->sequence)
596                         p = &(*p)->rb_right;
597                 else {
598                         fprintf(stderr, "sequence alias!\n");
599                         return 1;
600                 }
601         }
602
603         rb_link_node(&t->rb_node, parent, p);
604         rb_insert_color(&t->rb_node, &rb_root);
605         return 0;
606 }
607
608 #define min(a, b)       ((a) < (b) ? (a) : (b))
609
610 static struct blk_io_trace *find_trace(void *p, unsigned long offset, int nr)
611 {
612         unsigned long max_offset = min(offset,nr * sizeof(struct blk_io_trace));
613         unsigned long off;
614         struct blk_io_trace *bit;
615         __u32 magic;
616
617         for (off = 0; off < max_offset; off++) {
618                 bit = p + off;
619
620                 magic = be32_to_cpu(bit->magic);
621                 if ((magic & 0xffffff00) == BLK_IO_TRACE_MAGIC)
622                         return bit;
623         }
624
625         return NULL;
626 }
627
628 static int sort_entries(void *traces, unsigned long offset, int nr)
629 {
630         struct per_cpu_info *pci;
631         struct blk_io_trace *bit;
632         struct trace *t;
633         void *start = traces;
634         int nelems = 0;
635
636         while (traces - start <= offset - sizeof(*bit)) {
637                 if (!nr)
638                         break;
639
640                 bit = find_trace(traces, offset - (traces - start), nr);
641                 if (!bit)
642                         break;
643
644                 t = malloc(sizeof(*t));
645                 t->bit = bit;
646                 memset(&t->rb_node, 0, sizeof(t->rb_node));
647
648                 trace_to_cpu(bit);
649
650                 if (verify_trace(bit))
651                         break;
652
653                 pci = get_cpu_info(bit->cpu);
654                 pci->nelems++;
655
656                 if (trace_rb_insert(t))
657                         return -1;
658
659                 traces += sizeof(*bit) + bit->pdu_len;
660                 nelems++;
661                 nr--;
662         }
663
664         return nelems;
665 }
666
667 static void free_entries_rb(void)
668 {
669         struct rb_node *n;
670
671         while ((n = rb_first(&rb_root)) != NULL) {
672                 struct trace *t = rb_entry(n, struct trace, rb_node);
673
674                 rb_erase(&t->rb_node, &rb_root);
675                 free(t);
676         }
677 }
678
679 static void show_entries_rb(void)
680 {
681         struct blk_io_trace *bit;
682         struct rb_node *n;
683         struct trace *t;
684         int cpu;
685
686         n = rb_first(&rb_root);
687         if (!n)
688                 return;
689
690         do {
691                 t = rb_entry(n, struct trace, rb_node);
692                 bit = t->bit;
693
694                 cpu = bit->cpu;
695                 if (cpu > max_cpus) {
696                         fprintf(stderr, "CPU number too large (%d)\n", cpu);
697                         break;
698                 }
699
700                 if (genesis_time == 0)
701                         genesis_time = bit->time;
702                 bit->time -= genesis_time;
703
704                 check_time(bit);
705
706                 if (dump_trace(bit, &per_cpu_info[cpu]))
707                         break;
708
709         } while ((n = rb_next(n)) != NULL);
710 }
711
712 static int read_data(int fd, void *buffer, int bytes, int block)
713 {
714         int ret, bytes_left, fl;
715         void *p;
716
717         fl = fcntl(fd, F_GETFL);
718
719         if (!block)
720                 fcntl(fd, F_SETFL, fl | O_NONBLOCK);
721         else
722                 fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
723
724         bytes_left = bytes;
725         p = buffer;
726         while (bytes_left > 0) {
727                 ret = read(fd, p, bytes_left);
728                 if (!ret)
729                         return 1;
730                 else if (ret < 0) {
731                         if (errno != EAGAIN)
732                                 perror("read");
733                         return -1;
734                 } else {
735                         p += ret;
736                         bytes_left -= ret;
737                 }
738         }
739
740         return 0;
741 }
742
743 static int do_file(void)
744 {
745         int i, nfiles;
746
747         for (i = 0, nfiles = 0;; i++, nfiles++) {
748                 struct per_cpu_info *pci;
749                 struct stat st;
750                 void *tb;
751
752                 pci = get_cpu_info(i);
753
754                 snprintf(pci->fname, sizeof(pci->fname)-1,"%s_out.%d", dev, i);
755                 if (stat(pci->fname, &st) < 0)
756                         break;
757                 if (!st.st_size)
758                         continue;
759
760                 printf("Processing %s\n", pci->fname);
761
762                 tb = malloc(st.st_size);
763
764                 pci->fd = open(pci->fname, O_RDONLY);
765                 if (pci->fd < 0) {
766                         perror(pci->fname);
767                         break;
768                 }
769
770                 if (read_data(pci->fd, tb, st.st_size, 1))
771                         break;
772
773                 if (sort_entries(tb, st.st_size, ~0U) == -1)
774                         break;
775
776                 close(pci->fd);
777                 printf("\t%2d %10s %15d\n", i, pci->fname, pci->nelems);
778
779         }
780
781         if (!nfiles) {
782                 fprintf(stderr, "No files found\n");
783                 return 1;
784         }
785
786         show_entries_rb();
787         return 0;
788 }
789
790 static void resize_buffer(void **buffer, long *size, long offset)
791 {
792         long old_size = *size;
793
794         *size *= 2;
795         *buffer = realloc(*buffer, *size);
796         memset(*buffer + offset, 0, *size - old_size);
797 }
798
799 static int read_sort_events(int fd, void **buffer)
800 {
801         long offset, max_offset;
802         int events;
803
804         max_offset = 128 * sizeof(struct blk_io_trace);
805         *buffer = malloc(max_offset);
806         events = 0;
807         offset = 0;
808
809         do {
810                 struct blk_io_trace *t;
811                 int pdu_len;
812
813                 if (max_offset - offset < sizeof(*t))
814                         resize_buffer(buffer, &max_offset, offset);
815
816                 if (read_data(fd, *buffer + offset, sizeof(*t), !events)) {
817                         if (events)
818                                 break;
819
820                         usleep(1000);
821                         continue;
822                 }
823
824                 t = *buffer + offset;
825                 offset += sizeof(*t);
826
827                 pdu_len = be16_to_cpu(t->pdu_len);
828                 if (pdu_len) {
829                         if (max_offset - offset < pdu_len)
830                                 resize_buffer(buffer, &max_offset, offset);
831
832                         if (read_data(fd, *buffer + offset, pdu_len, 1))
833                                 break;
834
835                         offset += pdu_len;
836                 }
837
838                 events++;
839         } while (!is_done() && events < rb_batch);
840
841         return events;
842 }
843
844 static int do_stdin(void)
845 {
846         int fd;
847         void *ptr;
848
849         fd = dup(STDIN_FILENO);
850         do {
851                 int events;
852
853                 events = read_sort_events(fd, &ptr);
854                 if (!events)
855                         break;
856         
857                 if (sort_entries(ptr, ~0UL, events) == -1)
858                         break;
859
860                 show_entries_rb();
861                 free_entries_rb();
862         } while (1);
863
864         close(fd);
865         free(ptr);
866         return 0;
867 }
868
869 static void flush_output(void)
870 {
871         fflush(ofp);
872 }
873
874 static void handle_sigint(int sig)
875 {
876         done = 1;
877         flush_output();
878 }
879
880 static void usage(char *prog)
881 {
882         fprintf(stderr, "Usage: %s -i <name> [-o <output>][-s]\n", prog);
883 }
884
885 int main(int argc, char *argv[])
886 {
887         char *ofp_buffer;
888         int c, ret;
889
890         while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
891                 switch (c) {
892                 case 'i':
893                         dev = optarg;
894                         break;
895                 case 'o':
896                         output_name = optarg;
897                         break;
898                 case 'b':
899                         rb_batch = atoi(optarg);
900                         if (rb_batch <= 0)
901                                 rb_batch = RB_BATCH_DEFAULT;
902                         break;
903                 case 's':
904                         per_process_stats = 1;
905                         break;
906                 default:
907                         usage(argv[0]);
908                         return 1;
909                 }
910         }
911
912         if (!dev) {
913                 usage(argv[0]);
914                 return 1;
915         }
916
917         memset(&rb_root, 0, sizeof(rb_root));
918
919         signal(SIGINT, handle_sigint);
920         signal(SIGHUP, handle_sigint);
921         signal(SIGTERM, handle_sigint);
922
923         setlocale(LC_NUMERIC, "en_US");
924
925         if (!output_name)
926                 ofp = fdopen(STDOUT_FILENO, "w");
927         else {
928                 char ofname[128];
929
930                 snprintf(ofname, sizeof(ofname) - 1, "%s.log", output_name);
931                 ofp = fopen(ofname, "w");
932         }
933
934         if (!ofp) {
935                 perror("fopen");
936                 return 1;
937         }
938
939         ofp_buffer = malloc(4096);      
940         if (setvbuf(ofp, ofp_buffer, _IOFBF, 4096)) {
941                 perror("setvbuf");
942                 return 1;
943         }
944
945         if (!strcmp(dev, "-"))
946                 ret = do_stdin();
947         else
948                 ret = do_file();
949
950         if (per_process_stats)
951                 show_process_stats();
952
953         show_cpu_stats();
954
955         flush_output();
956         return ret;
957 }