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