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