[PATCH] blktrace: Fix whitespace in log_merge()
[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
152f6476
JA
42struct 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
d5396421 49struct per_cpu_info {
d0ca268b
JA
50 int cpu;
51 int nelems;
d0ca268b
JA
52
53 int fd;
87b72777 54 char fname[128];
d0ca268b 55
152f6476
JA
56 struct io_stats io_stats;
57};
8fc0abbc 58
152f6476
JA
59struct 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;
d0ca268b
JA
64};
65
152f6476
JA
66#define PPI_HASH_SHIFT (8)
67static struct per_process_info *ppi_hash[1 << PPI_HASH_SHIFT];
68static struct per_process_info *ppi_list;
69
70#define S_OPTS "i:o:b:s"
d5396421
JA
71static 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 },
79f19470
JA
84 {
85 .name = "batch",
86 .has_arg = 1,
87 .flag = NULL,
88 .val = 'b'
89 },
152f6476
JA
90 {
91 .name = "per program stats",
92 .has_arg = 0,
93 .flag = NULL,
94 .val = 's'
95 },
d5396421
JA
96 {
97 .name = NULL,
98 .has_arg = 0,
99 .flag = NULL,
100 .val = 0
101 }
102};
103
8fc0abbc
JA
104static struct rb_root rb_root;
105
106struct trace {
107 struct blk_io_trace *bit;
108 struct rb_node rb_node;
109};
110
a718bd37
NS
111static int max_cpus;
112static struct per_cpu_info *per_cpu_info;
d0ca268b 113
87b72777
JA
114static unsigned long long events;
115
d5396421 116static char *dev, *output_name;
152f6476
JA
117static FILE *ofp;
118
119static int per_process_stats;
d0ca268b 120
79f19470
JA
121#define RB_BATCH_DEFAULT (1024)
122static int rb_batch = RB_BATCH_DEFAULT;
123
412819ce
JA
124#define is_done() (*(volatile int *)(&done))
125static volatile int done;
126
152f6476
JA
127static inline unsigned long hash_long(unsigned long val)
128{
16ef714e
JA
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);
152f6476
JA
138}
139
140static 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
148static inline void add_process_to_list(struct per_process_info *ppi)
149{
150 ppi->list_next = ppi_list;
151 ppi_list = ppi;
152}
153
154static 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
170static 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
a718bd37
NS
186static 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
204static struct per_cpu_info *get_cpu_info(int cpu)
205{
c499bf38
JA
206 struct per_cpu_info *pci;
207
a718bd37
NS
208 if (cpu >= max_cpus)
209 resize_cpu_info(cpu);
210
c499bf38
JA
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;
a718bd37
NS
218}
219
cfab07eb
AB
220static 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
152f6476
JA
229static inline void __account_m(struct io_stats *ios, struct blk_io_trace *t,
230 int rw)
d0ca268b
JA
231{
232 if (rw) {
152f6476
JA
233 ios->mwrites++;
234 ios->qwrite_kb += t->bytes >> 10;
d0ca268b 235 } else {
152f6476
JA
236 ios->mreads++;
237 ios->qread_kb += t->bytes >> 10;
238 }
239}
240
241static 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);
d0ca268b
JA
250 }
251}
252
152f6476
JA
253static inline void __account_q(struct io_stats *ios, struct blk_io_trace *t,
254 int rw)
d0ca268b
JA
255{
256 if (rw) {
152f6476
JA
257 ios->qwrites++;
258 ios->qwrite_kb += t->bytes >> 10;
d0ca268b 259 } else {
152f6476
JA
260 ios->qreads++;
261 ios->qread_kb += t->bytes >> 10;
262 }
263}
264
265static 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);
d0ca268b
JA
274 }
275}
276
152f6476 277static inline void __account_c(struct io_stats *ios, int rw, unsigned int bytes)
d0ca268b
JA
278{
279 if (rw) {
152f6476
JA
280 ios->cwrites++;
281 ios->cwrite_kb += bytes >> 10;
d0ca268b 282 } else {
152f6476
JA
283 ios->creads++;
284 ios->cread_kb += bytes >> 10;
285 }
286}
287
288static 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);
d0ca268b
JA
297 }
298}
299
152f6476 300static inline void __account_i(struct io_stats *ios, int rw, unsigned int bytes)
afd2d7ad 301{
302 if (rw) {
152f6476
JA
303 ios->iwrites++;
304 ios->iwrite_kb += bytes >> 10;
afd2d7ad 305 } else {
152f6476
JA
306 ios->ireads++;
307 ios->iread_kb += bytes >> 10;
afd2d7ad 308 }
309}
310
152f6476
JA
311static inline void account_i(struct blk_io_trace *t, struct per_cpu_info *pci,
312 int rw)
d0ca268b 313{
152f6476
JA
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);
d5396421 318
152f6476
JA
319 __account_i(ios, rw, t->bytes);
320 }
321}
322
323static void output(struct per_cpu_info *pci, char *s)
324{
325 fprintf(ofp, "%s", s);
d0ca268b
JA
326}
327
3aabcd89
JA
328static char hstring[256];
329static char tstring[256];
d0ca268b 330
d5396421
JA
331static inline char *setup_header(struct per_cpu_info *pci,
332 struct blk_io_trace *t, char act)
d0ca268b
JA
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
cfab07eb 351 sprintf(hstring, "%c %3d %15ld %5Lu.%09Lu %5u %c %3s", backwards,
d5396421 352 pci->cpu,
cfab07eb
AB
353 (unsigned long)t->sequence, SECONDS(t->time),
354 NANO_SECONDS(t->time), t->pid, act, rwbs);
d0ca268b
JA
355
356 return hstring;
357}
358
d5396421
JA
359static void log_complete(struct per_cpu_info *pci, struct blk_io_trace *t,
360 char act)
d0ca268b 361{
d5396421 362 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(pci, t, act),
d0ca268b 363 (unsigned long long)t->sector, t->bytes >> 9, t->error);
d5396421 364 output(pci, tstring);
d0ca268b
JA
365}
366
d5396421
JA
367static void log_queue(struct per_cpu_info *pci, struct blk_io_trace *t,
368 char act)
d0ca268b 369{
2955af9d
NS
370 sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
371 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
d5396421 372 output(pci, tstring);
d0ca268b
JA
373}
374
d5396421
JA
375static void log_issue(struct per_cpu_info *pci, struct blk_io_trace *t,
376 char act)
d0ca268b 377{
2955af9d
NS
378 sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
379 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
d5396421 380 output(pci, tstring);
d0ca268b
JA
381}
382
d5396421
JA
383static void log_merge(struct per_cpu_info *pci, struct blk_io_trace *t,
384 char act)
d0ca268b 385{
984c63b7 386 sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
2955af9d 387 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
d5396421 388 output(pci, tstring);
d0ca268b
JA
389}
390
d5396421
JA
391static void log_generic(struct per_cpu_info *pci, struct blk_io_trace *t,
392 char act)
d0ca268b 393{
2955af9d
NS
394 sprintf(tstring,"%s %Lu + %u [%s]\n", setup_header(pci, t, act),
395 (unsigned long long)t->sector, t->bytes >> 9, t->comm);
d5396421 396 output(pci, tstring);
d0ca268b
JA
397}
398
d5396421 399static int log_pc(struct per_cpu_info *pci, struct blk_io_trace *t, char act)
d0ca268b 400{
87b72777
JA
401 unsigned char *buf;
402 int i;
d0ca268b 403
d5396421
JA
404 sprintf(tstring,"%s ", setup_header(pci, t, act));
405 output(pci, tstring);
d0ca268b 406
87b72777 407 buf = (unsigned char *) t + sizeof(*t);
d0ca268b
JA
408 for (i = 0; i < t->pdu_len; i++) {
409 sprintf(tstring,"%02x ", buf[i]);
d5396421 410 output(pci, tstring);
d0ca268b
JA
411 }
412
413 if (act == 'C') {
2955af9d
NS
414 sprintf(tstring,"[%d]\n", t->error);
415 output(pci, tstring);
416 } else {
417 sprintf(tstring,"[%s]\n", t->comm);
d5396421 418 output(pci, tstring);
d0ca268b 419 }
87b72777 420 return 0;
d0ca268b
JA
421}
422
d5396421 423static int dump_trace_pc(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b 424{
87b72777
JA
425 int ret = 0;
426
d0ca268b
JA
427 switch (t->action & 0xffff) {
428 case __BLK_TA_QUEUE:
d5396421 429 log_generic(pci, t, 'Q');
d0ca268b
JA
430 break;
431 case __BLK_TA_GETRQ:
d5396421 432 log_generic(pci, t, 'G');
d0ca268b
JA
433 break;
434 case __BLK_TA_SLEEPRQ:
d5396421 435 log_generic(pci, t, 'S');
d0ca268b
JA
436 break;
437 case __BLK_TA_REQUEUE:
d5396421 438 log_generic(pci, t, 'R');
d0ca268b
JA
439 break;
440 case __BLK_TA_ISSUE:
d5396421 441 ret = log_pc(pci, t, 'D');
d0ca268b
JA
442 break;
443 case __BLK_TA_COMPLETE:
d5396421 444 log_pc(pci, t, 'C');
d0ca268b
JA
445 break;
446 default:
447 fprintf(stderr, "Bad pc action %x\n", t->action);
87b72777
JA
448 ret = 1;
449 break;
d0ca268b
JA
450 }
451
87b72777 452 return ret;
d0ca268b
JA
453}
454
d5396421 455static void dump_trace_fs(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b
JA
456{
457 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
458
459 switch (t->action & 0xffff) {
460 case __BLK_TA_QUEUE:
152f6476 461 account_q(t, pci, w);
d5396421 462 log_queue(pci, t, 'Q');
d0ca268b
JA
463 break;
464 case __BLK_TA_BACKMERGE:
152f6476 465 account_m(t, pci, w);
d5396421 466 log_merge(pci, t, 'M');
d0ca268b
JA
467 break;
468 case __BLK_TA_FRONTMERGE:
152f6476 469 account_m(t, pci, w);
d5396421 470 log_merge(pci, t, 'F');
d0ca268b
JA
471 break;
472 case __BLK_TA_GETRQ:
d5396421 473 log_generic(pci, t, 'G');
d0ca268b
JA
474 break;
475 case __BLK_TA_SLEEPRQ:
d5396421 476 log_generic(pci, t, 'S');
d0ca268b
JA
477 break;
478 case __BLK_TA_REQUEUE:
152f6476 479 account_c(t, pci, w, -t->bytes);
d5396421 480 log_queue(pci, t, 'R');
d0ca268b
JA
481 break;
482 case __BLK_TA_ISSUE:
152f6476 483 account_i(t, pci, w);
d5396421 484 log_issue(pci, t, 'D');
d0ca268b
JA
485 break;
486 case __BLK_TA_COMPLETE:
152f6476 487 account_c(t, pci, w, t->bytes);
d5396421 488 log_complete(pci, t, 'C');
d0ca268b
JA
489 break;
490 default:
491 fprintf(stderr, "Bad fs action %x\n", t->action);
1f79c4a0 492 break;
d0ca268b 493 }
d0ca268b
JA
494}
495
d5396421 496static int dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci)
d0ca268b 497{
87b72777
JA
498 int ret = 0;
499
d0ca268b 500 if (t->action & BLK_TC_ACT(BLK_TC_PC))
d5396421 501 ret = dump_trace_pc(t, pci);
d0ca268b 502 else
d5396421 503 dump_trace_fs(t, pci);
87b72777
JA
504
505 events++;
506 return ret;
d0ca268b
JA
507}
508
152f6476 509static void dump_io_stats(struct io_stats *ios, char *msg)
5c017e4b 510{
152f6476
JA
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);
0a6b8fc4 515
152f6476
JA
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, ' ');
0a6b8fc4 521
152f6476 522 fprintf(ofp, " Write Merges: %'8lu\n", ios->mwrites);
5c017e4b
JA
523}
524
152f6476
JA
525static 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
538static void show_cpu_stats(void)
d0ca268b 539{
d5396421 540 struct per_cpu_info foo, *pci;
152f6476 541 struct io_stats *ios;
412819ce 542 int i, pci_events = 0;
5c017e4b
JA
543
544 memset(&foo, 0, sizeof(foo));
d0ca268b 545
a718bd37 546 for (i = 0; i < max_cpus; i++) {
152f6476
JA
547 char cpu[8];
548
d5396421 549 pci = &per_cpu_info[i];
152f6476 550 ios = &pci->io_stats;
5c017e4b 551
d5396421 552 if (!pci->nelems)
afd2d7ad 553 continue;
554
152f6476
JA
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;
11e51068
NS
561 foo.io_stats.ireads += ios->ireads;
562 foo.io_stats.iwrites += ios->iwrites;
152f6476
JA
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;
11e51068
NS
567 foo.io_stats.iread_kb += ios->iread_kb;
568 foo.io_stats.iwrite_kb += ios->iwrite_kb;
152f6476
JA
569
570 snprintf(cpu, sizeof(cpu) - 1, "CPU%d:", i);
571 dump_io_stats(ios, cpu);
412819ce 572 pci_events++;
5c017e4b
JA
573 }
574
412819ce 575 if (pci_events > 1) {
152f6476
JA
576 fprintf(ofp, "\n");
577 dump_io_stats(&foo.io_stats, "Total:");
5c017e4b 578 }
d0ca268b 579
152f6476 580 fprintf(ofp, "\nEvents: %'Lu\n", events);
d0ca268b
JA
581}
582
3aabcd89 583static inline int trace_rb_insert(struct trace *t)
8fc0abbc
JA
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 {
87b72777 598 fprintf(stderr, "sequence alias!\n");
8fc0abbc
JA
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
2ff323b0
JA
608#define min(a, b) ((a) < (b) ? (a) : (b))
609
610static 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
412819ce 628static int sort_entries(void *traces, unsigned long offset, int nr)
8fc0abbc 629{
412819ce 630 struct per_cpu_info *pci;
8fc0abbc
JA
631 struct blk_io_trace *bit;
632 struct trace *t;
633 void *start = traces;
634 int nelems = 0;
635
6fe4709e 636 while (traces - start <= offset - sizeof(*bit)) {
412819ce
JA
637 if (!nr)
638 break;
639
2ff323b0
JA
640 bit = find_trace(traces, offset - (traces - start), nr);
641 if (!bit)
642 break;
6fe4709e 643
8fc0abbc
JA
644 t = malloc(sizeof(*t));
645 t->bit = bit;
646 memset(&t->rb_node, 0, sizeof(t->rb_node));
647
6fe4709e
JA
648 trace_to_cpu(bit);
649
66fa7233
JA
650 if (verify_trace(bit))
651 break;
652
a718bd37 653 pci = get_cpu_info(bit->cpu);
412819ce
JA
654 pci->nelems++;
655
8fc0abbc
JA
656 if (trace_rb_insert(t))
657 return -1;
658
659 traces += sizeof(*bit) + bit->pdu_len;
660 nelems++;
412819ce 661 nr--;
6fe4709e 662 }
8fc0abbc
JA
663
664 return nelems;
665}
666
412819ce
JA
667static 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
d5396421 679static void show_entries_rb(void)
8fc0abbc 680{
8fc0abbc 681 struct blk_io_trace *bit;
3aabcd89 682 struct rb_node *n;
8fc0abbc
JA
683 struct trace *t;
684 int cpu;
685
3aabcd89
JA
686 n = rb_first(&rb_root);
687 if (!n)
688 return;
8fc0abbc 689
3aabcd89 690 do {
8fc0abbc
JA
691 t = rb_entry(n, struct trace, rb_node);
692 bit = t->bit;
693
d5396421 694 cpu = bit->cpu;
87b72777 695 if (cpu > max_cpus) {
8fc0abbc 696 fprintf(stderr, "CPU number too large (%d)\n", cpu);
87b72777 697 break;
8fc0abbc
JA
698 }
699
cfab07eb
AB
700 if (genesis_time == 0)
701 genesis_time = bit->time;
702 bit->time -= genesis_time;
8fc0abbc 703
cfab07eb 704 check_time(bit);
8fc0abbc 705
d5396421 706 if (dump_trace(bit, &per_cpu_info[cpu]))
87b72777
JA
707 break;
708
8fc0abbc
JA
709 } while ((n = rb_next(n)) != NULL);
710}
711
1f79c4a0
JA
712static 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
d5396421 743static int do_file(void)
d0ca268b 744{
a718bd37 745 int i, nfiles;
d0ca268b 746
a718bd37
NS
747 for (i = 0, nfiles = 0;; i++, nfiles++) {
748 struct per_cpu_info *pci;
87b72777
JA
749 struct stat st;
750 void *tb;
751
a718bd37 752 pci = get_cpu_info(i);
d0ca268b 753
d5396421
JA
754 snprintf(pci->fname, sizeof(pci->fname)-1,"%s_out.%d", dev, i);
755 if (stat(pci->fname, &st) < 0)
d0ca268b 756 break;
afd2d7ad 757 if (!st.st_size)
758 continue;
d0ca268b 759
d5396421 760 printf("Processing %s\n", pci->fname);
8fc0abbc 761
87b72777 762 tb = malloc(st.st_size);
8fc0abbc 763
d5396421
JA
764 pci->fd = open(pci->fname, O_RDONLY);
765 if (pci->fd < 0) {
766 perror(pci->fname);
3aabcd89 767 break;
d0ca268b 768 }
afd2d7ad 769
1f79c4a0 770 if (read_data(pci->fd, tb, st.st_size, 1))
3aabcd89 771 break;
d0ca268b 772
a718bd37 773 if (sort_entries(tb, st.st_size, ~0U) == -1)
3aabcd89 774 break;
d0ca268b 775
d5396421 776 close(pci->fd);
d5396421
JA
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();
d5396421
JA
787 return 0;
788}
789
2ff323b0 790static void resize_buffer(void **buffer, long *size, long offset)
d5396421 791{
2ff323b0 792 long old_size = *size;
d5396421 793
2ff323b0
JA
794 *size *= 2;
795 *buffer = realloc(*buffer, *size);
796 memset(*buffer + offset, 0, *size - old_size);
412819ce 797}
d5396421 798
412819ce
JA
799static int read_sort_events(int fd, void **buffer)
800{
801 long offset, max_offset;
802 int events;
d5396421 803
412819ce
JA
804 max_offset = 128 * sizeof(struct blk_io_trace);
805 *buffer = malloc(max_offset);
806 events = 0;
807 offset = 0;
d5396421 808
412819ce
JA
809 do {
810 struct blk_io_trace *t;
811 int pdu_len;
d5396421 812
412819ce 813 if (max_offset - offset < sizeof(*t))
2ff323b0 814 resize_buffer(buffer, &max_offset, offset);
d5396421 815
412819ce
JA
816 if (read_data(fd, *buffer + offset, sizeof(*t), !events)) {
817 if (events)
d5396421 818 break;
412819ce
JA
819
820 usleep(1000);
821 continue;
d5396421
JA
822 }
823
412819ce
JA
824 t = *buffer + offset;
825 offset += sizeof(*t);
d5396421 826
412819ce 827 pdu_len = be16_to_cpu(t->pdu_len);
2ff323b0
JA
828 if (pdu_len) {
829 if (max_offset - offset < pdu_len)
830 resize_buffer(buffer, &max_offset, offset);
d5396421 831
2ff323b0
JA
832 if (read_data(fd, *buffer + offset, pdu_len, 1))
833 break;
d5396421 834
2ff323b0
JA
835 offset += pdu_len;
836 }
d5396421 837
412819ce 838 events++;
79f19470 839 } while (!is_done() && events < rb_batch);
d5396421 840
412819ce
JA
841 return events;
842}
d5396421 843
412819ce
JA
844static int do_stdin(void)
845{
846 int fd;
847 void *ptr;
d5396421 848
1f79c4a0 849 fd = dup(STDIN_FILENO);
412819ce
JA
850 do {
851 int events;
d5396421 852
412819ce
JA
853 events = read_sort_events(fd, &ptr);
854 if (!events)
855 break;
856
2ff323b0
JA
857 if (sort_entries(ptr, ~0UL, events) == -1)
858 break;
859
412819ce
JA
860 show_entries_rb();
861 free_entries_rb();
d5396421
JA
862 } while (1);
863
864 close(fd);
865 free(ptr);
d5396421
JA
866 return 0;
867}
d0ca268b 868
1f79c4a0 869static void flush_output(void)
412819ce 870{
152f6476 871 fflush(ofp);
412819ce
JA
872}
873
1f79c4a0 874static void handle_sigint(int sig)
412819ce
JA
875{
876 done = 1;
877 flush_output();
878}
879
1f79c4a0
JA
880static void usage(char *prog)
881{
152f6476 882 fprintf(stderr, "Usage: %s -i <name> [-o <output>][-s]\n", prog);
1f79c4a0
JA
883}
884
d5396421
JA
885int main(int argc, char *argv[])
886{
152f6476 887 char *ofp_buffer;
412819ce 888 int c, ret;
d5396421
JA
889
890 while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
891 switch (c) {
892 case 'i':
66efebf8 893 dev = optarg;
d5396421
JA
894 break;
895 case 'o':
66efebf8 896 output_name = optarg;
d5396421 897 break;
79f19470
JA
898 case 'b':
899 rb_batch = atoi(optarg);
900 if (rb_batch <= 0)
901 rb_batch = RB_BATCH_DEFAULT;
902 break;
152f6476
JA
903 case 's':
904 per_process_stats = 1;
905 break;
d5396421 906 default:
1f79c4a0 907 usage(argv[0]);
d5396421
JA
908 return 1;
909 }
d0ca268b
JA
910 }
911
d5396421 912 if (!dev) {
1f79c4a0 913 usage(argv[0]);
d5396421
JA
914 return 1;
915 }
916
412819ce
JA
917 memset(&rb_root, 0, sizeof(rb_root));
918
919 signal(SIGINT, handle_sigint);
920 signal(SIGHUP, handle_sigint);
921 signal(SIGTERM, handle_sigint);
d5396421 922
d69db225
JA
923 setlocale(LC_NUMERIC, "en_US");
924
152f6476
JA
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
d5396421
JA
945 if (!strcmp(dev, "-"))
946 ret = do_stdin();
947 else
948 ret = do_file();
949
152f6476
JA
950 if (per_process_stats)
951 show_process_stats();
952
953 show_cpu_stats();
954
412819ce 955 flush_output();
d5396421 956 return ret;
d0ca268b 957}