[PATCH] Add argument parsing for blktrace
[blktrace.git] / blkparse.c
CommitLineData
d0ca268b
JA
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <fcntl.h>
6#include <stdlib.h>
8fc0abbc 7#include <string.h>
d0ca268b 8
8fc0abbc
JA
9#include "blktrace.h"
10#include "rbtree.h"
d0ca268b 11
fd92da24 12#define MAX_CPUS (512)
d0ca268b
JA
13
14struct per_file_info {
15 int cpu;
16 int nelems;
d0ca268b
JA
17
18 int fd;
87b72777 19 char fname[128];
d0ca268b 20
87b72777
JA
21 FILE *ofp;
22 char ofname[128];
8fc0abbc 23
d0ca268b 24 unsigned long long start_time;
5c017e4b
JA
25
26 unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
afd2d7ad 27 unsigned long ireads, iwrites;
5c017e4b 28 unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
afd2d7ad 29 unsigned long long iread_kb, iwrite_kb;
d0ca268b
JA
30};
31
8fc0abbc
JA
32static struct rb_root rb_root;
33
34struct trace {
35 struct blk_io_trace *bit;
66fa7233 36 unsigned int cpu;
8fc0abbc
JA
37 struct rb_node rb_node;
38};
39
87b72777
JA
40static struct per_file_info per_file_info[MAX_CPUS];
41static struct per_file_info *cur_file;
d0ca268b 42
87b72777
JA
43static unsigned long long events;
44
45static int max_cpus;
d0ca268b 46
5c017e4b
JA
47static inline void account_m(struct per_file_info *pfi, int rw,
48 unsigned int bytes)
d0ca268b
JA
49{
50 if (rw) {
5c017e4b
JA
51 pfi->mwrites++;
52 pfi->qwrite_kb += bytes >> 10;
d0ca268b 53 } else {
5c017e4b
JA
54 pfi->mreads++;
55 pfi->qread_kb += bytes >> 10;
d0ca268b
JA
56 }
57}
58
5c017e4b
JA
59static inline void account_q(struct per_file_info *pfi, int rw,
60 unsigned int bytes)
d0ca268b
JA
61{
62 if (rw) {
5c017e4b
JA
63 pfi->qwrites++;
64 pfi->qwrite_kb += bytes >> 10;
d0ca268b 65 } else {
5c017e4b
JA
66 pfi->qreads++;
67 pfi->qread_kb += bytes >> 10;
d0ca268b
JA
68 }
69}
70
5c017e4b
JA
71static inline void account_c(struct per_file_info *pfi, int rw,
72 unsigned int bytes)
d0ca268b
JA
73{
74 if (rw) {
5c017e4b
JA
75 pfi->cwrites++;
76 pfi->cwrite_kb += bytes >> 10;
d0ca268b 77 } else {
5c017e4b
JA
78 pfi->creads++;
79 pfi->cread_kb += bytes >> 10;
d0ca268b
JA
80 }
81}
82
afd2d7ad 83static inline void account_i(struct per_file_info *pfi, int rw,
84 unsigned int bytes)
85{
86 if (rw) {
87 pfi->iwrites++;
88 pfi->iwrite_kb += bytes >> 10;
89 } else {
90 pfi->ireads++;
91 pfi->iread_kb += bytes >> 10;
92 }
93}
94
3aabcd89 95static void output(char *s)
d0ca268b
JA
96{
97 printf("%s", s);
3aabcd89 98 fprintf(cur_file->ofp,"%s",s);
d0ca268b
JA
99}
100
3aabcd89
JA
101static char hstring[256];
102static char tstring[256];
d0ca268b 103
3aabcd89 104static inline char *setup_header(struct blk_io_trace *t, char act)
d0ca268b
JA
105{
106 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
107 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
108 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
109 char rwbs[4];
110 int i = 0;
111
112 if (w)
113 rwbs[i++] = 'W';
114 else
115 rwbs[i++] = 'R';
116 if (b)
117 rwbs[i++] = 'B';
118 if (s)
119 rwbs[i++] = 'S';
120
121 rwbs[i] = '\0';
122
3aabcd89 123 sprintf(hstring, "%3d %15ld %12Lu %5u %c %3s", cur_file->cpu,
d0ca268b
JA
124 (unsigned long)t->sequence, (unsigned long long)t->time, t->pid,
125 act, rwbs);
126
127 return hstring;
128}
129
3aabcd89 130static void log_complete(struct blk_io_trace *t, char act)
d0ca268b
JA
131{
132 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(t, act),
133 (unsigned long long)t->sector, t->bytes >> 9, t->error);
134 output(tstring);
135}
136
3aabcd89 137static void log_queue(struct blk_io_trace *t, char act)
d0ca268b
JA
138{
139 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
140 (unsigned long long)t->sector, t->bytes >> 9);
141 output(tstring);
142}
143
3aabcd89 144static void log_issue(struct blk_io_trace *t, char act)
d0ca268b
JA
145{
146 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
147 (unsigned long long)t->sector, t->bytes >> 9);
148 output(tstring);
149}
150
3aabcd89 151static void log_merge(struct blk_io_trace *t, char act)
d0ca268b
JA
152{
153 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
154 (unsigned long long)t->sector, t->bytes >> 9);
155 output(tstring);
156}
157
3aabcd89 158static void log_generic(struct blk_io_trace *t, char act)
d0ca268b
JA
159{
160 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
161 (unsigned long long)t->sector, t->bytes >> 9);
162 output(tstring);
163}
164
87b72777 165static int log_pc(struct blk_io_trace *t, char act)
d0ca268b 166{
87b72777
JA
167 unsigned char *buf;
168 int i;
d0ca268b 169
87b72777 170 sprintf(tstring,"%s ", setup_header(t, act));
d0ca268b
JA
171 output(tstring);
172
87b72777 173 buf = (unsigned char *) t + sizeof(*t);
d0ca268b
JA
174 for (i = 0; i < t->pdu_len; i++) {
175 sprintf(tstring,"%02x ", buf[i]);
176 output(tstring);
177 }
178
179 if (act == 'C') {
180 sprintf(tstring,"[%d]", t->error);
181 output(tstring);
182 }
183
184 printf("\n");
87b72777 185 return 0;
d0ca268b
JA
186}
187
5c017e4b 188static int dump_trace_pc(struct blk_io_trace *t, struct per_file_info *pfi)
d0ca268b 189{
87b72777
JA
190 int ret = 0;
191
d0ca268b
JA
192 switch (t->action & 0xffff) {
193 case __BLK_TA_QUEUE:
194 log_generic(t, 'Q');
195 break;
196 case __BLK_TA_GETRQ:
197 log_generic(t, 'G');
198 break;
199 case __BLK_TA_SLEEPRQ:
200 log_generic(t, 'S');
201 break;
202 case __BLK_TA_REQUEUE:
203 log_generic(t, 'R');
204 break;
205 case __BLK_TA_ISSUE:
87b72777 206 ret = log_pc(t, 'D');
d0ca268b
JA
207 break;
208 case __BLK_TA_COMPLETE:
209 log_pc(t, 'C');
210 break;
211 default:
212 fprintf(stderr, "Bad pc action %x\n", t->action);
87b72777
JA
213 ret = 1;
214 break;
d0ca268b
JA
215 }
216
87b72777 217 return ret;
d0ca268b
JA
218}
219
5c017e4b 220static void dump_trace_fs(struct blk_io_trace *t, struct per_file_info *pfi)
d0ca268b
JA
221{
222 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
223
224 switch (t->action & 0xffff) {
225 case __BLK_TA_QUEUE:
5c017e4b 226 account_q(pfi, w, t->bytes);
d0ca268b
JA
227 log_queue(t, 'Q');
228 break;
229 case __BLK_TA_BACKMERGE:
5c017e4b 230 account_m(pfi, w, t->bytes);
d0ca268b
JA
231 log_merge(t, 'M');
232 break;
233 case __BLK_TA_FRONTMERGE:
5c017e4b 234 account_m(pfi, w, t->bytes);
d0ca268b
JA
235 log_merge(t, 'F');
236 break;
237 case __BLK_TA_GETRQ:
238 log_generic(t, 'G');
239 break;
240 case __BLK_TA_SLEEPRQ:
241 log_generic(t, 'S');
242 break;
243 case __BLK_TA_REQUEUE:
5c017e4b 244 account_c(pfi, w, -t->bytes);
d0ca268b
JA
245 log_queue(t, 'R');
246 break;
247 case __BLK_TA_ISSUE:
afd2d7ad 248 account_i(pfi, w, t->bytes);
d0ca268b
JA
249 log_issue(t, 'D');
250 break;
251 case __BLK_TA_COMPLETE:
5c017e4b 252 account_c(pfi, w, t->bytes);
d0ca268b
JA
253 log_complete(t, 'C');
254 break;
255 default:
256 fprintf(stderr, "Bad fs action %x\n", t->action);
257 return;
258 }
d0ca268b
JA
259}
260
5c017e4b 261static int dump_trace(struct blk_io_trace *t, struct per_file_info *pfi)
d0ca268b 262{
87b72777
JA
263 int ret = 0;
264
d0ca268b 265 if (t->action & BLK_TC_ACT(BLK_TC_PC))
5c017e4b 266 ret = dump_trace_pc(t, pfi);
d0ca268b 267 else
5c017e4b 268 dump_trace_fs(t, pfi);
87b72777
JA
269
270 events++;
271 return ret;
d0ca268b
JA
272}
273
5c017e4b
JA
274static void dump_pfi_stats(struct per_file_info *pfi)
275{
276 printf("\tReads:\n");
277 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pfi->qreads, pfi->qread_kb);
afd2d7ad 278 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pfi->ireads, pfi->iread_kb);
5c017e4b
JA
279 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pfi->creads, pfi->cread_kb);
280 printf("\t\tMerges: %'8lu\n", pfi->mreads);
281
282 printf("\tWrites:\n");
283 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pfi->qwrites,pfi->qwrite_kb);
afd2d7ad 284 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pfi->iwrites,pfi->iwrite_kb);
5c017e4b
JA
285 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pfi->cwrites,pfi->cwrite_kb);
286 printf("\t\tMerges: %'8lu\n", pfi->mwrites);
287}
288
289static void show_stats(int nfiles)
d0ca268b 290{
5c017e4b
JA
291 struct per_file_info foo, *pfi;
292 int i;
293
294 memset(&foo, 0, sizeof(foo));
d0ca268b 295
5c017e4b
JA
296 for (i = 0; i < nfiles; i++) {
297 pfi = &per_file_info[i];
298
afd2d7ad 299 if (!pfi->nelems)
300 continue;
301
5c017e4b
JA
302 foo.qreads += pfi->qreads;
303 foo.qwrites += pfi->qwrites;
304 foo.creads += pfi->creads;
305 foo.cwrites += pfi->cwrites;
306 foo.mreads += pfi->mreads;
307 foo.mwrites += pfi->mwrites;
308 foo.qread_kb += pfi->qread_kb;
309 foo.qwrite_kb += pfi->qwrite_kb;
310 foo.cread_kb += pfi->cread_kb;
311 foo.cwrite_kb += pfi->cwrite_kb;
312
313 printf("CPU%d:\n", i);
314 dump_pfi_stats(pfi);
315 }
316
317 if (nfiles > 1) {
318 printf("Total:\n");
319 dump_pfi_stats(&foo);
320 }
d0ca268b
JA
321
322 printf("Events: %'Lu\n", events);
d0ca268b
JA
323}
324
3aabcd89 325static inline int trace_rb_insert(struct trace *t)
8fc0abbc
JA
326{
327 struct rb_node **p = &rb_root.rb_node;
328 struct rb_node *parent = NULL;
329 struct trace *__t;
330
331 while (*p) {
332 parent = *p;
333 __t = rb_entry(parent, struct trace, rb_node);
334
335 if (t->bit->sequence < __t->bit->sequence)
336 p = &(*p)->rb_left;
337 else if (t->bit->sequence > __t->bit->sequence)
338 p = &(*p)->rb_right;
339 else {
87b72777 340 fprintf(stderr, "sequence alias!\n");
8fc0abbc
JA
341 return 1;
342 }
343 }
344
345 rb_link_node(&t->rb_node, parent, p);
346 rb_insert_color(&t->rb_node, &rb_root);
347 return 0;
348}
349
66fa7233 350static int sort_entries(void *traces, unsigned long offset, int cpu)
8fc0abbc
JA
351{
352 struct blk_io_trace *bit;
353 struct trace *t;
354 void *start = traces;
355 int nelems = 0;
356
6fe4709e 357 while (traces - start <= offset - sizeof(*bit)) {
8fc0abbc 358 bit = traces;
6fe4709e 359
8fc0abbc
JA
360 t = malloc(sizeof(*t));
361 t->bit = bit;
66fa7233 362 t->cpu = cpu;
8fc0abbc
JA
363 memset(&t->rb_node, 0, sizeof(t->rb_node));
364
6fe4709e
JA
365 trace_to_cpu(bit);
366
66fa7233
JA
367 if (verify_trace(bit))
368 break;
369
8fc0abbc
JA
370 if (trace_rb_insert(t))
371 return -1;
372
373 traces += sizeof(*bit) + bit->pdu_len;
374 nelems++;
6fe4709e 375 }
8fc0abbc
JA
376
377 return nelems;
378}
379
3aabcd89 380static void show_entries(void)
8fc0abbc 381{
8fc0abbc 382 struct blk_io_trace *bit;
3aabcd89 383 struct rb_node *n;
8fc0abbc
JA
384 struct trace *t;
385 int cpu;
386
3aabcd89
JA
387 n = rb_first(&rb_root);
388 if (!n)
389 return;
8fc0abbc 390
3aabcd89 391 do {
8fc0abbc
JA
392 t = rb_entry(n, struct trace, rb_node);
393 bit = t->bit;
394
66fa7233 395 cpu = t->cpu;
87b72777 396 if (cpu > max_cpus) {
8fc0abbc 397 fprintf(stderr, "CPU number too large (%d)\n", cpu);
87b72777 398 break;
8fc0abbc
JA
399 }
400
3aabcd89 401 cur_file = &per_file_info[cpu];
8fc0abbc
JA
402
403 /*
404 * offset time by first trace event.
405 *
406 * NOTE: This is *cpu* relative, thus you can not
407 * compare times ACROSS cpus.
408 */
3aabcd89
JA
409 if (cur_file->start_time == 0)
410 cur_file->start_time = bit->time;
8fc0abbc 411
3aabcd89 412 bit->time -= cur_file->start_time;
8fc0abbc 413
5c017e4b 414 if (dump_trace(bit, cur_file))
87b72777
JA
415 break;
416
8fc0abbc
JA
417 } while ((n = rb_next(n)) != NULL);
418}
419
d0ca268b
JA
420int main(int argc, char *argv[])
421{
3aabcd89
JA
422 int i, nfiles, ret;
423 char *dev;
d0ca268b
JA
424
425 if (argc != 2) {
87b72777 426 fprintf(stderr, "Usage: %s <dev>\n", argv[0]);
d0ca268b
JA
427 return 1;
428 }
429
430 dev = argv[1];
431
df0fae6d 432 memset(&rb_root, 0, sizeof(rb_root));
5c017e4b 433 memset(per_file_info, 0, sizeof(per_file_info));
df0fae6d 434
afd2d7ad 435 for (max_cpus = 0, i = 0, nfiles = 0; i < MAX_CPUS; i++, nfiles++, max_cpus++) {
87b72777
JA
436 struct per_file_info *pfi = &per_file_info[i];
437 struct stat st;
438 void *tb;
439
d0ca268b
JA
440 pfi->cpu = i;
441 pfi->start_time = 0;
442
87b72777
JA
443 snprintf(pfi->fname, sizeof(pfi->fname)-1,"%s_out.%d", dev, i);
444 if (stat(pfi->fname, &st) < 0)
d0ca268b 445 break;
afd2d7ad 446 if (!st.st_size)
447 continue;
d0ca268b 448
87b72777 449 snprintf(pfi->ofname, sizeof(pfi->ofname)-1, "%s_log.%d", dev, i);
d0ca268b
JA
450 pfi->ofp = fopen(pfi->ofname, "w");
451 if (pfi->ofp == NULL) {
452 perror(pfi->ofname);
3aabcd89 453 break;
d0ca268b
JA
454 }
455
8fc0abbc
JA
456 printf("Processing %s\n", pfi->fname);
457
87b72777 458 tb = malloc(st.st_size);
8fc0abbc
JA
459
460 pfi->fd = open(pfi->fname, O_RDONLY);
461 if (pfi->fd < 0) {
d0ca268b 462 perror(pfi->fname);
3aabcd89 463 break;
d0ca268b 464 }
afd2d7ad 465
87b72777 466 if (read(pfi->fd, tb, st.st_size) != st.st_size) {
8fc0abbc 467 fprintf(stderr, "error reading\n");
3aabcd89 468 break;
fd92da24 469 }
d0ca268b 470
66fa7233 471 ret = sort_entries(tb, st.st_size, i);
8fc0abbc 472 if (ret == -1)
3aabcd89 473 break;
d0ca268b 474
8fc0abbc 475 close(pfi->fd);
8fc0abbc 476 pfi->nelems = ret;
8fc0abbc 477 printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems);
d0ca268b 478
d0ca268b
JA
479 }
480
3aabcd89
JA
481 if (nfiles) {
482 show_entries();
5c017e4b 483 show_stats(nfiles);
3aabcd89
JA
484 return 0;
485 }
8fc0abbc 486
3aabcd89
JA
487 fprintf(stderr, "No files found\n");
488 return 1;
d0ca268b 489}